2 * Copyright (c) 2000-2001, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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.
55 #include <priv_utils.h>
57 #include <sys/types.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>
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. */
90 #define OPT_NODEVICES 5
94 #define OPT_NOSETUID 7
102 #define OPT_NOXATTR 11
105 /* Sort of generic (from NFS) */
108 #define OPT_ACTIMEO 13
110 #define OPT_ACREGMIN 14
112 #define OPT_ACREGMAX 15
114 #define OPT_ACDIRMIN 16
116 #define OPT_ACDIRMAX 17
119 /* smbfs-specifis options */
120 #define OPT_DOMAIN 18
128 #define OPT_DIRPERMS 22
130 #define OPT_FILEPERMS 23
132 #define OPT_NOPROMPT 24
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
;
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
;
173 int opt
, error
, err2
;
174 static char *fstype
= MNTTYPE_SMBFS
;
177 (void) setlocale(LC_ALL
, "");
178 #if !defined(TEXT_DOMAIN)
179 #define TEXT_DOMAIN "SYS_TEST"
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]);
198 if (strcmp(argv
[1], "-h") == 0) {
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);
210 /* Debugging support. */
211 if ((env
= getenv("SMBFS_DEBUG")) != NULL
) {
212 smb_debug
= atoi(env
);
217 error
= smb_lib_init();
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
);
233 * Parse the UNC path so we have the server (etc.)
234 * that we need during rcfile+sharectl parsing.
238 error
= smb_ctx_parseunc(ctx
, argv
[argc
- 2],
239 SMBL_SHARE
, SMBL_SHARE
, USE_DISKDEV
, NULL
);
243 error
= smb_ctx_readrc(ctx
);
247 while ((opt
= getopt(argc
, argv
, "ro:Oq")) != -1) {
258 mntflags
|= MS_RDONLY
;
262 char *nextopt
, *comma
, *sopt
;
265 for (sopt
= optarg
; sopt
!= NULL
; sopt
= nextopt
) {
266 comma
= strchr(sopt
, ',');
272 ret
= setsubopt(ctx
, &mdata
, sopt
);
275 /* undo changes to optarg */
289 mntflags
|= MS_OVERLAY
;
291 if (mntflags
& MS_RDONLY
) {
293 /* convert "rw"->"ro" */
294 if (p
= strstr(optbuf
, "rw")) {
295 if (*(p
+2) == ',' || *(p
+2) == '\0')
300 if (optind
+ 2 != argc
)
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"),
314 if (!S_ISDIR(st
.st_mode
)) {
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
;
340 ctx
->ct_flags
|= SMBCF_NOPWD
;
343 * Resolve the server address,
344 * setup derived defaults.
346 error
= smb_ctx_resolve(ctx
);
351 * Have server, share, etc. from above:
352 * smb_ctx_scan_argv, option settings.
353 * Get the session and tree.
356 error
= smb_ctx_get_ssn(ctx
);
357 if (error
== EAUTH
&& noprompt
== 0) {
358 err2
= smb_get_authentication(ctx
);
363 smb_error(gettext("//%s: login failed"),
364 error
, ctx
->ct_fullserver
);
368 error
= smb_ctx_get_tree(ctx
);
370 smb_error(gettext("//%s/%s: tree connect failed"),
371 error
, ctx
->ct_fullserver
, ctx
->ct_origshare
);
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
);
388 if (errno
!= ENOENT
) {
389 err(EX_MNT
, gettext("mount_smbfs: %s"),
393 if (stat(mnt
.mnt_mountp
, &sb
) < 0 &&
395 err(EX_MNT
, gettext("mount_smbfs: %s"),
398 err(EX_MNT
, gettext("mount_smbfs: %s"),
407 #define bad(val) (val == NULL || !isdigit(*val))
410 setsubopt(smb_ctx_t
*ctx
, struct smbfs_args
*mdatap
, char *subopt
)
412 char *equals
, *optarg
;
420 equals
= strchr(subopt
, '=');
427 for (index
= 0; optlist
[index
] != NULL
; index
++) {
428 if (strcmp(subopt
, optlist
[index
]) == 0)
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.
453 * These options are handled via the
454 * generic option string mechanism.
455 * None of these take an optarg.
459 (void) strlcat(optbuf
, ",", sizeof (optbuf
));
460 if (strlcat(optbuf
, subopt
, sizeof (optbuf
)) >=
463 warnx(gettext("option string too long"));
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.
474 mntflags
|= MS_RDONLY
;
477 mntflags
&= ~MS_RDONLY
;
481 * NFS-derived options for attribute cache
482 * handling (disable, set min/max timeouts)
485 mdatap
->flags
|= SMBFS_MF_NOAC
;
490 val
= strtol(optarg
, &p
, 10);
491 if (errno
|| *p
!= 0)
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
;
503 val
= strtol(optarg
, &p
, 10);
504 if (errno
|| *p
!= 0)
506 mdatap
->acregmin
= val
;
507 mdatap
->flags
|= SMBFS_MF_ACREGMIN
;
512 val
= strtol(optarg
, &p
, 10);
513 if (errno
|| *p
!= 0)
515 mdatap
->acregmax
= val
;
516 mdatap
->flags
|= SMBFS_MF_ACREGMAX
;
521 val
= strtol(optarg
, &p
, 10);
522 if (errno
|| *p
!= 0)
524 mdatap
->acdirmin
= val
;
525 mdatap
->flags
|= SMBFS_MF_ACDIRMIN
;
530 val
= strtol(optarg
, &p
, 10);
531 if (errno
|| *p
!= 0)
533 mdatap
->acdirmax
= val
;
534 mdatap
->flags
|= SMBFS_MF_ACDIRMAX
;
538 * SMBFS-specific options. Some of these
539 * don't go through the mount system call,
540 * but just set libsmbfs options.
543 if (smb_ctx_setdomain(ctx
, optarg
, B_TRUE
) != 0)
548 if (smb_ctx_setuser(ctx
, optarg
, B_TRUE
) != 0)
553 pwd
= isdigit(optarg
[0]) ?
554 getpwuid(atoi(optarg
)) : getpwnam(optarg
);
557 warnx(gettext("unknown user '%s'"), optarg
);
560 mdatap
->uid
= pwd
->pw_uid
;
565 grp
= isdigit(optarg
[0]) ?
566 getgrgid(atoi(optarg
)) : getgrnam(optarg
);
569 warnx(gettext("unknown group '%s'"), optarg
);
572 mdatap
->gid
= grp
->gr_gid
;
578 val
= strtol(optarg
, &p
, 8);
579 if (errno
|| *p
!= 0)
581 mdatap
->dir_mode
= val
;
586 val
= strtol(optarg
, &p
, 8);
587 if (errno
|| *p
!= 0)
589 mdatap
->file_mode
= val
;
599 warnx(gettext("unknown option %s"), subopt
);
605 warnx(gettext("invalid value for %s"), subopt
);
610 /* Undo changes made to subopt */
620 (void) fprintf(stderr
, "%s\n",
621 gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]"
622 " //[workgroup;][user[:password]@]server[/share] path"));