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