1 /* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Boris Popov. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: mount_smbfs.c,v 1.28.44.2 2005/06/02 00:55:41 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #include <stdio.h> 41 #include <string.h> 42 #include <strings.h> 43 #include <pwd.h> 44 #include <grp.h> 45 #include <unistd.h> 46 #include <ctype.h> 47 #include <stdlib.h> 48 #include <errno.h> 49 #include <err.h> 50 #include <sysexits.h> 51 #include <libintl.h> 52 #include <locale.h> 53 #include <libscf.h> 54 55 #include <sys/types.h> 56 #include <sys/stat.h> 57 #include <sys/errno.h> 58 #include <sys/mount.h> 59 #include <sys/mntent.h> 60 #include <sys/mnttab.h> 61 62 /* This needs to know ctx->ct_dev_fd, etc. */ 63 #include <netsmb/smb_lib.h> 64 65 #include <sys/fs/smbfs_mount.h> 66 67 #include "mntopts.h" 68 69 extern char *optarg; 70 extern int optind; 71 72 static char mount_point[MAXPATHLEN + 1]; 73 static void usage(void); 74 static int setsubopt(smb_ctx_t *, struct smbfs_args *, int, char *); 75 76 /* smbfs options */ 77 #define MNTOPT_DOMAIN "domain" 78 #define MNTOPT_USER "user" 79 #define MNTOPT_DIRPERMS "dirperms" 80 #define MNTOPT_FILEPERMS "fileperms" 81 #define MNTOPT_GID "gid" 82 #define MNTOPT_UID "uid" 83 #define MNTOPT_NOPROMPT "noprompt" 84 85 #define OPT_DOMAIN 1 86 #define OPT_USER 2 87 #define OPT_DIRPERMS 3 88 #define OPT_FILEPERMS 4 89 #define OPT_GID 5 90 #define OPT_UID 6 91 #define OPT_NOPROMPT 7 92 93 /* generic VFS options */ 94 #define OPT_RO 10 95 #define OPT_RW 11 96 #define OPT_SUID 12 97 #define OPT_NOSUID 13 98 #define OPT_DEVICES 14 99 #define OPT_NODEVICES 15 100 #define OPT_SETUID 16 101 #define OPT_NOSETUID 17 102 #define OPT_EXEC 18 103 #define OPT_NOEXEC 19 104 105 struct smbfsopts { 106 char *name; 107 int index; 108 }; 109 110 struct smbfsopts opts[] = { 111 {MNTOPT_DOMAIN, OPT_DOMAIN}, 112 {MNTOPT_USER, OPT_USER}, 113 {MNTOPT_DIRPERMS, OPT_DIRPERMS}, 114 {MNTOPT_FILEPERMS, OPT_FILEPERMS}, 115 {MNTOPT_GID, OPT_GID}, 116 {MNTOPT_UID, OPT_UID}, 117 {MNTOPT_NOPROMPT, OPT_NOPROMPT}, 118 {MNTOPT_RO, OPT_RO}, 119 {MNTOPT_RW, OPT_RW}, 120 {MNTOPT_SUID, OPT_SUID}, 121 {MNTOPT_NOSUID, OPT_NOSUID}, 122 {MNTOPT_DEVICES, OPT_DEVICES}, 123 {MNTOPT_NODEVICES, OPT_NODEVICES}, 124 {MNTOPT_SETUID, OPT_SETUID}, 125 {MNTOPT_NOSETUID, OPT_NOSETUID}, 126 {MNTOPT_EXEC, OPT_EXEC}, 127 {MNTOPT_NOEXEC, OPT_NOEXEC}, 128 {NULL, 0} 129 }; 130 131 static int Oflg = 0; /* Overlay mounts */ 132 static int qflg = 0; /* quiet - don't print warnings on bad options */ 133 static int ro = 0; /* read-only mount */ 134 static int noprompt = 0; /* don't prompt for password */ 135 136 #define RET_ERR 33 137 #define SERVICE "svc:/network/smb/client:default" 138 139 struct smbfs_args mdata; 140 struct mnttab mnt; 141 char optbuf[MAX_MNTOPT_STR]; 142 143 int 144 main(int argc, char *argv[]) 145 { 146 struct smb_ctx *ctx = NULL; 147 struct stat st; 148 int opt, error, err2, mntflags; 149 static char *fstype = MNTTYPE_SMBFS; 150 char *env, *state; 151 152 (void) setlocale(LC_ALL, ""); 153 #if !defined(TEXT_DOMAIN) 154 #define TEXT_DOMAIN "SYS_TEST" 155 #endif 156 (void) textdomain(TEXT_DOMAIN); 157 if (argc == 2) { 158 if (strcmp(argv[1], "-h") == 0) { 159 usage(); 160 } else if (strcmp(argv[1], "-v") == 0) { 161 errx(EX_OK, gettext("version %d.%d.%d"), 162 SMBFS_VERSION / 100000, 163 (SMBFS_VERSION % 10000) / 1000, 164 (SMBFS_VERSION % 1000) / 100); 165 } 166 } 167 if (argc < 3) 168 usage(); 169 170 state = smf_get_state(SERVICE); 171 if (state == NULL || strcmp(state, SCF_STATE_STRING_ONLINE) != 0) { 172 fprintf(stderr, 173 gettext("mount_smbfs: service \"%s\" not enabled.\n"), 174 SERVICE); 175 exit(RET_ERR); 176 } 177 free(state); 178 179 /* Debugging support. */ 180 if ((env = getenv("SMBFS_DEBUG")) != NULL) { 181 smb_debug = atoi(env); 182 if (smb_debug < 1) 183 smb_debug = 1; 184 } 185 186 error = smb_lib_init(); 187 if (error) 188 exit(RET_ERR); 189 190 mnt.mnt_mntopts = optbuf; 191 mntflags = MS_DATA; 192 193 bzero(&mdata, sizeof (mdata)); 194 mdata.version = SMBFS_VERSION; /* smbfs mount version */ 195 mdata.uid = (uid_t)-1; 196 mdata.gid = (gid_t)-1; 197 mdata.caseopt = SMB_CS_NONE; 198 199 error = smb_ctx_alloc(&ctx); 200 if (error) 201 exit(RET_ERR); 202 203 /* 204 * Parse the UNC path so we have the server (etc.) 205 * that we need during rcfile+sharectl parsing. 206 */ 207 if (argc < 3) 208 usage(); 209 error = smb_ctx_parseunc(ctx, argv[argc - 2], 210 SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL); 211 if (error) 212 exit(RET_ERR); 213 214 error = smb_ctx_readrc(ctx); 215 if (error) 216 exit(RET_ERR); 217 218 while ((opt = getopt(argc, argv, "ro:Oq")) != -1) { 219 switch (opt) { 220 case 'O': 221 Oflg++; 222 break; 223 224 case 'q': 225 qflg++; 226 break; 227 228 case 'r': 229 ro++; 230 break; 231 232 case 'o': { 233 char *nextopt, *comma, *equals, *sopt, *soptval; 234 int i, ret; 235 236 if (strlen(optarg) >= MAX_MNTOPT_STR) { 237 if (!qflg) 238 warnx(gettext( 239 "option string too long")); 240 exit(RET_ERR); 241 } 242 for (sopt = optarg; sopt != NULL; sopt = nextopt) { 243 comma = strchr(sopt, ','); 244 if (comma) { 245 nextopt = comma + 1; 246 *comma = '\0'; 247 } else 248 nextopt = NULL; 249 equals = strchr(sopt, '='); 250 if (equals) { 251 soptval = equals + 1; 252 *equals = '\0'; 253 } else 254 soptval = NULL; 255 for (i = 0; opts[i].name != NULL; i++) { 256 if (strcmp(sopt, opts[i].name) == 0) 257 break; 258 } 259 if (opts[i].name == NULL) { 260 if (equals) 261 *equals = '='; 262 if (!qflg) 263 errx(RET_ERR, gettext( 264 "Bad option '%s'"), sopt); 265 if (comma) 266 *comma = ','; 267 continue; 268 } 269 ret = setsubopt(ctx, &mdata, 270 opts[i].index, soptval); 271 if (ret != 0) 272 exit(RET_ERR); 273 if (equals) 274 *equals = '='; 275 (void) strcat(mnt.mnt_mntopts, sopt); 276 if (comma) 277 *comma = ','; 278 } 279 break; 280 } 281 282 case '?': 283 default: 284 usage(); 285 } 286 } 287 288 if (Oflg) 289 mntflags |= MS_OVERLAY; 290 291 if (ro) { 292 char *p; 293 294 mntflags |= MS_RDONLY; 295 /* convert "rw"->"ro" */ 296 if (p = strstr(mnt.mnt_mntopts, "rw")) { 297 if (*(p+2) == ',' || *(p+2) == '\0') 298 *(p+1) = 'o'; 299 } 300 } 301 302 if (optind + 2 != argc) 303 usage(); 304 305 mnt.mnt_special = argv[optind]; 306 mnt.mnt_mountp = argv[optind+1]; 307 308 realpath(argv[optind+1], mount_point); 309 if (stat(mount_point, &st) == -1) 310 err(EX_OSERR, gettext("could not find mount point %s"), 311 mount_point); 312 if (!S_ISDIR(st.st_mode)) { 313 errno = ENOTDIR; 314 err(EX_OSERR, gettext("can't mount on %s"), mount_point); 315 } 316 317 /* 318 * Fill in mdata defaults. 319 */ 320 if (mdata.uid == (uid_t)-1) 321 mdata.uid = getuid(); 322 if (mdata.gid == (gid_t)-1) 323 mdata.gid = getgid(); 324 if (mdata.file_mode == 0) 325 mdata.file_mode = S_IRWXU; 326 if (mdata.dir_mode == 0) { 327 mdata.dir_mode = mdata.file_mode; 328 if (mdata.dir_mode & S_IRUSR) 329 mdata.dir_mode |= S_IXUSR; 330 if (mdata.dir_mode & S_IRGRP) 331 mdata.dir_mode |= S_IXGRP; 332 if (mdata.dir_mode & S_IROTH) 333 mdata.dir_mode |= S_IXOTH; 334 } 335 336 ctx->ct_ssn.ssn_owner = SMBM_ANY_OWNER; 337 if (noprompt) 338 ctx->ct_flags |= SMBCF_NOPWD; 339 340 /* 341 * Resolve the server address, 342 * setup derived defaults. 343 */ 344 error = smb_ctx_resolve(ctx); 345 if (error) 346 exit(RET_ERR); 347 348 /* 349 * Have server, share, etc. from above: 350 * smb_ctx_scan_argv, option settings. 351 * Get the session and tree. 352 */ 353 again: 354 error = smb_ctx_get_ssn(ctx); 355 if (error == EAUTH && noprompt == 0) { 356 err2 = smb_get_authentication(ctx); 357 if (err2 == 0) 358 goto again; 359 } 360 if (error) { 361 smb_error(gettext("//%s: login failed"), 362 error, ctx->ct_fullserver); 363 exit(RET_ERR); 364 } 365 366 error = smb_ctx_get_tree(ctx); 367 if (error) { 368 smb_error(gettext("//%s/%s: tree connect failed"), 369 error, ctx->ct_fullserver, ctx->ct_origshare); 370 exit(RET_ERR); 371 } 372 373 /* 374 * Have tree connection, now mount it. 375 */ 376 mdata.devfd = ctx->ct_dev_fd; 377 378 if (mount(mnt.mnt_special, mnt.mnt_mountp, 379 mntflags, fstype, &mdata, sizeof (mdata), 380 mnt.mnt_mntopts, MAX_MNTOPT_STR) < 0) { 381 if (errno != ENOENT) { 382 err(EX_OSERR, gettext("mount_smbfs: %s"), 383 mnt.mnt_mountp); 384 } else { 385 struct stat sb; 386 if (stat(mnt.mnt_mountp, &sb) < 0 && 387 errno == ENOENT) 388 err(EX_OSERR, gettext("mount_smbfs: %s"), 389 mnt.mnt_mountp); 390 else 391 err(EX_OSERR, gettext("mount_smbfs: %s"), 392 mnt.mnt_special); 393 } 394 } 395 396 smb_ctx_free(ctx); 397 if (error) { 398 smb_error(gettext("mount error: %s"), error, mount_point); 399 exit(RET_ERR); 400 } 401 return (0); 402 } 403 404 int 405 setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg) 406 { 407 struct passwd *pwd; 408 struct group *grp; 409 long l; 410 int err = 0; 411 char *next; 412 413 switch (index) { 414 case OPT_RO: 415 case OPT_RW: 416 case OPT_SUID: 417 case OPT_NOSUID: 418 case OPT_DEVICES: 419 case OPT_NODEVICES: 420 case OPT_SETUID: 421 case OPT_NOSETUID: 422 case OPT_EXEC: 423 case OPT_NOEXEC: 424 /* We don't have to handle generic options here */ 425 return (0); 426 427 case OPT_DOMAIN: 428 err = smb_ctx_setdomain(ctx, optarg, B_TRUE); 429 break; 430 431 case OPT_USER: 432 err = smb_ctx_setuser(ctx, optarg, B_TRUE); 433 break; 434 435 case OPT_UID: 436 pwd = isdigit(optarg[0]) ? 437 getpwuid(atoi(optarg)) : getpwnam(optarg); 438 if (pwd == NULL) { 439 if (!qflg) 440 warnx(gettext("unknown user '%s'"), optarg); 441 err = -1; 442 } else { 443 mdatap->uid = pwd->pw_uid; 444 } 445 break; 446 case OPT_GID: 447 grp = isdigit(optarg[0]) ? 448 getgrgid(atoi(optarg)) : getgrnam(optarg); 449 if (grp == NULL) { 450 if (!qflg) 451 warnx(gettext("unknown group '%s'"), optarg); 452 err = -1; 453 } else { 454 mdatap->gid = grp->gr_gid; 455 } 456 break; 457 case OPT_DIRPERMS: 458 errno = 0; 459 l = strtol(optarg, &next, 8); 460 if (errno || *next != 0) { 461 if (!qflg) 462 warnx(gettext( 463 "invalid value for directory mode")); 464 err = -1; 465 } else { 466 mdatap->dir_mode = l; 467 } 468 break; 469 case OPT_FILEPERMS: 470 errno = 0; 471 l = strtol(optarg, &next, 8); 472 if (errno || *next != 0) { 473 if (!qflg) 474 warnx(gettext("invalid value for file mode")); 475 err = -1; 476 } else { 477 mdatap->file_mode = l; 478 } 479 break; 480 case OPT_NOPROMPT: 481 noprompt++; 482 } 483 return (err); 484 } 485 486 static void 487 usage(void) 488 { 489 fprintf(stderr, "%s\n", 490 gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]" 491 " //[workgroup;][user[:password]@]server[/share] path")); 492 493 exit(EX_USAGE); 494 } 495