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