xref: /freebsd/contrib/smbfs/mount_smbfs/mount_smbfs.c (revision a123502ef781ea052e842af25c7aeb64fd9fe217)
1f1b9d127SSheldon Hearn /*
234ffbc80SSheldon Hearn  * Copyright (c) 2000-2002, Boris Popov
3f1b9d127SSheldon Hearn  * All rights reserved.
4f1b9d127SSheldon Hearn  *
5f1b9d127SSheldon Hearn  * Redistribution and use in source and binary forms, with or without
6f1b9d127SSheldon Hearn  * modification, are permitted provided that the following conditions
7f1b9d127SSheldon Hearn  * are met:
8f1b9d127SSheldon Hearn  * 1. Redistributions of source code must retain the above copyright
9f1b9d127SSheldon Hearn  *    notice, this list of conditions and the following disclaimer.
10f1b9d127SSheldon Hearn  * 2. Redistributions in binary form must reproduce the above copyright
11f1b9d127SSheldon Hearn  *    notice, this list of conditions and the following disclaimer in the
12f1b9d127SSheldon Hearn  *    documentation and/or other materials provided with the distribution.
13f1b9d127SSheldon Hearn  * 3. All advertising materials mentioning features or use of this software
14f1b9d127SSheldon Hearn  *    must display the following acknowledgement:
15f1b9d127SSheldon Hearn  *    This product includes software developed by Boris Popov.
16f1b9d127SSheldon Hearn  * 4. Neither the name of the author nor the names of any co-contributors
17f1b9d127SSheldon Hearn  *    may be used to endorse or promote products derived from this software
18f1b9d127SSheldon Hearn  *    without specific prior written permission.
19f1b9d127SSheldon Hearn  *
20f1b9d127SSheldon Hearn  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21f1b9d127SSheldon Hearn  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22f1b9d127SSheldon Hearn  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23f1b9d127SSheldon Hearn  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24f1b9d127SSheldon Hearn  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25f1b9d127SSheldon Hearn  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26f1b9d127SSheldon Hearn  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27f1b9d127SSheldon Hearn  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28f1b9d127SSheldon Hearn  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29f1b9d127SSheldon Hearn  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30f1b9d127SSheldon Hearn  * SUCH DAMAGE.
31f1b9d127SSheldon Hearn  *
3234ffbc80SSheldon Hearn  * $Id: mount_smbfs.c,v 1.17 2002/04/10 04:17:51 bp Exp $
33b97916daSTim J. Robbins  * $FreeBSD$
34f1b9d127SSheldon Hearn  */
35f1b9d127SSheldon Hearn #include <sys/param.h>
36f1b9d127SSheldon Hearn #include <sys/stat.h>
37f1b9d127SSheldon Hearn #include <sys/errno.h>
3856cb1e8cSMaxime Henrion #include <sys/linker.h>
39f1b9d127SSheldon Hearn #include <sys/mount.h>
40f1b9d127SSheldon Hearn 
41f1b9d127SSheldon Hearn #include <stdio.h>
42f1b9d127SSheldon Hearn #include <string.h>
43f1b9d127SSheldon Hearn #include <pwd.h>
44f1b9d127SSheldon Hearn #include <grp.h>
45f1b9d127SSheldon Hearn #include <unistd.h>
46f1b9d127SSheldon Hearn #include <ctype.h>
47f1b9d127SSheldon Hearn #include <stdlib.h>
48f1b9d127SSheldon Hearn #include <err.h>
49f1b9d127SSheldon Hearn #include <sysexits.h>
50*a123502eSBrooks Davis #include <mntopts.h>
51f1b9d127SSheldon Hearn 
52f1b9d127SSheldon Hearn #include <cflib.h>
53f1b9d127SSheldon Hearn 
54f1b9d127SSheldon Hearn #include <netsmb/smb.h>
55f1b9d127SSheldon Hearn #include <netsmb/smb_conn.h>
56f1b9d127SSheldon Hearn #include <netsmb/smb_lib.h>
57f1b9d127SSheldon Hearn 
58f1b9d127SSheldon Hearn #include <fs/smbfs/smbfs.h>
59f1b9d127SSheldon Hearn 
60f1b9d127SSheldon Hearn static char mount_point[MAXPATHLEN + 1];
61f1b9d127SSheldon Hearn static void usage(void);
62f1b9d127SSheldon Hearn 
63f1b9d127SSheldon Hearn static struct mntopt mopts[] = {
64f1b9d127SSheldon Hearn 	MOPT_STDOPTS,
65c76b3c84SCraig Rodrigues 	MOPT_END
66f1b9d127SSheldon Hearn };
67f1b9d127SSheldon Hearn 
68c76b3c84SCraig Rodrigues static char smbfs_vfsname[] = "smbfs";
69f1b9d127SSheldon Hearn 
70f1b9d127SSheldon Hearn int
main(int argc,char * argv[])71f1b9d127SSheldon Hearn main(int argc, char *argv[])
72f1b9d127SSheldon Hearn {
73c76b3c84SCraig Rodrigues 	struct iovec *iov;
74c76b3c84SCraig Rodrigues 	unsigned int iovlen;
75f1b9d127SSheldon Hearn 	struct smb_ctx sctx, *ctx = &sctx;
76f1b9d127SSheldon Hearn 	struct stat st;
77df3342d6SSheldon Hearn #ifdef APPLE
78df3342d6SSheldon Hearn 	extern void dropsuid();
79df3342d6SSheldon Hearn 	extern int loadsmbvfs();
8056cb1e8cSMaxime Henrion #else
8156cb1e8cSMaxime Henrion 	struct xvfsconf vfc;
8224449958SMaxime Henrion #endif
83afe21afeSEdward Tomasz Napierala 	char *next, *p, *val;
8492a4d9bcSDavide Italiano 	int opt, error, mntflags, caseopt, fd;
85c76b3c84SCraig Rodrigues 	uid_t uid;
86c76b3c84SCraig Rodrigues 	gid_t gid;
87c76b3c84SCraig Rodrigues 	mode_t dir_mode, file_mode;
88c76b3c84SCraig Rodrigues 	char errmsg[255] = { 0 };
89f1b9d127SSheldon Hearn 
90c76b3c84SCraig Rodrigues 	iov = NULL;
91c76b3c84SCraig Rodrigues 	iovlen = 0;
9292a4d9bcSDavide Italiano 	fd = 0;
931a6c5d9fSRuslan Ermilov 	uid = (uid_t)-1;
941a6c5d9fSRuslan Ermilov 	gid = (gid_t)-1;
95c76b3c84SCraig Rodrigues 	caseopt = 0;
96c76b3c84SCraig Rodrigues 	file_mode = 0;
97c76b3c84SCraig Rodrigues 	dir_mode = 0;
98df3342d6SSheldon Hearn 
99df3342d6SSheldon Hearn #ifdef APPLE
100df3342d6SSheldon Hearn 	dropsuid();
10124449958SMaxime Henrion #endif
102f1b9d127SSheldon Hearn 	if (argc == 2) {
103f1b9d127SSheldon Hearn 		if (strcmp(argv[1], "-h") == 0) {
104f1b9d127SSheldon Hearn 			usage();
105f1b9d127SSheldon Hearn 		}
106f1b9d127SSheldon Hearn 	}
107f1b9d127SSheldon Hearn 	if (argc < 3)
108f1b9d127SSheldon Hearn 		usage();
109f1b9d127SSheldon Hearn 
110df3342d6SSheldon Hearn #ifdef APPLE
111df3342d6SSheldon Hearn 	error = loadsmbvfs();
11256cb1e8cSMaxime Henrion #else
113c76b3c84SCraig Rodrigues 	error = getvfsbyname(smbfs_vfsname, &vfc);
11456cb1e8cSMaxime Henrion 	if (error) {
115c76b3c84SCraig Rodrigues 		if (kldload(smbfs_vfsname) < 0)
116c76b3c84SCraig Rodrigues 			err(EX_OSERR, "kldload(%s)", smbfs_vfsname);
117c76b3c84SCraig Rodrigues 		error = getvfsbyname(smbfs_vfsname, &vfc);
11856cb1e8cSMaxime Henrion 	}
11956cb1e8cSMaxime Henrion #endif
120f1b9d127SSheldon Hearn 	if (error)
121f1b9d127SSheldon Hearn 		errx(EX_OSERR, "SMB filesystem is not available");
122f1b9d127SSheldon Hearn 
123f1b9d127SSheldon Hearn 	if (smb_lib_init() != 0)
124f1b9d127SSheldon Hearn 		exit(1);
125f1b9d127SSheldon Hearn 
126f1b9d127SSheldon Hearn 	mntflags = error = 0;
127c76b3c84SCraig Rodrigues 
128f1b9d127SSheldon Hearn 	caseopt = SMB_CS_NONE;
129f1b9d127SSheldon Hearn 
130f1b9d127SSheldon Hearn 	if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0)
131f1b9d127SSheldon Hearn 		exit(1);
132f1b9d127SSheldon Hearn 	if (smb_ctx_readrc(ctx) != 0)
133f1b9d127SSheldon Hearn 		exit(1);
134f1b9d127SSheldon Hearn 	if (smb_rc)
135f1b9d127SSheldon Hearn 		rc_close(smb_rc);
136f1b9d127SSheldon Hearn 
137f1b9d127SSheldon Hearn 	while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) {
138f1b9d127SSheldon Hearn 		switch (opt) {
139f1b9d127SSheldon Hearn 		    case STDPARAM_ARGS:
140f1b9d127SSheldon Hearn 			error = smb_ctx_opt(ctx, opt, optarg);
141f1b9d127SSheldon Hearn 			if (error)
142f1b9d127SSheldon Hearn 				exit(1);
143f1b9d127SSheldon Hearn 			break;
144f1b9d127SSheldon Hearn 		    case 'u': {
145f1b9d127SSheldon Hearn 			struct passwd *pwd;
146f1b9d127SSheldon Hearn 
147f1b9d127SSheldon Hearn 			pwd = isdigit(optarg[0]) ?
148f1b9d127SSheldon Hearn 			    getpwuid(atoi(optarg)) : getpwnam(optarg);
149f1b9d127SSheldon Hearn 			if (pwd == NULL)
150f1b9d127SSheldon Hearn 				errx(EX_NOUSER, "unknown user '%s'", optarg);
151c76b3c84SCraig Rodrigues 			uid = pwd->pw_uid;
152f1b9d127SSheldon Hearn 			break;
153f1b9d127SSheldon Hearn 		    }
154f1b9d127SSheldon Hearn 		    case 'g': {
155f1b9d127SSheldon Hearn 			struct group *grp;
156f1b9d127SSheldon Hearn 
157f1b9d127SSheldon Hearn 			grp = isdigit(optarg[0]) ?
158f1b9d127SSheldon Hearn 			    getgrgid(atoi(optarg)) : getgrnam(optarg);
159f1b9d127SSheldon Hearn 			if (grp == NULL)
160f1b9d127SSheldon Hearn 				errx(EX_NOUSER, "unknown group '%s'", optarg);
161c76b3c84SCraig Rodrigues 			gid = grp->gr_gid;
162f1b9d127SSheldon Hearn 			break;
163f1b9d127SSheldon Hearn 		    }
164f1b9d127SSheldon Hearn 		    case 'd':
165f1b9d127SSheldon Hearn 			errno = 0;
166c76b3c84SCraig Rodrigues 			dir_mode = strtol(optarg, &next, 8);
167f1b9d127SSheldon Hearn 			if (errno || *next != 0)
168f1b9d127SSheldon Hearn 				errx(EX_DATAERR, "invalid value for directory mode");
169f1b9d127SSheldon Hearn 			break;
170f1b9d127SSheldon Hearn 		    case 'f':
171f1b9d127SSheldon Hearn 			errno = 0;
172c76b3c84SCraig Rodrigues 			file_mode = strtol(optarg, &next, 8);
173f1b9d127SSheldon Hearn 			if (errno || *next != 0)
174f1b9d127SSheldon Hearn 				errx(EX_DATAERR, "invalid value for file mode");
175f1b9d127SSheldon Hearn 			break;
176f1b9d127SSheldon Hearn 		    case '?':
177f1b9d127SSheldon Hearn 			usage();
178f1b9d127SSheldon Hearn 			/*NOTREACHED*/
179f1b9d127SSheldon Hearn 		    case 'n': {
180f1b9d127SSheldon Hearn 			char *inp, *nsp;
181f1b9d127SSheldon Hearn 
182f1b9d127SSheldon Hearn 			nsp = inp = optarg;
183f1b9d127SSheldon Hearn 			while ((nsp = strsep(&inp, ",;:")) != NULL) {
184c76b3c84SCraig Rodrigues 				if (strcasecmp(nsp, "LONG") == 0) {
185c76b3c84SCraig Rodrigues 					build_iovec(&iov, &iovlen,
186c76b3c84SCraig Rodrigues 					    "nolong", NULL, 0);
187c76b3c84SCraig Rodrigues 				} else {
188c76b3c84SCraig Rodrigues 					errx(EX_DATAERR,
189c76b3c84SCraig Rodrigues 					    "unknown suboption '%s'", nsp);
190c76b3c84SCraig Rodrigues 				}
191f1b9d127SSheldon Hearn 			}
192f1b9d127SSheldon Hearn 			break;
193f1b9d127SSheldon Hearn 		    };
194f1b9d127SSheldon Hearn 		    case 'o':
195f1b9d127SSheldon Hearn 			getmntopts(optarg, mopts, &mntflags, 0);
196afe21afeSEdward Tomasz Napierala 			p = strchr(optarg, '=');
197afe21afeSEdward Tomasz Napierala 			val = NULL;
198afe21afeSEdward Tomasz Napierala 			if (p != NULL) {
199afe21afeSEdward Tomasz Napierala 				*p = '\0';
200afe21afeSEdward Tomasz Napierala 				val = p + 1;
201afe21afeSEdward Tomasz Napierala 			}
202afe21afeSEdward Tomasz Napierala 			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
203f1b9d127SSheldon Hearn 			break;
204f1b9d127SSheldon Hearn 		    case 'c':
205f1b9d127SSheldon Hearn 			switch (optarg[0]) {
206f1b9d127SSheldon Hearn 			    case 'l':
207f1b9d127SSheldon Hearn 				caseopt |= SMB_CS_LOWER;
208f1b9d127SSheldon Hearn 				break;
209f1b9d127SSheldon Hearn 			    case 'u':
210f1b9d127SSheldon Hearn 				caseopt |= SMB_CS_UPPER;
211f1b9d127SSheldon Hearn 				break;
212f1b9d127SSheldon Hearn 			    default:
213f1b9d127SSheldon Hearn 		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
214f1b9d127SSheldon Hearn 				    optarg[0]);
215f1b9d127SSheldon Hearn 			}
216f1b9d127SSheldon Hearn 			break;
217f1b9d127SSheldon Hearn 		    default:
218f1b9d127SSheldon Hearn 			usage();
219f1b9d127SSheldon Hearn 		}
220f1b9d127SSheldon Hearn 	}
221f1b9d127SSheldon Hearn 
222f1b9d127SSheldon Hearn 	if (optind == argc - 2)
223f1b9d127SSheldon Hearn 		optind++;
224f1b9d127SSheldon Hearn 
225f1b9d127SSheldon Hearn 	if (optind != argc - 1)
226f1b9d127SSheldon Hearn 		usage();
227f1b9d127SSheldon Hearn 	realpath(argv[optind], mount_point);
228f1b9d127SSheldon Hearn 
229f1b9d127SSheldon Hearn 	if (stat(mount_point, &st) == -1)
230f1b9d127SSheldon Hearn 		err(EX_OSERR, "could not find mount point %s", mount_point);
231f1b9d127SSheldon Hearn 	if (!S_ISDIR(st.st_mode)) {
232f1b9d127SSheldon Hearn 		errno = ENOTDIR;
233f1b9d127SSheldon Hearn 		err(EX_OSERR, "can't mount on %s", mount_point);
234f1b9d127SSheldon Hearn 	}
235f1b9d127SSheldon Hearn /*
236f1b9d127SSheldon Hearn 	if (smb_getextattr(mount_point, &einfo) == 0)
237f1b9d127SSheldon Hearn 		errx(EX_OSERR, "can't mount on %s twice", mount_point);
238f1b9d127SSheldon Hearn */
2391a6c5d9fSRuslan Ermilov 	if (uid == (uid_t)-1)
240c76b3c84SCraig Rodrigues 		uid = st.st_uid;
2411a6c5d9fSRuslan Ermilov 	if (gid == (gid_t)-1)
242c76b3c84SCraig Rodrigues 		gid = st.st_gid;
243c76b3c84SCraig Rodrigues 	if (file_mode == 0 )
244c76b3c84SCraig Rodrigues 		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
245c76b3c84SCraig Rodrigues 	if (dir_mode == 0) {
246c76b3c84SCraig Rodrigues 		dir_mode = file_mode;
247c76b3c84SCraig Rodrigues 		if (dir_mode & S_IRUSR)
248c76b3c84SCraig Rodrigues 			dir_mode |= S_IXUSR;
249c76b3c84SCraig Rodrigues 		if (dir_mode & S_IRGRP)
250c76b3c84SCraig Rodrigues 			dir_mode |= S_IXGRP;
251c76b3c84SCraig Rodrigues 		if (dir_mode & S_IROTH)
252c76b3c84SCraig Rodrigues 			dir_mode |= S_IXOTH;
253f1b9d127SSheldon Hearn 	}
254f1b9d127SSheldon Hearn 	/*
255f1b9d127SSheldon Hearn 	 * For now, let connection be private for this mount
256f1b9d127SSheldon Hearn 	 */
257f1b9d127SSheldon Hearn 	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
258f1b9d127SSheldon Hearn 	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
259c76b3c84SCraig Rodrigues 	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
260f1b9d127SSheldon Hearn 	opt = 0;
261c76b3c84SCraig Rodrigues 	if (dir_mode & S_IXGRP)
262f1b9d127SSheldon Hearn 		opt |= SMBM_EXECGRP;
263c76b3c84SCraig Rodrigues 	if (dir_mode & S_IXOTH)
264f1b9d127SSheldon Hearn 		opt |= SMBM_EXECOTH;
265f1b9d127SSheldon Hearn 	ctx->ct_ssn.ioc_rights |= opt;
266f1b9d127SSheldon Hearn 	ctx->ct_sh.ioc_rights |= opt;
267f1b9d127SSheldon Hearn 	error = smb_ctx_resolve(ctx);
268f1b9d127SSheldon Hearn 	if (error)
269f1b9d127SSheldon Hearn 		exit(1);
270f1b9d127SSheldon Hearn 	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
271f1b9d127SSheldon Hearn 	if (error) {
272f1b9d127SSheldon Hearn 		exit(1);
273f1b9d127SSheldon Hearn 	}
274c76b3c84SCraig Rodrigues 
27592a4d9bcSDavide Italiano 	fd = ctx->ct_fd;
276c76b3c84SCraig Rodrigues 
277c76b3c84SCraig Rodrigues 	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
278c76b3c84SCraig Rodrigues 	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
27992a4d9bcSDavide Italiano 	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
280c76b3c84SCraig Rodrigues 	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
281c76b3c84SCraig Rodrigues 	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
282c76b3c84SCraig Rodrigues 	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
283c76b3c84SCraig Rodrigues 	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
284c76b3c84SCraig Rodrigues 	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
285c76b3c84SCraig Rodrigues 	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
286c76b3c84SCraig Rodrigues 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg);
287c76b3c84SCraig Rodrigues 
288c76b3c84SCraig Rodrigues 	error = nmount(iov, iovlen, mntflags);
289f1b9d127SSheldon Hearn 	smb_ctx_done(ctx);
290f1b9d127SSheldon Hearn 	if (error) {
291c76b3c84SCraig Rodrigues 		smb_error("mount error: %s %s", error, mount_point, errmsg);
292f1b9d127SSheldon Hearn 		exit(1);
293f1b9d127SSheldon Hearn 	}
294f1b9d127SSheldon Hearn 	return 0;
295f1b9d127SSheldon Hearn }
296f1b9d127SSheldon Hearn 
297f1b9d127SSheldon Hearn static void
usage(void)298f1b9d127SSheldon Hearn usage(void)
299f1b9d127SSheldon Hearn {
300f1b9d127SSheldon Hearn 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
3018d4076f0SSheldon Hearn 	"usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]",
3028d4076f0SSheldon Hearn 	"                   [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]",
3038d4076f0SSheldon Hearn 	"                   [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]",
304377e63adSTom Rhodes 	"                   [-g gid] [-n opt] [-u uid] [-U username] //user@server/share node");
305f1b9d127SSheldon Hearn 
306f1b9d127SSheldon Hearn 	exit (1);
307f1b9d127SSheldon Hearn }
308