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