dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / smbclnt / mount / mount.c
blob5e00ff0f76e6fb19833c383d95207ea558f3d773
1 /*
2 * Copyright (c) 2000-2001, Boris Popov
3 * All rights reserved.
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.
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.
32 * $Id: mount_smbfs.c,v 1.28.44.2 2005/06/02 00:55:41 lindak Exp $
36 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
37 * Use is subject to license terms.
39 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
42 #include <stdio.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <pwd.h>
46 #include <grp.h>
47 #include <unistd.h>
48 #include <ctype.h>
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <libintl.h>
53 #include <locale.h>
54 #include <libscf.h>
55 #include <priv_utils.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/errno.h>
60 #include <sys/mount.h>
61 #include <sys/mntent.h>
62 #include <sys/mnttab.h>
63 #include <sys/param.h>
65 #include <sys/fs/smbfs_mount.h>
67 /* This needs to know ctx->ct_dev_fd, etc. */
68 #include <netsmb/smb_lib.h>
70 extern char *optarg;
71 extern int optind;
73 static char mount_point[MAXPATHLEN + 1];
74 static void usage(void);
75 static int setsubopt(smb_ctx_t *, struct smbfs_args *, char *);
77 const char * const optlist[] = {
79 /* Generic VFS options. */
80 #define OPT_RO 0
81 MNTOPT_RO,
82 #define OPT_RW 1
83 MNTOPT_RW,
84 #define OPT_SUID 2
85 MNTOPT_SUID,
86 #define OPT_NOSUID 3
87 MNTOPT_NOSUID,
88 #define OPT_DEVICES 4
89 MNTOPT_DEVICES,
90 #define OPT_NODEVICES 5
91 MNTOPT_NODEVICES,
92 #define OPT_SETUID 6
93 MNTOPT_SETUID,
94 #define OPT_NOSETUID 7
95 MNTOPT_NOSETUID,
96 #define OPT_EXEC 8
97 MNTOPT_EXEC,
98 #define OPT_NOEXEC 9
99 MNTOPT_NOEXEC,
100 #define OPT_XATTR 10
101 MNTOPT_XATTR,
102 #define OPT_NOXATTR 11
103 MNTOPT_NOXATTR,
105 /* Sort of generic (from NFS) */
106 #define OPT_NOAC 12
107 MNTOPT_NOAC,
108 #define OPT_ACTIMEO 13
109 MNTOPT_ACTIMEO,
110 #define OPT_ACREGMIN 14
111 MNTOPT_ACREGMIN,
112 #define OPT_ACREGMAX 15
113 MNTOPT_ACREGMAX,
114 #define OPT_ACDIRMIN 16
115 MNTOPT_ACDIRMIN,
116 #define OPT_ACDIRMAX 17
117 MNTOPT_ACDIRMAX,
119 /* smbfs-specifis options */
120 #define OPT_DOMAIN 18
121 "domain",
122 #define OPT_USER 19
123 "user",
124 #define OPT_UID 20
125 "uid",
126 #define OPT_GID 21
127 "gid",
128 #define OPT_DIRPERMS 22
129 "dirperms",
130 #define OPT_FILEPERMS 23
131 "fileperms",
132 #define OPT_NOPROMPT 24
133 "noprompt",
134 #define OPT_ACL 25
135 MNTOPT_ACL,
136 #define OPT_NOACL 26
137 MNTOPT_NOACL,
139 NULL
142 static int Oflg = 0; /* Overlay mounts */
143 static int qflg = 0; /* quiet - don't print warnings on bad options */
144 static int noprompt = 0; /* don't prompt for password */
146 /* Note: smbfs uses _both_ kinds of options. */
147 static int mntflags = MS_DATA | MS_OPTIONSTR;
149 #define EX_OK 0 /* normal */
150 #define EX_OPT 1 /* bad options, usage, etc */
151 #define EX_MNT 2 /* mount point problems, etc */
152 #define RET_ERR 3 /* later errors */
154 #define SERVICE "svc:/network/smb/client:default"
156 struct smbfs_args mdata;
157 struct mnttab mnt;
160 * Initialize this with "rw" just to have something there,
161 * so we don't have to decide whether to add a comma when
162 * we strcat another option. Note the "rw" may be changed
163 * to an "ro" by option processing.
165 char optbuf[MAX_MNTOPT_STR] = "rw";
166 char special[MAXPATHLEN];
169 main(int argc, char *argv[])
171 struct smb_ctx *ctx = NULL;
172 struct stat st;
173 int opt, error, err2;
174 static char *fstype = MNTTYPE_SMBFS;
175 char *env;
177 (void) setlocale(LC_ALL, "");
178 #if !defined(TEXT_DOMAIN)
179 #define TEXT_DOMAIN "SYS_TEST"
180 #endif
181 (void) textdomain(TEXT_DOMAIN);
184 * Normal users are allowed to run "mount -F smbfs ..."
185 * to mount on a directory they own. To allow that, this
186 * program is installed setuid root, and it adds SYS_MOUNT
187 * privilege here (if needed), and then restores the user's
188 * normal privileges. When root runs this, it's a no-op.
190 if (__init_suid_priv(0, PRIV_SYS_MOUNT, NULL) < 0) {
191 (void) fprintf(stderr,
192 gettext("Insufficient privileges, "
193 "%s must be set-uid root\n"), argv[0]);
194 exit(RET_ERR);
197 if (argc == 2) {
198 if (strcmp(argv[1], "-h") == 0) {
199 usage();
200 } else if (strcmp(argv[1], "-v") == 0) {
201 errx(EX_OK, gettext("version %d.%d.%d"),
202 SMBFS_VERSION / 100000,
203 (SMBFS_VERSION % 10000) / 1000,
204 (SMBFS_VERSION % 1000) / 100);
207 if (argc < 3)
208 usage();
210 /* Debugging support. */
211 if ((env = getenv("SMBFS_DEBUG")) != NULL) {
212 smb_debug = atoi(env);
213 if (smb_debug < 1)
214 smb_debug = 1;
217 error = smb_lib_init();
218 if (error)
219 exit(RET_ERR);
221 mnt.mnt_mntopts = optbuf;
223 bzero(&mdata, sizeof (mdata));
224 mdata.version = SMBFS_VERSION; /* smbfs mount version */
225 mdata.uid = (uid_t)-1;
226 mdata.gid = (gid_t)-1;
228 error = smb_ctx_alloc(&ctx);
229 if (error)
230 exit(RET_ERR);
233 * Parse the UNC path so we have the server (etc.)
234 * that we need during rcfile+sharectl parsing.
236 if (argc < 3)
237 usage();
238 error = smb_ctx_parseunc(ctx, argv[argc - 2],
239 SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL);
240 if (error)
241 exit(EX_OPT);
243 error = smb_ctx_readrc(ctx);
244 if (error)
245 exit(EX_OPT);
247 while ((opt = getopt(argc, argv, "ro:Oq")) != -1) {
248 switch (opt) {
249 case 'O':
250 Oflg++;
251 break;
253 case 'q':
254 qflg++;
255 break;
257 case 'r':
258 mntflags |= MS_RDONLY;
259 break;
261 case 'o': {
262 char *nextopt, *comma, *sopt;
263 int ret;
265 for (sopt = optarg; sopt != NULL; sopt = nextopt) {
266 comma = strchr(sopt, ',');
267 if (comma) {
268 nextopt = comma + 1;
269 *comma = '\0';
270 } else
271 nextopt = NULL;
272 ret = setsubopt(ctx, &mdata, sopt);
273 if (ret != 0)
274 exit(EX_OPT);
275 /* undo changes to optarg */
276 if (comma)
277 *comma = ',';
279 break;
282 case '?':
283 default:
284 usage();
288 if (Oflg)
289 mntflags |= MS_OVERLAY;
291 if (mntflags & MS_RDONLY) {
292 char *p;
293 /* convert "rw"->"ro" */
294 if (p = strstr(optbuf, "rw")) {
295 if (*(p+2) == ',' || *(p+2) == '\0')
296 *(p+1) = 'o';
300 if (optind + 2 != argc)
301 usage();
303 (void) snprintf(special, sizeof (special), "//%s/%s",
304 ctx->ct_fullserver, ctx->ct_origshare);
306 mnt.mnt_special = special;
307 mnt.mnt_mountp = argv[optind+1];
309 if ((realpath(argv[optind+1], mount_point) == NULL) ||
310 (stat(mount_point, &st) == -1)) {
311 err(EX_MNT, gettext("could not find mount point %s"),
312 argv[optind+1]);
314 if (!S_ISDIR(st.st_mode)) {
315 errno = ENOTDIR;
316 err(EX_MNT, gettext("can't mount on %s"), mount_point);
320 * Fill in mdata defaults.
322 if (mdata.uid == (uid_t)-1)
323 mdata.uid = getuid();
324 if (mdata.gid == (gid_t)-1)
325 mdata.gid = getgid();
326 if (mdata.file_mode == 0)
327 mdata.file_mode = S_IRWXU;
328 if (mdata.dir_mode == 0) {
329 mdata.dir_mode = mdata.file_mode;
330 if (mdata.dir_mode & S_IRUSR)
331 mdata.dir_mode |= S_IXUSR;
332 if (mdata.dir_mode & S_IRGRP)
333 mdata.dir_mode |= S_IXGRP;
334 if (mdata.dir_mode & S_IROTH)
335 mdata.dir_mode |= S_IXOTH;
338 ctx->ct_ssn.ssn_owner = SMBM_ANY_OWNER;
339 if (noprompt)
340 ctx->ct_flags |= SMBCF_NOPWD;
343 * Resolve the server address,
344 * setup derived defaults.
346 error = smb_ctx_resolve(ctx);
347 if (error)
348 exit(RET_ERR);
351 * Have server, share, etc. from above:
352 * smb_ctx_scan_argv, option settings.
353 * Get the session and tree.
355 again:
356 error = smb_ctx_get_ssn(ctx);
357 if (error == EAUTH && noprompt == 0) {
358 err2 = smb_get_authentication(ctx);
359 if (err2 == 0)
360 goto again;
362 if (error) {
363 smb_error(gettext("//%s: login failed"),
364 error, ctx->ct_fullserver);
365 exit(RET_ERR);
368 error = smb_ctx_get_tree(ctx);
369 if (error) {
370 smb_error(gettext("//%s/%s: tree connect failed"),
371 error, ctx->ct_fullserver, ctx->ct_origshare);
372 exit(RET_ERR);
376 * Have tree connection, now mount it.
378 mdata.devfd = ctx->ct_dev_fd;
380 /* Need sys_mount privilege for the mount call. */
381 (void) __priv_bracket(PRIV_ON);
382 err2 = mount(mnt.mnt_special, mnt.mnt_mountp,
383 mntflags, fstype, &mdata, sizeof (mdata),
384 mnt.mnt_mntopts, MAX_MNTOPT_STR);
385 (void) __priv_bracket(PRIV_OFF);
387 if (err2 < 0) {
388 if (errno != ENOENT) {
389 err(EX_MNT, gettext("mount_smbfs: %s"),
390 mnt.mnt_mountp);
391 } else {
392 struct stat sb;
393 if (stat(mnt.mnt_mountp, &sb) < 0 &&
394 errno == ENOENT)
395 err(EX_MNT, gettext("mount_smbfs: %s"),
396 mnt.mnt_mountp);
397 else
398 err(EX_MNT, gettext("mount_smbfs: %s"),
399 mnt.mnt_special);
403 smb_ctx_free(ctx);
404 return (0);
407 #define bad(val) (val == NULL || !isdigit(*val))
410 setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, char *subopt)
412 char *equals, *optarg;
413 struct passwd *pwd;
414 struct group *grp;
415 long val;
416 int rc = EX_OK;
417 int index;
418 char *p;
420 equals = strchr(subopt, '=');
421 if (equals) {
422 *equals = '\0';
423 optarg = equals + 1;
424 } else
425 optarg = NULL;
427 for (index = 0; optlist[index] != NULL; index++) {
428 if (strcmp(subopt, optlist[index]) == 0)
429 break;
433 * Note: if the option was unknown, index will
434 * point to the NULL at the end of optlist[],
435 * and we'll take the switch default.
438 switch (index) {
440 case OPT_ACL:
441 case OPT_NOACL:
442 case OPT_SUID:
443 case OPT_NOSUID:
444 case OPT_DEVICES:
445 case OPT_NODEVICES:
446 case OPT_SETUID:
447 case OPT_NOSETUID:
448 case OPT_EXEC:
449 case OPT_NOEXEC:
450 case OPT_XATTR:
451 case OPT_NOXATTR:
453 * These options are handled via the
454 * generic option string mechanism.
455 * None of these take an optarg.
457 if (optarg != NULL)
458 goto badval;
459 (void) strlcat(optbuf, ",", sizeof (optbuf));
460 if (strlcat(optbuf, subopt, sizeof (optbuf)) >=
461 sizeof (optbuf)) {
462 if (!qflg)
463 warnx(gettext("option string too long"));
464 rc = EX_OPT;
466 break;
469 * OPT_RO, OPT_RW, are actually generic too,
470 * but we use the mntflags for these, and
471 * then update the options string later.
473 case OPT_RO:
474 mntflags |= MS_RDONLY;
475 break;
476 case OPT_RW:
477 mntflags &= ~MS_RDONLY;
478 break;
481 * NFS-derived options for attribute cache
482 * handling (disable, set min/max timeouts)
484 case OPT_NOAC:
485 mdatap->flags |= SMBFS_MF_NOAC;
486 break;
488 case OPT_ACTIMEO:
489 errno = 0;
490 val = strtol(optarg, &p, 10);
491 if (errno || *p != 0)
492 goto badval;
493 mdatap->acdirmin = mdatap->acregmin = val;
494 mdatap->acdirmax = mdatap->acregmax = val;
495 mdatap->flags |= SMBFS_MF_ACDIRMAX;
496 mdatap->flags |= SMBFS_MF_ACREGMAX;
497 mdatap->flags |= SMBFS_MF_ACDIRMIN;
498 mdatap->flags |= SMBFS_MF_ACREGMIN;
499 break;
501 case OPT_ACREGMIN:
502 errno = 0;
503 val = strtol(optarg, &p, 10);
504 if (errno || *p != 0)
505 goto badval;
506 mdatap->acregmin = val;
507 mdatap->flags |= SMBFS_MF_ACREGMIN;
508 break;
510 case OPT_ACREGMAX:
511 errno = 0;
512 val = strtol(optarg, &p, 10);
513 if (errno || *p != 0)
514 goto badval;
515 mdatap->acregmax = val;
516 mdatap->flags |= SMBFS_MF_ACREGMAX;
517 break;
519 case OPT_ACDIRMIN:
520 errno = 0;
521 val = strtol(optarg, &p, 10);
522 if (errno || *p != 0)
523 goto badval;
524 mdatap->acdirmin = val;
525 mdatap->flags |= SMBFS_MF_ACDIRMIN;
526 break;
528 case OPT_ACDIRMAX:
529 errno = 0;
530 val = strtol(optarg, &p, 10);
531 if (errno || *p != 0)
532 goto badval;
533 mdatap->acdirmax = val;
534 mdatap->flags |= SMBFS_MF_ACDIRMAX;
535 break;
538 * SMBFS-specific options. Some of these
539 * don't go through the mount system call,
540 * but just set libsmbfs options.
542 case OPT_DOMAIN:
543 if (smb_ctx_setdomain(ctx, optarg, B_TRUE) != 0)
544 rc = EX_OPT;
545 break;
547 case OPT_USER:
548 if (smb_ctx_setuser(ctx, optarg, B_TRUE) != 0)
549 rc = EX_OPT;
550 break;
552 case OPT_UID:
553 pwd = isdigit(optarg[0]) ?
554 getpwuid(atoi(optarg)) : getpwnam(optarg);
555 if (pwd == NULL) {
556 if (!qflg)
557 warnx(gettext("unknown user '%s'"), optarg);
558 rc = EX_OPT;
559 } else {
560 mdatap->uid = pwd->pw_uid;
562 break;
564 case OPT_GID:
565 grp = isdigit(optarg[0]) ?
566 getgrgid(atoi(optarg)) : getgrnam(optarg);
567 if (grp == NULL) {
568 if (!qflg)
569 warnx(gettext("unknown group '%s'"), optarg);
570 rc = EX_OPT;
571 } else {
572 mdatap->gid = grp->gr_gid;
574 break;
576 case OPT_DIRPERMS:
577 errno = 0;
578 val = strtol(optarg, &p, 8);
579 if (errno || *p != 0)
580 goto badval;
581 mdatap->dir_mode = val;
582 break;
584 case OPT_FILEPERMS:
585 errno = 0;
586 val = strtol(optarg, &p, 8);
587 if (errno || *p != 0)
588 goto badval;
589 mdatap->file_mode = val;
590 break;
592 case OPT_NOPROMPT:
593 noprompt++;
594 break;
596 default:
597 badopt:
598 if (!qflg)
599 warnx(gettext("unknown option %s"), subopt);
600 rc = EX_OPT;
601 break;
603 badval:
604 if (!qflg)
605 warnx(gettext("invalid value for %s"), subopt);
606 rc = EX_OPT;
607 break;
610 /* Undo changes made to subopt */
611 if (equals)
612 *equals = '=';
614 return (rc);
617 static void
618 usage(void)
620 (void) fprintf(stderr, "%s\n",
621 gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]"
622 " //[workgroup;][user[:password]@]server[/share] path"));
624 exit(EX_OPT);