xref: /freebsd/contrib/smbfs/mount_smbfs/mount_smbfs.c (revision a123502ef781ea052e842af25c7aeb64fd9fe217)
1 /*
2  * Copyright (c) 2000-2002, Boris Popov
3  * All rights reserved.
4  *
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.
19  *
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.
31  *
32  * $Id: mount_smbfs.c,v 1.17 2002/04/10 04:17:51 bp Exp $
33  * $FreeBSD$
34  */
35 #include <sys/param.h>
36 #include <sys/stat.h>
37 #include <sys/errno.h>
38 #include <sys/linker.h>
39 #include <sys/mount.h>
40 
41 #include <stdio.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <grp.h>
45 #include <unistd.h>
46 #include <ctype.h>
47 #include <stdlib.h>
48 #include <err.h>
49 #include <sysexits.h>
50 #include <mntopts.h>
51 
52 #include <cflib.h>
53 
54 #include <netsmb/smb.h>
55 #include <netsmb/smb_conn.h>
56 #include <netsmb/smb_lib.h>
57 
58 #include <fs/smbfs/smbfs.h>
59 
60 static char mount_point[MAXPATHLEN + 1];
61 static void usage(void);
62 
63 static struct mntopt mopts[] = {
64 	MOPT_STDOPTS,
65 	MOPT_END
66 };
67 
68 static char smbfs_vfsname[] = "smbfs";
69 
70 int
main(int argc,char * argv[])71 main(int argc, char *argv[])
72 {
73 	struct iovec *iov;
74 	unsigned int iovlen;
75 	struct smb_ctx sctx, *ctx = &sctx;
76 	struct stat st;
77 #ifdef APPLE
78 	extern void dropsuid();
79 	extern int loadsmbvfs();
80 #else
81 	struct xvfsconf vfc;
82 #endif
83 	char *next, *p, *val;
84 	int opt, error, mntflags, caseopt, fd;
85 	uid_t uid;
86 	gid_t gid;
87 	mode_t dir_mode, file_mode;
88 	char errmsg[255] = { 0 };
89 
90 	iov = NULL;
91 	iovlen = 0;
92 	fd = 0;
93 	uid = (uid_t)-1;
94 	gid = (gid_t)-1;
95 	caseopt = 0;
96 	file_mode = 0;
97 	dir_mode = 0;
98 
99 #ifdef APPLE
100 	dropsuid();
101 #endif
102 	if (argc == 2) {
103 		if (strcmp(argv[1], "-h") == 0) {
104 			usage();
105 		}
106 	}
107 	if (argc < 3)
108 		usage();
109 
110 #ifdef APPLE
111 	error = loadsmbvfs();
112 #else
113 	error = getvfsbyname(smbfs_vfsname, &vfc);
114 	if (error) {
115 		if (kldload(smbfs_vfsname) < 0)
116 			err(EX_OSERR, "kldload(%s)", smbfs_vfsname);
117 		error = getvfsbyname(smbfs_vfsname, &vfc);
118 	}
119 #endif
120 	if (error)
121 		errx(EX_OSERR, "SMB filesystem is not available");
122 
123 	if (smb_lib_init() != 0)
124 		exit(1);
125 
126 	mntflags = error = 0;
127 
128 	caseopt = SMB_CS_NONE;
129 
130 	if (smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE, SMB_ST_DISK) != 0)
131 		exit(1);
132 	if (smb_ctx_readrc(ctx) != 0)
133 		exit(1);
134 	if (smb_rc)
135 		rc_close(smb_rc);
136 
137 	while ((opt = getopt(argc, argv, STDPARAM_OPT"c:d:f:g:l:n:o:u:w:")) != -1) {
138 		switch (opt) {
139 		    case STDPARAM_ARGS:
140 			error = smb_ctx_opt(ctx, opt, optarg);
141 			if (error)
142 				exit(1);
143 			break;
144 		    case 'u': {
145 			struct passwd *pwd;
146 
147 			pwd = isdigit(optarg[0]) ?
148 			    getpwuid(atoi(optarg)) : getpwnam(optarg);
149 			if (pwd == NULL)
150 				errx(EX_NOUSER, "unknown user '%s'", optarg);
151 			uid = pwd->pw_uid;
152 			break;
153 		    }
154 		    case 'g': {
155 			struct group *grp;
156 
157 			grp = isdigit(optarg[0]) ?
158 			    getgrgid(atoi(optarg)) : getgrnam(optarg);
159 			if (grp == NULL)
160 				errx(EX_NOUSER, "unknown group '%s'", optarg);
161 			gid = grp->gr_gid;
162 			break;
163 		    }
164 		    case 'd':
165 			errno = 0;
166 			dir_mode = strtol(optarg, &next, 8);
167 			if (errno || *next != 0)
168 				errx(EX_DATAERR, "invalid value for directory mode");
169 			break;
170 		    case 'f':
171 			errno = 0;
172 			file_mode = strtol(optarg, &next, 8);
173 			if (errno || *next != 0)
174 				errx(EX_DATAERR, "invalid value for file mode");
175 			break;
176 		    case '?':
177 			usage();
178 			/*NOTREACHED*/
179 		    case 'n': {
180 			char *inp, *nsp;
181 
182 			nsp = inp = optarg;
183 			while ((nsp = strsep(&inp, ",;:")) != NULL) {
184 				if (strcasecmp(nsp, "LONG") == 0) {
185 					build_iovec(&iov, &iovlen,
186 					    "nolong", NULL, 0);
187 				} else {
188 					errx(EX_DATAERR,
189 					    "unknown suboption '%s'", nsp);
190 				}
191 			}
192 			break;
193 		    };
194 		    case 'o':
195 			getmntopts(optarg, mopts, &mntflags, 0);
196 			p = strchr(optarg, '=');
197 			val = NULL;
198 			if (p != NULL) {
199 				*p = '\0';
200 				val = p + 1;
201 			}
202 			build_iovec(&iov, &iovlen, optarg, val, (size_t)-1);
203 			break;
204 		    case 'c':
205 			switch (optarg[0]) {
206 			    case 'l':
207 				caseopt |= SMB_CS_LOWER;
208 				break;
209 			    case 'u':
210 				caseopt |= SMB_CS_UPPER;
211 				break;
212 			    default:
213 		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
214 				    optarg[0]);
215 			}
216 			break;
217 		    default:
218 			usage();
219 		}
220 	}
221 
222 	if (optind == argc - 2)
223 		optind++;
224 
225 	if (optind != argc - 1)
226 		usage();
227 	realpath(argv[optind], mount_point);
228 
229 	if (stat(mount_point, &st) == -1)
230 		err(EX_OSERR, "could not find mount point %s", mount_point);
231 	if (!S_ISDIR(st.st_mode)) {
232 		errno = ENOTDIR;
233 		err(EX_OSERR, "can't mount on %s", mount_point);
234 	}
235 /*
236 	if (smb_getextattr(mount_point, &einfo) == 0)
237 		errx(EX_OSERR, "can't mount on %s twice", mount_point);
238 */
239 	if (uid == (uid_t)-1)
240 		uid = st.st_uid;
241 	if (gid == (gid_t)-1)
242 		gid = st.st_gid;
243 	if (file_mode == 0 )
244 		file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
245 	if (dir_mode == 0) {
246 		dir_mode = file_mode;
247 		if (dir_mode & S_IRUSR)
248 			dir_mode |= S_IXUSR;
249 		if (dir_mode & S_IRGRP)
250 			dir_mode |= S_IXGRP;
251 		if (dir_mode & S_IROTH)
252 			dir_mode |= S_IXOTH;
253 	}
254 	/*
255 	 * For now, let connection be private for this mount
256 	 */
257 	ctx->ct_ssn.ioc_opt |= SMBVOPT_PRIVATE;
258 	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = 0; /* root */
259 	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = gid;
260 	opt = 0;
261 	if (dir_mode & S_IXGRP)
262 		opt |= SMBM_EXECGRP;
263 	if (dir_mode & S_IXOTH)
264 		opt |= SMBM_EXECOTH;
265 	ctx->ct_ssn.ioc_rights |= opt;
266 	ctx->ct_sh.ioc_rights |= opt;
267 	error = smb_ctx_resolve(ctx);
268 	if (error)
269 		exit(1);
270 	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
271 	if (error) {
272 		exit(1);
273 	}
274 
275 	fd = ctx->ct_fd;
276 
277 	build_iovec(&iov, &iovlen, "fstype", strdup("smbfs"), -1);
278 	build_iovec(&iov, &iovlen, "fspath", mount_point, -1);
279 	build_iovec_argf(&iov, &iovlen, "fd", "%d", fd);
280 	build_iovec(&iov, &iovlen, "mountpoint", mount_point, -1);
281 	build_iovec_argf(&iov, &iovlen, "uid", "%d", uid);
282 	build_iovec_argf(&iov, &iovlen, "gid", "%d", gid);
283 	build_iovec_argf(&iov, &iovlen, "file_mode", "%d", file_mode);
284 	build_iovec_argf(&iov, &iovlen, "dir_mode", "%d", dir_mode);
285 	build_iovec_argf(&iov, &iovlen, "caseopt", "%d", caseopt);
286 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof errmsg);
287 
288 	error = nmount(iov, iovlen, mntflags);
289 	smb_ctx_done(ctx);
290 	if (error) {
291 		smb_error("mount error: %s %s", error, mount_point, errmsg);
292 		exit(1);
293 	}
294 	return 0;
295 }
296 
297 static void
usage(void)298 usage(void)
299 {
300 	fprintf(stderr, "%s\n%s\n%s\n%s\n",
301 	"usage: mount_smbfs [-E cs1:cs2] [-I host] [-L locale] [-M crights:srights]",
302 	"                   [-N] [-O cowner:cgroup/sowner:sgroup] [-R retrycount]",
303 	"                   [-T timeout] [-W workgroup] [-c case] [-d mode] [-f mode]",
304 	"                   [-g gid] [-n opt] [-u uid] [-U username] //user@server/share node");
305 
306 	exit (1);
307 }
308