1/* $NetBSD: mount_smbfs.c,v 1.11 2009/09/07 13:52:05 pooka Exp $ */ 2 3/* 4 * Copyright (c) 2000-2002, Boris Popov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: Id: mount_smbfs.c,v 1.17 2002/04/10 04:17:51 bp Exp 35 */ 36 37#include <sys/cdefs.h> 38__RCSID("$NetBSD: mount_smbfs.c,v 1.11 2009/09/07 13:52:05 pooka Exp $"); 39 40#include <sys/param.h> 41#include <sys/stat.h> 42#include <sys/errno.h> 43#include <sys/mount.h> 44 45#include <stdio.h> 46#include <string.h> 47#include <pwd.h> 48#include <grp.h> 49#include <unistd.h> 50#include <ctype.h> 51#include <stdlib.h> 52#include <err.h> 53#include <sysexits.h> 54#include <errno.h> 55 56#include <cflib.h> 57 58#include <netsmb/smb.h> 59#include <netsmb/smb_conn.h> 60#include <netsmb/smb_lib.h> 61 62#include <fs/smbfs/smbfs.h> 63 64#include "mount_smbfs.h" 65 66#include "mntopts.h" 67 68static void usage(void); 69 70static const struct mntopt mopts[] = { 71 MOPT_STDOPTS, 72 { NULL, 0, 0, 0 } 73}; 74 75#ifndef MOUNT_NOMAIN 76int 77main(int argc, char *argv[]) 78{ 79 80 setprogname(argv[0]); 81 return mount_smbfs(argc, argv); 82} 83#endif 84 85struct smb_ctx sctx; 86void 87mount_smbfs_parseargs(int argc, char *argv[], struct smbfs_args *mdatap, 88 int *mntflagsp, char *canon_dev, char *mount_point) 89{ 90 struct smb_ctx *ctx = &sctx; 91 struct stat st; 92 char *next; 93 int opt, error, caseopt; 94 95 if (argc == 2) { 96 if (strcmp(argv[1], "-h") == 0) { 97 usage(); 98 } else if (strcmp(argv[1], "-v") == 0) { 99 errx(EX_OK, "version %d.%d.%d", SMBFS_VERSION / 100000, 100 (SMBFS_VERSION % 10000) / 1000, 101 (SMBFS_VERSION % 1000) / 100); 102 } 103 } 104 if (argc < 3) 105 usage(); 106 107 if (smb_lib_init() != 0) 108 exit(1); 109 110 *mntflagsp = error = 0; 111 memset(mdatap, 0, sizeof(*mdatap)); 112 mdatap->uid = mdatap->gid = -1; 113 caseopt = SMB_CS_NONE; 114 115 if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0) 116 exit(1); 117 if (smb_ctx_readrc(ctx) != 0) 118 exit(1); 119 if (smb_rc) 120 rc_close(smb_rc); 121 122 while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) { 123 switch (opt) { 124 case STDPARAM_ARGS: 125 error = smb_ctx_opt(ctx, opt, optarg); 126 if (error) 127 exit(1); 128 break; 129 case 'u': { 130 struct passwd *pwd; 131 132 pwd = isdigit((unsigned char)optarg[0]) ? 133 getpwuid(atoi(optarg)) : getpwnam(optarg); 134 if (pwd == NULL) 135 errx(EX_NOUSER, "unknown user '%s'", optarg); 136 mdatap->uid = pwd->pw_uid; 137 break; 138 } 139 case 'g': { 140 struct group *grp; 141 142 grp = isdigit((unsigned char)optarg[0]) ? 143 getgrgid(atoi(optarg)) : getgrnam(optarg); 144 if (grp == NULL) 145 errx(EX_NOUSER, "unknown group '%s'", optarg); 146 mdatap->gid = grp->gr_gid; 147 break; 148 } 149 case 'd': 150 errno = 0; 151 mdatap->dir_mode = strtol(optarg, &next, 8); 152 if (errno || *next != 0) 153 errx(EX_DATAERR, "invalid value for directory mode"); 154 break; 155 case 'f': 156 errno = 0; 157 mdatap->file_mode = strtol(optarg, &next, 8); 158 if (errno || *next != 0) 159 errx(EX_DATAERR, "invalid value for file mode"); 160 break; 161 case '?': 162 usage(); 163 /*NOTREACHED*/ 164 case 'n': { 165 char *inp, *nsp; 166 167 nsp = inp = optarg; 168 while ((nsp = strsep(&inp, ",;:")) != NULL) { 169 if (strcasecmp(nsp, "LONG") == 0) 170 mdatap->flags |= SMBFS_MOUNT_NO_LONG; 171 else 172 errx(EX_DATAERR, "unknown suboption '%s'", nsp); 173 } 174 break; 175 }; 176 case 'o': 177 getmntopts(optarg, mopts, mntflagsp, 0); 178 break; 179 case 'c': 180 switch (optarg[0]) { 181 case 'l': 182 caseopt |= SMB_CS_LOWER; 183 break; 184 case 'u': 185 caseopt |= SMB_CS_UPPER; 186 break; 187 default: 188 errx(EX_DATAERR, "invalid suboption '%c' for -c", 189 optarg[0]); 190 } 191 break; 192 default: 193 usage(); 194 } 195 } 196 197 if (optind == argc - 2) 198 optind++; 199 200 if (optind != argc - 1) 201 usage(); 202 realpath(argv[optind], mount_point); 203 204 if (stat(mount_point, &st) == -1) 205 err(EX_OSERR, "could not find mount point %s", mount_point); 206 if (!S_ISDIR(st.st_mode)) { 207 errno = ENOTDIR; 208 err(EX_OSERR, "can't mount on %s", mount_point); 209 } 210/* 211 if (smb_getextattr(mount_point, &einfo) == 0) 212 errx(EX_OSERR, "can't mount on %s twice", mount_point); 213*/ 214 if (mdatap->uid == (uid_t)-1) 215 mdatap->uid = st.st_uid; 216 if (mdatap->gid == (gid_t)-1) 217 mdatap->gid = st.st_gid; 218 if (mdatap->file_mode == 0 ) 219 mdatap->file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); 220 if (mdatap->dir_mode == 0) { 221 mdatap->dir_mode = mdatap->file_mode; 222 if (mdatap->dir_mode & S_IRUSR) 223 mdatap->dir_mode |= S_IXUSR; 224 if (mdatap->dir_mode & S_IRGRP) 225 mdatap->dir_mode |= S_IXGRP; 226 if (mdatap->dir_mode & S_IROTH) 227 mdatap->dir_mode |= S_IXOTH; 228 } 229 /* 230 * For now, let connection be private for this mount 231 */ 232 ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE; 233 if (getuid() == 0) 234 ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */ 235 else 236 ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = mdatap->uid; 237 ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = mdatap->gid; 238 opt = 0; 239 if (mdatap->dir_mode & S_IXGRP) 240 opt |= SMBM_EXECGRP; 241 if (mdatap->dir_mode & S_IXOTH) 242 opt |= SMBM_EXECOTH; 243 ctx->ct_ssn.ioc_rights |= opt; 244 ctx->ct_sh.ioc_rights |= opt; 245 error = smb_ctx_resolve(ctx); 246 if (error) 247 err(1, "resolve %d", error); 248 error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE); 249 if (error) { 250 err(1, "lookup %d", error); 251 } 252 mdatap->version = SMBFS_VERSION; 253 mdatap->dev_fd = ctx->ct_fd; 254 mdatap->caseopt = caseopt; 255 256 snprintf(canon_dev, MAXPATHLEN, "//%s@%s/%s", 257 ctx->ct_ssn.ioc_user[0] ? ctx->ct_ssn.ioc_user : "guest", 258 ctx->ct_ssn.ioc_srvname, ctx->ct_sh.ioc_share); 259} 260 261int 262mount_smbfs(int argc, char *argv[]) 263{ 264 char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; 265 struct smbfs_args mdata; 266 int mntflags, error; 267 268 mount_smbfs_parseargs(argc, argv, &mdata, &mntflags, 269 canon_dev, canon_dir); 270 271 error = mount(SMBFS_VFSNAME, canon_dir, mntflags, 272 &mdata, sizeof mdata); 273 smb_ctx_done(&sctx); /* XXX */ 274 275 if (error) { 276 smb_error("mount error for %s: %s", error, canon_dir, 277 strerror(errno)); 278 exit(1); 279 } 280 return 0; 281} 282 283static void 284usage(void) 285{ 286 fprintf(stderr, "%s\n%s\n%s\n%s\n", 287 "usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]", 288 " [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]", 289 " [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]", 290 " [-g gid] [-n opt] [-u uid] //user@server/share node"); 291 292 exit (1); 293} 294