1 /*
2  * Copyright (c) 1999, 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  * $FreeBSD: stable/9/usr.sbin/mount_nwfs/mount_nwfs.c 204710 2010-03-04 16:07:14Z uqs $
33  */
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/errno.h>
37 #include <sys/mount.h>
38 #include <sys/sysctl.h>
39 #include <machine/cpu.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 <time.h>
51 
52 #include <netncp/ncp_lib.h>
53 #include <netncp/ncp_rcfile.h>
54 #include <fs/nwfs/nwfs_mount.h>
55 #include "mntopts.h"
56 
57 #define	NWFS_VFSNAME	"nwfs"
58 
59 static char mount_point[MAXPATHLEN + 1];
60 static void usage(void);
61 static int parsercfile(struct ncp_conn_loginfo *li, struct nwfs_args *mdata);
62 
63 static struct mntopt mopts[] = {
64 	MOPT_STDOPTS,
65 	MOPT_END
66 };
67 
68 static int
parsercfile(struct ncp_conn_loginfo * li __unused,struct nwfs_args * mdata __unused)69 parsercfile(struct ncp_conn_loginfo *li __unused,
70     struct nwfs_args *mdata __unused)
71 {
72 	return 0;
73 }
74 
75 int
main(int argc,char * argv[])76 main(int argc, char *argv[])
77 {
78 	NWCONN_HANDLE connHandle;
79 	struct nwfs_args mdata;
80 	struct ncp_conn_loginfo li;
81 	struct stat st;
82 	struct nw_entry_info einfo;
83 	struct tm *tm;
84 	time_t ltime;
85 	int opt, error, mntflags, nlsopt, wall_clock;
86 	int uid_set, gid_set;
87 	size_t len;
88 	char *p, *p1, tmp[1024];
89 	u_char *pv;
90 
91 	if (argc < 2)
92 		usage();
93 	if (argc == 2) {
94 		if (strcmp(argv[1], "-h") == 0) {
95 			usage();
96 		} else if (strcmp(argv[1], "-v") == 0) {
97 			errx(EX_OK, "version %d.%d.%d", NWFS_VERSION / 100000,
98 			    (NWFS_VERSION % 10000) / 1000,
99 			    (NWFS_VERSION % 1000) / 100);
100 		}
101 	}
102 
103 	if(ncp_initlib()) exit(1);
104 
105 	mntflags = error = 0;
106 	bzero(&mdata,sizeof(mdata));
107 	gid_set = uid_set = 0;
108 	nlsopt = 0;
109 
110 	if (ncp_li_init(&li, argc, argv)) return 1;
111 	/*
112 	 * A little bit weird, but I should figure out which server/user to use
113 	 * _before_ reading .rc file
114 	 */
115 	if (argc >= 3 && argv[argc-1][0] != '-' && argv[argc-2][0] != '-' &&
116 	    argv[argc-2][0] == '/') {
117 		p = argv[argc-2];
118 		error = 1;
119 		do {
120 			if (*p++ != '/') break;
121 			p1 = tmp;
122 			while (*p != ':' && *p != 0) *p1++ = *p++;
123 			if (*p++ == 0) break;
124 			*p1 = 0;
125 			if (ncp_li_setserver(&li, tmp)) break;
126 			p1 = tmp;
127 			while (*p != '/' && *p != 0) *p1++ = *p++;
128 			if (*p++ == 0) break;
129 			*p1 = 0;
130 			if (ncp_li_setuser(&li, tmp)) break;
131 			p1 = tmp;
132 			while (*p != '/' && *p != 0) *p1++ = *p++;
133 			*p1 = 0;
134 			if (strlen(tmp) > NCP_VOLNAME_LEN) {
135 				warnx("volume name too long: %s", tmp);
136 				break;
137 			}
138 			ncp_str_upper(strcpy(mdata.mounted_vol,tmp));
139 			if (*p == '/')
140 				p++;
141 			p1 = mdata.root_path + 2;
142 			pv = mdata.root_path + 1;
143 			for(;*p;) {
144 				*pv = 0;
145 				while (*p != '/' && *p) {
146 					*p1++ = *p++;
147 					(*pv)++;
148 				}
149 				if (*pv) {
150 					ncp_nls_mem_u2n(pv + 1, pv + 1, *pv);
151 					pv += (*pv) + 1;
152 					mdata.root_path[0]++;
153 				}
154 				if (*p++ == 0) break;
155 				p1++;
156 			}
157 			error = 0;
158 		} while(0);
159 		if (error)
160 			errx(EX_DATAERR,
161 			    "an error occurred while parsing '%s'",
162 			    argv[argc - 2]);
163 	}
164 	if (ncp_li_readrc(&li)) return 1;
165 	if (ncp_rc) {
166 		parsercfile(&li,&mdata);
167 		rc_close(ncp_rc);
168 	}
169 	while ((opt = getopt(argc, argv, STDPARAM_OPT"V:c:d:f:g:l:n:o:u:w:")) != -1) {
170 		switch (opt) {
171 		    case STDPARAM_ARGS:
172 			if (ncp_li_arg(&li, opt, optarg)) {
173 				return 1;
174 			}
175 			break;
176 		    case 'V':
177 			if (strlen(optarg) > NCP_VOLNAME_LEN)
178 				errx(EX_DATAERR, "volume too long: %s", optarg);
179 			ncp_str_upper(strcpy(mdata.mounted_vol,optarg));
180 			break;
181 		    case 'u': {
182 			struct passwd *pwd;
183 
184 			pwd = isdigit(optarg[0]) ?
185 			    getpwuid(atoi(optarg)) : getpwnam(optarg);
186 			if (pwd == NULL)
187 				errx(EX_NOUSER, "unknown user '%s'", optarg);
188 			mdata.uid = pwd->pw_uid;
189 			uid_set = 1;
190 			break;
191 		    }
192 		    case 'g': {
193 			struct group *grp;
194 
195 			grp = isdigit(optarg[0]) ?
196 			    getgrgid(atoi(optarg)) : getgrnam(optarg);
197 			if (grp == NULL)
198 				errx(EX_NOUSER, "unknown group '%s'", optarg);
199 			mdata.gid = grp->gr_gid;
200 			gid_set = 1;
201 			break;
202 		    }
203 		    case 'd':
204 			errno = 0;
205 			mdata.dir_mode = strtol(optarg, &p, 8);
206 			if (errno || *p != 0)
207 				errx(EX_DATAERR, "invalid value for directory mode");
208 			break;
209 		    case 'f':
210 			errno = 0;
211 			mdata.file_mode = strtol(optarg, &p, 8);
212 			if (errno || *p != 0)
213 				errx(EX_DATAERR, "invalid value for file mode");
214 			break;
215 		    case '?':
216 			usage();
217 			/*NOTREACHED*/
218 		    case 'n': {
219 			char *inp, *nsp;
220 
221 			nsp = inp = optarg;
222 			while ((nsp = strsep(&inp, ",;:")) != NULL) {
223 				if (strcasecmp(nsp, "OS2") == 0)
224 					mdata.flags |= NWFS_MOUNT_NO_OS2;
225 				else if (strcasecmp(nsp, "LONG") == 0)
226 					mdata.flags |= NWFS_MOUNT_NO_LONG;
227 				else if (strcasecmp(nsp, "NFS") == 0)
228 					mdata.flags |= NWFS_MOUNT_NO_NFS;
229 				else
230 					errx(EX_DATAERR, "unknown namespace '%s'", nsp);
231 			}
232 			break;
233 		    };
234 		    case 'l':
235 			if (ncp_nls_setlocale(optarg) != 0) return 1;
236 			mdata.flags |= NWFS_MOUNT_HAVE_NLS;
237 			break;
238 		    case 'o':
239 			getmntopts(optarg, mopts, &mntflags, 0);
240 			break;
241 		    case 'c':
242 			switch (optarg[0]) {
243 			    case 'l':
244 				nlsopt |= NWHP_LOWER;
245 				break;
246 			    case 'u':
247 				nlsopt |= NWHP_UPPER;
248 				break;
249 			    case 'n':
250 				nlsopt |= NWHP_LOWER | NWHP_UPPER;
251 				break;
252 			    case 'L':
253 				nlsopt |= NWHP_LOWER | NWHP_NOSTRICT;
254 				break;
255 			    case 'U':
256 				nlsopt |= NWHP_UPPER | NWHP_NOSTRICT;
257 				break;
258 			    default:
259 		    		errx(EX_DATAERR, "invalid suboption '%c' for -c",
260 				    optarg[0]);
261 			}
262 			break;
263 		    case 'w':
264 			if (ncp_nls_setrecodebyname(optarg) != 0)
265 				return 1;
266 			mdata.flags |= NWFS_MOUNT_HAVE_NLS;
267 			break;
268 		    default:
269 			usage();
270 		}
271 	}
272 
273 	if (optind == argc - 2) {
274 		optind++;
275 	} else if (mdata.mounted_vol[0] == 0)
276 		errx(EX_USAGE, "volume name should be specified");
277 
278 	if (optind != argc - 1)
279 		usage();
280 	realpath(argv[optind], mount_point);
281 
282 	if (stat(mount_point, &st) == -1)
283 		err(EX_OSERR, "could not find mount point %s", mount_point);
284 	if (!S_ISDIR(st.st_mode)) {
285 		errno = ENOTDIR;
286 		err(EX_OSERR, "can't mount on %s", mount_point);
287 	}
288 	if (ncp_geteinfo(mount_point, &einfo) == 0)
289 		errx(EX_OSERR, "can't mount on %s twice", mount_point);
290 
291 	if (uid_set == 0) {
292 		mdata.uid = st.st_uid;
293 	}
294 	if (gid_set == 0) {
295 		mdata.gid = st.st_gid;
296 	}
297 	if (mdata.file_mode == 0 ) {
298 		mdata.file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
299 	}
300 	if (mdata.dir_mode == 0) {
301 		mdata.dir_mode = mdata.file_mode;
302 		if ((mdata.dir_mode & S_IRUSR) != 0)
303 			mdata.dir_mode |= S_IXUSR;
304 		if ((mdata.dir_mode & S_IRGRP) != 0)
305 			mdata.dir_mode |= S_IXGRP;
306 		if ((mdata.dir_mode & S_IROTH) != 0)
307 			mdata.dir_mode |= S_IXOTH;
308 	}
309 	if (li.access_mode == 0) {
310 		li.access_mode = mdata.dir_mode;
311 	}
312 /*	if (mdata.flags & NWFS_MOUNT_HAVE_NLS) {*/
313 		mdata.nls = ncp_nls;
314 /*	}*/
315 	mdata.nls.opt = nlsopt;
316 
317 	len = sizeof(wall_clock);
318 	if (sysctlbyname("machdep.wall_cmos_clock", &wall_clock, &len, NULL, 0) == -1)
319 		err(EX_OSERR, "get wall_clock");
320 	if (wall_clock == 0) {
321 		time(&ltime);
322 		tm = localtime(&ltime);
323 		mdata.tz = -(tm->tm_gmtoff / 60);
324 	}
325 
326 	error = ncp_li_check(&li);
327 	if (error)
328 		return 1;
329 	li.opt |= NCP_OPT_WDOG;
330 	/* well, now we can try to login, or use already established connection */
331 	error = ncp_li_login(&li, &connHandle);
332 	if (error) {
333 		ncp_error("cannot login to server %s", error, li.server);
334 		exit(1);
335 	}
336 	error = ncp_conn2ref(connHandle, &mdata.connRef);
337 	if (error) {
338 		ncp_error("could not convert handle to reference", error);
339 		ncp_disconnect(connHandle);
340 		exit(1);
341 	}
342 	strcpy(mdata.mount_point,mount_point);
343 	mdata.version = NWFS_VERSION;
344 	error = mount(NWFS_VFSNAME, mdata.mount_point, mntflags, (void*)&mdata);
345 	if (error) {
346 		ncp_error("mount error: %s", error, mdata.mount_point);
347 		ncp_disconnect(connHandle);
348 		exit(1);
349 	}
350 	/*
351 	 * I'm leave along my handle, but kernel should keep own ...
352 	 */
353 	ncp_disconnect(connHandle);
354 	/* we are done ?, impossible ... */
355 	return 0;
356 }
357 
358 static void
usage(void)359 usage(void)
360 {
361 	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
362 	"usage: mount_nwfs [-Chv] -S server -U user [-connection options]",
363 	"                  -V volume [-M mode] [-c case] [-d mode] [-f mode]",
364 	"                  [-g gid] [-l locale] [-n os2] [-u uid] [-w scheme]",
365 	"                  node",
366 	"       mount_nwfs [-options] /server:user/volume[/path] node");
367 
368 	exit (1);
369 }
370