187866Ssheldonh/*
295267Ssheldonh * Copyright (c) 2000-2002, Boris Popov
387866Ssheldonh * All rights reserved.
487866Ssheldonh *
587866Ssheldonh * Redistribution and use in source and binary forms, with or without
687866Ssheldonh * modification, are permitted provided that the following conditions
787866Ssheldonh * are met:
887866Ssheldonh * 1. Redistributions of source code must retain the above copyright
987866Ssheldonh *    notice, this list of conditions and the following disclaimer.
1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
1187866Ssheldonh *    notice, this list of conditions and the following disclaimer in the
1287866Ssheldonh *    documentation and/or other materials provided with the distribution.
1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software
1487866Ssheldonh *    must display the following acknowledgement:
1587866Ssheldonh *    This product includes software developed by Boris Popov.
1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors
1787866Ssheldonh *    may be used to endorse or promote products derived from this software
1887866Ssheldonh *    without specific prior written permission.
1987866Ssheldonh *
2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2387866Ssheldonh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3087866Ssheldonh * SUCH DAMAGE.
3187866Ssheldonh *
3295267Ssheldonh * $Id: mount_smbfs.c,v 1.17 2002/04/10 04:17:51 bp Exp $
33117804Stjr * $FreeBSD: releng/10.3/contrib/smbfs/mount_smbfs/mount_smbfs.c 272118 2014-09-25 17:47:26Z trasz $
3487866Ssheldonh */
3587866Ssheldonh#include <sys/param.h>
3687866Ssheldonh#include <sys/stat.h>
3787866Ssheldonh#include <sys/errno.h>
38130789Smux#include <sys/linker.h>
3987866Ssheldonh#include <sys/mount.h>
4087866Ssheldonh
4187866Ssheldonh#include <stdio.h>
4287866Ssheldonh#include <string.h>
4387866Ssheldonh#include <pwd.h>
4487866Ssheldonh#include <grp.h>
4587866Ssheldonh#include <unistd.h>
4687866Ssheldonh#include <ctype.h>
4787866Ssheldonh#include <stdlib.h>
4887866Ssheldonh#include <err.h>
4987866Ssheldonh#include <sysexits.h>
5087866Ssheldonh
5187866Ssheldonh#include <cflib.h>
5287866Ssheldonh
5387866Ssheldonh#include <netsmb/smb.h>
5487866Ssheldonh#include <netsmb/smb_conn.h>
5587866Ssheldonh#include <netsmb/smb_lib.h>
5687866Ssheldonh
5787866Ssheldonh#include <fs/smbfs/smbfs.h>
5887866Ssheldonh
5987866Ssheldonh#include "mntopts.h"
6087866Ssheldonh
6187866Ssheldonhstatic char mount_point[MAXPATHLEN + 1];
6287866Ssheldonhstatic void usage(void);
6387866Ssheldonh
6487866Ssheldonhstatic struct mntopt mopts[] = {
6587866Ssheldonh	MOPT_STDOPTS,
66152467Srodrigc	MOPT_END
6787866Ssheldonh};
6887866Ssheldonh
69152467Srodrigcstatic char smbfs_vfsname[] = "smbfs";
7087866Ssheldonh
7187866Ssheldonhint
7287866Ssheldonhmain(int argc, char *argv[])
7387866Ssheldonh{
74152467Srodrigc	struct iovec *iov;
75152467Srodrigc	unsigned int iovlen;
7687866Ssheldonh	struct smb_ctx sctx, *ctx = &sctx;
7787866Ssheldonh	struct stat st;
7888282Ssheldonh#ifdef APPLE
7988282Ssheldonh	extern void dropsuid();
8088282Ssheldonh	extern int loadsmbvfs();
81130789Smux#else
82130789Smux	struct xvfsconf vfc;
83128140Smux#endif
84272118Strasz	char *next, *p, *val;
85250236Sdavide	int opt, error, mntflags, caseopt, fd;
86152467Srodrigc	uid_t uid;
87152467Srodrigc	gid_t gid;
88152467Srodrigc	mode_t dir_mode, file_mode;
89152467Srodrigc	char errmsg[255] = { 0 };
9087866Ssheldonh
91152467Srodrigc	iov = NULL;
92152467Srodrigc	iovlen = 0;
93250236Sdavide	fd = 0;
94152523Sru	uid = (uid_t)-1;
95152523Sru	gid = (gid_t)-1;
96152467Srodrigc	caseopt = 0;
97152467Srodrigc	file_mode = 0;
98152467Srodrigc	dir_mode = 0;
9988282Ssheldonh
10088282Ssheldonh#ifdef APPLE
10188282Ssheldonh	dropsuid();
102128140Smux#endif
10387866Ssheldonh	if (argc == 2) {
10487866Ssheldonh		if (strcmp(argv[1], "-h") == 0) {
10587866Ssheldonh			usage();
10687866Ssheldonh		}
10787866Ssheldonh	}
10887866Ssheldonh	if (argc < 3)
10987866Ssheldonh		usage();
11087866Ssheldonh
11188282Ssheldonh#ifdef APPLE
11288282Ssheldonh	error = loadsmbvfs();
113130789Smux#else
114152467Srodrigc	error = getvfsbyname(smbfs_vfsname, &vfc);
115130789Smux	if (error) {
116152467Srodrigc		if (kldload(smbfs_vfsname) < 0)
117152467Srodrigc			err(EX_OSERR, "kldload(%s)", smbfs_vfsname);
118152467Srodrigc		error = getvfsbyname(smbfs_vfsname, &vfc);
119130789Smux	}
120130789Smux#endif
12187866Ssheldonh	if (error)
12287866Ssheldonh		errx(EX_OSERR, "SMB filesystem is not available");
12387866Ssheldonh
12487866Ssheldonh	if (smb_lib_init() != 0)
12587866Ssheldonh		exit(1);
12687866Ssheldonh
12787866Ssheldonh	mntflags = error = 0;
128152467Srodrigc
12987866Ssheldonh	caseopt = SMB_CS_NONE;
13087866Ssheldonh
13187866Ssheldonh	if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0)
13287866Ssheldonh		exit(1);
13387866Ssheldonh	if (smb_ctx_readrc(ctx) != 0)
13487866Ssheldonh		exit(1);
13587866Ssheldonh	if (smb_rc)
13687866Ssheldonh		rc_close(smb_rc);
13787866Ssheldonh
13887866Ssheldonh	while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) {
13987866Ssheldonh		switch (opt) {
14087866Ssheldonh		    case STDPARAM_ARGS:
14187866Ssheldonh			error = smb_ctx_opt(ctx, opt, optarg);
14287866Ssheldonh			if (error)
14387866Ssheldonh				exit(1);
14487866Ssheldonh			break;
14587866Ssheldonh		    case 'u': {
14687866Ssheldonh			struct passwd *pwd;
14787866Ssheldonh
14887866Ssheldonh			pwd = isdigit(optarg[0]) ?
14987866Ssheldonh			    getpwuid(atoi(optarg)) : getpwnam(optarg);
15087866Ssheldonh			if (pwd == NULL)
15187866Ssheldonh				errx(EX_NOUSER, "unknown user '%s'", optarg);
152152467Srodrigc			uid = pwd->pw_uid;
15387866Ssheldonh			break;
15487866Ssheldonh		    }
15587866Ssheldonh		    case 'g': {
15687866Ssheldonh			struct group *grp;
15787866Ssheldonh
15887866Ssheldonh			grp = isdigit(optarg[0]) ?
15987866Ssheldonh			    getgrgid(atoi(optarg)) : getgrnam(optarg);
16087866Ssheldonh			if (grp == NULL)
16187866Ssheldonh				errx(EX_NOUSER, "unknown group '%s'", optarg);
162152467Srodrigc			gid = grp->gr_gid;
16387866Ssheldonh			break;
16487866Ssheldonh		    }
16587866Ssheldonh		    case 'd':
16687866Ssheldonh			errno = 0;
167152467Srodrigc			dir_mode = strtol(optarg, &next, 8);
16887866Ssheldonh			if (errno || *next != 0)
16987866Ssheldonh				errx(EX_DATAERR, "invalid value for directory mode");
17087866Ssheldonh			break;
17187866Ssheldonh		    case 'f':
17287866Ssheldonh			errno = 0;
173152467Srodrigc			file_mode = strtol(optarg, &next, 8);
17487866Ssheldonh			if (errno || *next != 0)
17587866Ssheldonh				errx(EX_DATAERR, "invalid value for file mode");
17687866Ssheldonh			break;
17787866Ssheldonh		    case '?':
17887866Ssheldonh			usage();
17987866Ssheldonh			/*NOTREACHED*/
18087866Ssheldonh		    case 'n': {
18187866Ssheldonh			char *inp, *nsp;
18287866Ssheldonh
18387866Ssheldonh			nsp = inp = optarg;
18487866Ssheldonh			while ((nsp = strsep(&inp, ",;:")) != NULL) {
185152467Srodrigc				if (strcasecmp(nsp, "LONG") == 0) {
186152467Srodrigc					build_iovec(&iov, &iovlen,
187152467Srodrigc					    "nolong", NULL, 0);
188152467Srodrigc				} else {
189152467Srodrigc					errx(EX_DATAERR,
190152467Srodrigc					    "unknown suboption '%s'", nsp);
191152467Srodrigc				}
19287866Ssheldonh			}
19387866Ssheldonh			break;
19487866Ssheldonh		    };
19587866Ssheldonh		    case 'o':
19687866Ssheldonh			getmntopts(optarg, mopts, &mntflags, 0);
197272118Strasz			p = strchr(optarg, '=');
198272118Strasz			val = NULL;
199272118Strasz			if (p != NULL) {
200272118Strasz				*p = '\0';
201272118Strasz				val = p + 1;
202272118Strasz			}
203272118Strasz			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
20487866Ssheldonh			break;
20587866Ssheldonh		    case 'c':
20687866Ssheldonh			switch (optarg[0]) {
20787866Ssheldonh			    case 'l':
20887866Ssheldonh				caseopt |= SMB_CS_LOWER;
20987866Ssheldonh				break;
21087866Ssheldonh			    case 'u':
21187866Ssheldonh				caseopt |= SMB_CS_UPPER;
21287866Ssheldonh				break;
21387866Ssheldonh			    default:
21487866Ssheldonh		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
21587866Ssheldonh				    optarg[0]);
21687866Ssheldonh			}
21787866Ssheldonh			break;
21887866Ssheldonh		    default:
21987866Ssheldonh			usage();
22087866Ssheldonh		}
22187866Ssheldonh	}
22287866Ssheldonh
22387866Ssheldonh	if (optind == argc - 2)
22487866Ssheldonh		optind++;
22587866Ssheldonh
22687866Ssheldonh	if (optind != argc - 1)
22787866Ssheldonh		usage();
22887866Ssheldonh	realpath(argv[optind], mount_point);
22987866Ssheldonh
23087866Ssheldonh	if (stat(mount_point, &st) == -1)
23187866Ssheldonh		err(EX_OSERR, "could not find mount point %s", mount_point);
23287866Ssheldonh	if (!S_ISDIR(st.st_mode)) {
23387866Ssheldonh		errno = ENOTDIR;
23487866Ssheldonh		err(EX_OSERR, "can't mount on %s", mount_point);
23587866Ssheldonh	}
23687866Ssheldonh/*
23787866Ssheldonh	if (smb_getextattr(mount_point, &einfo) == 0)
23887866Ssheldonh		errx(EX_OSERR, "can't mount on %s twice", mount_point);
23987866Ssheldonh*/
240152523Sru	if (uid == (uid_t)-1)
241152467Srodrigc		uid = st.st_uid;
242152523Sru	if (gid == (gid_t)-1)
243152467Srodrigc		gid = st.st_gid;
244152467Srodrigc	if (file_mode == 0 )
245152467Srodrigc		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
246152467Srodrigc	if (dir_mode == 0) {
247152467Srodrigc		dir_mode = file_mode;
248152467Srodrigc		if (dir_mode & S_IRUSR)
249152467Srodrigc			dir_mode |= S_IXUSR;
250152467Srodrigc		if (dir_mode & S_IRGRP)
251152467Srodrigc			dir_mode |= S_IXGRP;
252152467Srodrigc		if (dir_mode & S_IROTH)
253152467Srodrigc			dir_mode |= S_IXOTH;
25487866Ssheldonh	}
25587866Ssheldonh	/*
25687866Ssheldonh	 * For now, let connection be private for this mount
25787866Ssheldonh	 */
25887866Ssheldonh	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
25987866Ssheldonh	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
260152467Srodrigc	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
26187866Ssheldonh	opt = 0;
262152467Srodrigc	if (dir_mode & S_IXGRP)
26387866Ssheldonh		opt |= SMBM_EXECGRP;
264152467Srodrigc	if (dir_mode & S_IXOTH)
26587866Ssheldonh		opt |= SMBM_EXECOTH;
26687866Ssheldonh	ctx->ct_ssn.ioc_rights |= opt;
26787866Ssheldonh	ctx->ct_sh.ioc_rights |= opt;
26887866Ssheldonh	error = smb_ctx_resolve(ctx);
26987866Ssheldonh	if (error)
27087866Ssheldonh		exit(1);
27187866Ssheldonh	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
27287866Ssheldonh	if (error) {
27387866Ssheldonh		exit(1);
27487866Ssheldonh	}
275152467Srodrigc
276250236Sdavide	fd = ctx->ct_fd;
277152467Srodrigc
278152467Srodrigc	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
279152467Srodrigc	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
280250236Sdavide	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
281152467Srodrigc	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
282152467Srodrigc	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
283152467Srodrigc	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
284152467Srodrigc	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
285152467Srodrigc	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
286152467Srodrigc	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
287152467Srodrigc	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg);
288152467Srodrigc
289152467Srodrigc	error = nmount(iov, iovlen, mntflags);
29087866Ssheldonh	smb_ctx_done(ctx);
29187866Ssheldonh	if (error) {
292152467Srodrigc		smb_error("mount error: %s %s", error, mount_point, errmsg);
29387866Ssheldonh		exit(1);
29487866Ssheldonh	}
29587866Ssheldonh	return 0;
29687866Ssheldonh}
29787866Ssheldonh
29887866Ssheldonhstatic void
29987866Ssheldonhusage(void)
30087866Ssheldonh{
30187866Ssheldonh	fprintf(stderr, "%s\n%s\n%s\n%s\n",
30288492Ssheldonh	"usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]",
30388492Ssheldonh	"                   [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]",
30488492Ssheldonh	"                   [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]",
305187583Strhodes	"                   [-g gid] [-n opt] [-u uid] [-U username] //user@server/share node");
30687866Ssheldonh
30787866Ssheldonh	exit (1);
30887866Ssheldonh}
309