xref: /original-bsd/sbin/mount_nfs/mount_nfs.c (revision 0997b878)
1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 static char copyright[] =
13 "@(#) Copyright (c) 1992, 1993, 1994\n\
14 	The Regents of the University of California.  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)mount_nfs.c	8.6 (Berkeley) 01/07/95";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/mount.h>
23 #include <sys/socket.h>
24 #include <sys/socketvar.h>
25 #include <sys/stat.h>
26 #include <sys/syslog.h>
27 
28 #include <rpc/rpc.h>
29 #include <rpc/pmap_clnt.h>
30 #include <rpc/pmap_prot.h>
31 
32 #ifdef ISO
33 #include <netiso/iso.h>
34 #endif
35 
36 #ifdef KERBEROS
37 #include <kerberosIV/des.h>
38 #include <kerberosIV/krb.h>
39 #endif
40 
41 #include <nfs/rpcv2.h>
42 #include <nfs/nfsv2.h>
43 #define KERNEL
44 #include <nfs/nfs.h>
45 #undef KERNEL
46 #include <nfs/nqnfs.h>
47 
48 #include <arpa/inet.h>
49 
50 #include <ctype.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <netdb.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <strings.h>
59 #include <unistd.h>
60 
61 #include "mntopts.h"
62 
63 struct mntopt mopts[] = {
64 	MOPT_STDOPTS,
65 	MOPT_FORCE,
66 	MOPT_UPDATE,
67 	{ NULL }
68 };
69 
70 struct nfs_args nfsdefargs = {
71 	(struct sockaddr *)0,
72 	sizeof (struct sockaddr_in),
73 	SOCK_DGRAM,
74 	0,
75 	(nfsv2fh_t *)0,
76 	0,
77 	NFS_WSIZE,
78 	NFS_RSIZE,
79 	NFS_TIMEO,
80 	NFS_RETRANS,
81 	NFS_MAXGRPS,
82 	NFS_DEFRAHEAD,
83 	NQ_DEFLEASE,
84 	NQ_DEADTHRESH,
85 	(char *)0,
86 };
87 
88 struct nfhret {
89 	u_long	stat;
90 	nfsv2fh_t nfh;
91 };
92 #define	DEF_RETRY	10000
93 #define	BGRND	1
94 #define	ISBGRND	2
95 int retrycnt = DEF_RETRY;
96 int opflags = 0;
97 
98 #ifdef KERBEROS
99 char inst[INST_SZ];
100 char realm[REALM_SZ];
101 KTEXT_ST kt;
102 #endif
103 
104 int	getnfsargs __P((char *, struct nfs_args *));
105 #ifdef ISO
106 struct	iso_addr *iso_addr __P((const char *));
107 #endif
108 void	set_rpc_maxgrouplist __P((int));
109 __dead	void usage __P((void));
110 int	xdr_dir __P((XDR *, char *));
111 int	xdr_fh __P((XDR *, struct nfhret *));
112 
113 int
114 main(argc, argv)
115 	int argc;
116 	char *argv[];
117 {
118 	register int c;
119 	register struct nfs_args *nfsargsp;
120 	struct nfs_args nfsargs;
121 	struct nfsd_cargs ncd;
122 	int mntflags, i, nfssvc_flag, num;
123 	char *name, *p, *spec;
124 	int error = 0;
125 #ifdef KERBEROS
126 	uid_t last_ruid;
127 #endif
128 
129 #ifdef KERBEROS
130 	last_ruid = -1;
131 	(void)strcpy(realm, KRB_REALM);
132 #endif
133 	retrycnt = DEF_RETRY;
134 
135 	mntflags = 0;
136 	nfsargs = nfsdefargs;
137 	nfsargsp = &nfsargs;
138 	while ((c = getopt(argc, argv,
139 	    "a:bcdD:g:iKklL:Mm:o:PpqR:r:sTt:w:x:")) != EOF)
140 		switch (c) {
141 		case 'a':
142 			num = strtol(optarg, &p, 10);
143 			if (*p || num < 0)
144 				errx(1, "illegal -a value -- %s", optarg);
145 			nfsargsp->readahead = num;
146 			nfsargsp->flags |= NFSMNT_READAHEAD;
147 			break;
148 		case 'b':
149 			opflags |= BGRND;
150 			break;
151 		case 'c':
152 			nfsargsp->flags |= NFSMNT_NOCONN;
153 			break;
154 		case 'D':
155 			num = strtol(optarg, &p, 10);
156 			if (*p || num <= 0)
157 				errx(1, "illegal -D value -- %s", optarg);
158 			nfsargsp->deadthresh = num;
159 			nfsargsp->flags |= NFSMNT_DEADTHRESH;
160 			break;
161 		case 'd':
162 			nfsargsp->flags |= NFSMNT_DUMBTIMR;
163 			break;
164 		case 'g':
165 			num = strtol(optarg, &p, 10);
166 			if (*p || num <= 0)
167 				errx(1, "illegal -g value -- %s", optarg);
168 			set_rpc_maxgrouplist(num);
169 			nfsargsp->maxgrouplist = num;
170 			nfsargsp->flags |= NFSMNT_MAXGRPS;
171 			break;
172 		case 'i':
173 			nfsargsp->flags |= NFSMNT_INT;
174 			break;
175 #ifdef KERBEROS
176 		case 'K':
177 			nfsargsp->flags |= NFSMNT_KERB;
178 			break;
179 #endif
180 		case 'k':
181 			nfsargsp->flags |= NFSMNT_NQLOOKLEASE;
182 			break;
183 		case 'L':
184 			num = strtol(optarg, &p, 10);
185 			if (*p || num < 2)
186 				errx(1, "illegal -L value -- %s", optarg);
187 			nfsargsp->leaseterm = num;
188 			nfsargsp->flags |= NFSMNT_LEASETERM;
189 			break;
190 		case 'l':
191 			nfsargsp->flags |= NFSMNT_RDIRALOOK;
192 			break;
193 		case 'M':
194 			nfsargsp->flags |= NFSMNT_MYWRITE;
195 			break;
196 #ifdef KERBEROS
197 		case 'm':
198 			(void)strncpy(realm, optarg, REALM_SZ - 1);
199 			realm[REALM_SZ - 1] = '\0';
200 			break;
201 #endif
202 		case 'o':
203 			getmntopts(optarg, mopts, &mntflags);
204 			break;
205 		case 'P':
206 			nfsargsp->flags |= NFSMNT_RESVPORT;
207 			break;
208 #ifdef ISO
209 		case 'p':
210 			nfsargsp->sotype = SOCK_SEQPACKET;
211 			break;
212 #endif
213 		case 'q':
214 			nfsargsp->flags |= NFSMNT_NQNFS;
215 			break;
216 		case 'R':
217 			num = strtol(optarg, &p, 10);
218 			if (*p || num <= 0)
219 				errx(1, "illegal -R value -- %s", optarg);
220 			retrycnt = num;
221 			break;
222 		case 'r':
223 			num = strtol(optarg, &p, 10);
224 			if (*p || num <= 0)
225 				errx(1, "illegal -r value -- %s", optarg);
226 			nfsargsp->rsize = num;
227 			nfsargsp->flags |= NFSMNT_RSIZE;
228 			break;
229 		case 's':
230 			nfsargsp->flags |= NFSMNT_SOFT;
231 			break;
232 		case 'T':
233 			nfsargsp->sotype = SOCK_STREAM;
234 			break;
235 		case 't':
236 			num = strtol(optarg, &p, 10);
237 			if (*p || num <= 0)
238 				errx(1, "illegal -t value -- %s", optarg);
239 			nfsargsp->timeo = num;
240 			nfsargsp->flags |= NFSMNT_TIMEO;
241 			break;
242 		case 'w':
243 			num = strtol(optarg, &p, 10);
244 			if (*p || num <= 0)
245 				errx(1, "illegal -w value -- %s", optarg);
246 			nfsargsp->wsize = num;
247 			nfsargsp->flags |= NFSMNT_WSIZE;
248 			break;
249 		case 'x':
250 			num = strtol(optarg, &p, 10);
251 			if (*p || num <= 0)
252 				errx(1, "illegal -x value -- %s", optarg);
253 			nfsargsp->retrans = num;
254 			nfsargsp->flags |= NFSMNT_RETRANS;
255 			break;
256 		default:
257 			usage();
258 			break;
259 		}
260 	argc -= optind;
261 	argv += optind;
262 
263 	if (argc != 2)
264 		usage();
265 
266 	spec = *argv++;
267 	name = *argv;
268 
269 	if (!getnfsargs(spec, nfsargsp))
270 		exit(1);
271 	if (mount(MOUNT_NFS, name, mntflags, nfsargsp))
272 		err(1, "%s", name);
273 	if (nfsargsp->flags & (NFSMNT_NQNFS | NFSMNT_KERB)) {
274 		if ((opflags & ISBGRND) == 0) {
275 			if (i = fork()) {
276 				if (i == -1)
277 					err(1, "nqnfs 1");
278 				exit(0);
279 			}
280 			(void) setsid();
281 			(void) close(STDIN_FILENO);
282 			(void) close(STDOUT_FILENO);
283 			(void) close(STDERR_FILENO);
284 			(void) chdir("/");
285 		}
286 		openlog("mount_nfs:", LOG_PID, LOG_DAEMON);
287 		nfssvc_flag = NFSSVC_MNTD;
288 		ncd.ncd_dirp = name;
289 		while (nfssvc(nfssvc_flag, (caddr_t)&ncd) < 0) {
290 			if (errno != ENEEDAUTH) {
291 				syslog(LOG_ERR, "nfssvc err %m");
292 				continue;
293 			}
294 			nfssvc_flag =
295 			    NFSSVC_MNTD | NFSSVC_GOTAUTH | NFSSVC_AUTHINFAIL;
296 #ifdef KERBEROS
297 			/*
298 			 * Set up as ncd_authuid for the kerberos call.
299 			 * Must set ruid to ncd_authuid and reset the
300 			 * ticket name iff ncd_authuid is not the same
301 			 * as last time, so that the right ticket file
302 			 * is found.
303 			 */
304 			if (ncd.ncd_authuid != last_ruid) {
305 				krb_set_tkt_string("");
306 				last_ruid = ncd.ncd_authuid;
307 			}
308 			setreuid(ncd.ncd_authuid, 0);
309 			if (krb_mk_req(&kt, "rcmd", inst, realm, 0) ==
310 			    KSUCCESS &&
311 			    kt.length <= (RPCAUTH_MAXSIZ - 2 * NFSX_UNSIGNED)) {
312 				ncd.ncd_authtype = RPCAUTH_NQNFS;
313 				ncd.ncd_authlen = kt.length;
314 				ncd.ncd_authstr = (char *)kt.dat;
315 				nfssvc_flag = NFSSVC_MNTD | NFSSVC_GOTAUTH;
316 			}
317 			setreuid(0, 0);
318 #endif /* KERBEROS */
319 		}
320 	}
321 	exit(0);
322 }
323 
324 int
325 getnfsargs(spec, nfsargsp)
326 	char *spec;
327 	struct nfs_args *nfsargsp;
328 {
329 	register CLIENT *clp;
330 	struct hostent *hp;
331 	static struct sockaddr_in saddr;
332 #ifdef ISO
333 	static struct sockaddr_iso isoaddr;
334 	struct iso_addr *isop;
335 	int isoflag = 0;
336 #endif
337 	struct timeval pertry, try;
338 	enum clnt_stat clnt_stat;
339 	int so = RPC_ANYSOCK, i;
340 	char *hostp, *delimp;
341 #ifdef KERBEROS
342 	char *cp;
343 #endif
344 	u_short tport;
345 	static struct nfhret nfhret;
346 	static char nam[MNAMELEN + 1];
347 
348 	strncpy(nam, spec, MNAMELEN);
349 	nam[MNAMELEN] = '\0';
350 	if ((delimp = strchr(spec, '@')) != NULL) {
351 		hostp = delimp + 1;
352 	} else if ((delimp = strchr(spec, ':')) != NULL) {
353 		hostp = spec;
354 		spec = delimp + 1;
355 	} else {
356 		warnx("no <host>:<dirpath> or <dirpath>@<host> spec");
357 		return (0);
358 	}
359 	*delimp = '\0';
360 	/*
361 	 * DUMB!! Until the mount protocol works on iso transport, we must
362 	 * supply both an iso and an inet address for the host.
363 	 */
364 #ifdef ISO
365 	if (!strncmp(hostp, "iso=", 4)) {
366 		u_short isoport;
367 
368 		hostp += 4;
369 		isoflag++;
370 		if ((delimp = strchr(hostp, '+')) == NULL) {
371 			warnx("no iso+inet address");
372 			return (0);
373 		}
374 		*delimp = '\0';
375 		if ((isop = iso_addr(hostp)) == NULL) {
376 			warnx("bad ISO address");
377 			return (0);
378 		}
379 		bzero((caddr_t)&isoaddr, sizeof (isoaddr));
380 		bcopy((caddr_t)isop, (caddr_t)&isoaddr.siso_addr,
381 			sizeof (struct iso_addr));
382 		isoaddr.siso_len = sizeof (isoaddr);
383 		isoaddr.siso_family = AF_ISO;
384 		isoaddr.siso_tlen = 2;
385 		isoport = htons(NFS_PORT);
386 		bcopy((caddr_t)&isoport, TSEL(&isoaddr), isoaddr.siso_tlen);
387 		hostp = delimp + 1;
388 	}
389 #endif /* ISO */
390 
391 	/*
392 	 * Handle an internet host address and reverse resolve it if
393 	 * doing Kerberos.
394 	 */
395 	if (isdigit(*hostp)) {
396 		if ((saddr.sin_addr.s_addr = inet_addr(hostp)) == -1) {
397 			warnx("bad net address %s", hostp);
398 			return (0);
399 		}
400 		if ((nfsargsp->flags & NFSMNT_KERB) &&
401 		    (hp = gethostbyaddr((char *)&saddr.sin_addr.s_addr,
402 		    sizeof (u_long), AF_INET)) == (struct hostent *)0) {
403 			warnx("can't reverse resolve net address");
404 			return (0);
405 		}
406 	} else if ((hp = gethostbyname(hostp)) == NULL) {
407 		warnx("can't get net id for host");
408 		return (0);
409 	}
410 #ifdef KERBEROS
411 	if (nfsargsp->flags & NFSMNT_KERB) {
412 		strncpy(inst, hp->h_name, INST_SZ);
413 		inst[INST_SZ - 1] = '\0';
414 		if (cp = strchr(inst, '.'))
415 			*cp = '\0';
416 	}
417 #endif /* KERBEROS */
418 
419 	bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
420 	nfhret.stat = EACCES;	/* Mark not yet successful */
421 	while (retrycnt > 0) {
422 		saddr.sin_family = AF_INET;
423 		saddr.sin_port = htons(PMAPPORT);
424 		if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
425 		    NFS_VER2, nfsargsp->sotype == SOCK_STREAM ? IPPROTO_TCP :
426 		    IPPROTO_UDP)) == 0) {
427 			if ((opflags & ISBGRND) == 0)
428 				clnt_pcreateerror("NFS Portmap");
429 		} else {
430 			saddr.sin_port = 0;
431 			pertry.tv_sec = 10;
432 			pertry.tv_usec = 0;
433 			if ((clp = (nfsargsp->sotype == SOCK_STREAM ?
434 			    clnttcp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
435 					   &so, 0, 0) :
436 			    clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
437 					   pertry, &so))) == NULL) {
438 				if ((opflags & ISBGRND) == 0)
439 					clnt_pcreateerror("Cannot MNT PRC");
440 			} else {
441 				clp->cl_auth = authunix_create_default();
442 				try.tv_sec = 10;
443 				try.tv_usec = 0;
444 				clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
445 				    xdr_dir, spec, xdr_fh, &nfhret, try);
446 				if (clnt_stat != RPC_SUCCESS) {
447 					if ((opflags & ISBGRND) == 0)
448 						warnx("%s", clnt_sperror(clp,
449 						    "bad MNT RPC"));
450 				} else {
451 					auth_destroy(clp->cl_auth);
452 					clnt_destroy(clp);
453 					retrycnt = 0;
454 				}
455 			}
456 		}
457 		if (--retrycnt > 0) {
458 			if (opflags & BGRND) {
459 				opflags &= ~BGRND;
460 				if (i = fork()) {
461 					if (i == -1)
462 						err(1, "nqnfs 2");
463 					exit(0);
464 				}
465 				(void) setsid();
466 				(void) close(STDIN_FILENO);
467 				(void) close(STDOUT_FILENO);
468 				(void) close(STDERR_FILENO);
469 				(void) chdir("/");
470 				opflags |= ISBGRND;
471 			}
472 			sleep(60);
473 		}
474 	}
475 	if (nfhret.stat) {
476 		if (opflags & ISBGRND)
477 			exit(1);
478 		errno = nfhret.stat;
479 		warn("can't access %s", spec);
480 		return (0);
481 	}
482 	saddr.sin_port = htons(tport);
483 #ifdef ISO
484 	if (isoflag) {
485 		nfsargsp->addr = (struct sockaddr *) &isoaddr;
486 		nfsargsp->addrlen = sizeof (isoaddr);
487 	} else
488 #endif /* ISO */
489 	{
490 		nfsargsp->addr = (struct sockaddr *) &saddr;
491 		nfsargsp->addrlen = sizeof (saddr);
492 	}
493 	nfsargsp->fh = &nfhret.nfh;
494 	nfsargsp->hostname = nam;
495 	return (1);
496 }
497 
498 /*
499  * xdr routines for mount rpc's
500  */
501 int
502 xdr_dir(xdrsp, dirp)
503 	XDR *xdrsp;
504 	char *dirp;
505 {
506 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
507 }
508 
509 int
510 xdr_fh(xdrsp, np)
511 	XDR *xdrsp;
512 	struct nfhret *np;
513 {
514 	if (!xdr_u_long(xdrsp, &(np->stat)))
515 		return (0);
516 	if (np->stat)
517 		return (1);
518 	return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
519 }
520 
521 __dead void
522 usage()
523 {
524 	(void)fprintf(stderr, "usage: mount_nfs %s\n%s\n%s\n%s\n",
525 "[-bcdiKklMPqsT] [-a maxreadahead] [-D deadthresh]",
526 "\t[-g maxgroups] [-L leaseterm] [-m realm] [-o options] [-R retrycnt]",
527 "\t[-r readsize] [-t timeout] [-w writesize] [-x retrans]",
528 "\trhost:path node");
529 	exit(1);
530 }
531