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$
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
8487866Ssheldonh	char *next;
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);
19787866Ssheldonh			break;
19887866Ssheldonh		    case 'c':
19987866Ssheldonh			switch (optarg[0]) {
20087866Ssheldonh			    case 'l':
20187866Ssheldonh				caseopt |= SMB_CS_LOWER;
20287866Ssheldonh				break;
20387866Ssheldonh			    case 'u':
20487866Ssheldonh				caseopt |= SMB_CS_UPPER;
20587866Ssheldonh				break;
20687866Ssheldonh			    default:
20787866Ssheldonh		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
20887866Ssheldonh				    optarg[0]);
20987866Ssheldonh			}
21087866Ssheldonh			break;
21187866Ssheldonh		    default:
21287866Ssheldonh			usage();
21387866Ssheldonh		}
21487866Ssheldonh	}
21587866Ssheldonh
21687866Ssheldonh	if (optind == argc - 2)
21787866Ssheldonh		optind++;
21887866Ssheldonh
21987866Ssheldonh	if (optind != argc - 1)
22087866Ssheldonh		usage();
22187866Ssheldonh	realpath(argv[optind], mount_point);
22287866Ssheldonh
22387866Ssheldonh	if (stat(mount_point, &st) == -1)
22487866Ssheldonh		err(EX_OSERR, "could not find mount point %s", mount_point);
22587866Ssheldonh	if (!S_ISDIR(st.st_mode)) {
22687866Ssheldonh		errno = ENOTDIR;
22787866Ssheldonh		err(EX_OSERR, "can't mount on %s", mount_point);
22887866Ssheldonh	}
22987866Ssheldonh/*
23087866Ssheldonh	if (smb_getextattr(mount_point, &einfo) == 0)
23187866Ssheldonh		errx(EX_OSERR, "can't mount on %s twice", mount_point);
23287866Ssheldonh*/
233152523Sru	if (uid == (uid_t)-1)
234152467Srodrigc		uid = st.st_uid;
235152523Sru	if (gid == (gid_t)-1)
236152467Srodrigc		gid = st.st_gid;
237152467Srodrigc	if (file_mode == 0 )
238152467Srodrigc		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
239152467Srodrigc	if (dir_mode == 0) {
240152467Srodrigc		dir_mode = file_mode;
241152467Srodrigc		if (dir_mode & S_IRUSR)
242152467Srodrigc			dir_mode |= S_IXUSR;
243152467Srodrigc		if (dir_mode & S_IRGRP)
244152467Srodrigc			dir_mode |= S_IXGRP;
245152467Srodrigc		if (dir_mode & S_IROTH)
246152467Srodrigc			dir_mode |= S_IXOTH;
24787866Ssheldonh	}
24887866Ssheldonh	/*
24987866Ssheldonh	 * For now, let connection be private for this mount
25087866Ssheldonh	 */
25187866Ssheldonh	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
25287866Ssheldonh	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
253152467Srodrigc	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
25487866Ssheldonh	opt = 0;
255152467Srodrigc	if (dir_mode & S_IXGRP)
25687866Ssheldonh		opt |= SMBM_EXECGRP;
257152467Srodrigc	if (dir_mode & S_IXOTH)
25887866Ssheldonh		opt |= SMBM_EXECOTH;
25987866Ssheldonh	ctx->ct_ssn.ioc_rights |= opt;
26087866Ssheldonh	ctx->ct_sh.ioc_rights |= opt;
26187866Ssheldonh	error = smb_ctx_resolve(ctx);
26287866Ssheldonh	if (error)
26387866Ssheldonh		exit(1);
26487866Ssheldonh	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
26587866Ssheldonh	if (error) {
26687866Ssheldonh		exit(1);
26787866Ssheldonh	}
268152467Srodrigc
269250236Sdavide	fd = ctx->ct_fd;
270152467Srodrigc
271152467Srodrigc	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
272152467Srodrigc	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
273250236Sdavide	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
274152467Srodrigc	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
275152467Srodrigc	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
276152467Srodrigc	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
277152467Srodrigc	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
278152467Srodrigc	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
279152467Srodrigc	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
280152467Srodrigc	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg);
281152467Srodrigc
282152467Srodrigc	error = nmount(iov, iovlen, mntflags);
28387866Ssheldonh	smb_ctx_done(ctx);
28487866Ssheldonh	if (error) {
285152467Srodrigc		smb_error("mount error: %s %s", error, mount_point, errmsg);
28687866Ssheldonh		exit(1);
28787866Ssheldonh	}
28887866Ssheldonh	return 0;
28987866Ssheldonh}
29087866Ssheldonh
29187866Ssheldonhstatic void
29287866Ssheldonhusage(void)
29387866Ssheldonh{
29487866Ssheldonh	fprintf(stderr, "%s\n%s\n%s\n%s\n",
29588492Ssheldonh	"usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]",
29688492Ssheldonh	"                   [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]",
29788492Ssheldonh	"                   [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]",
298187583Strhodes	"                   [-g gid] [-n opt] [-u uid] [-U username] //user@server/share node");
29987866Ssheldonh
30087866Ssheldonh	exit (1);
30187866Ssheldonh}
302