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