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