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