xref: /386bsd/usr/src/sbin/mountd/mountd.c (revision a2142627)
1 /*
2  * Copyright (c) 1989 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  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
40  All rights reserved.\n";
41 #endif not lint
42 
43 #ifndef lint
44 static char sccsid[] = "@(#)mountd.c	5.14 (Berkeley) 2/26/91";
45 #endif not lint
46 
47 #include <sys/param.h>
48 #include <sys/ioctl.h>
49 #include <sys/stat.h>
50 #include <sys/file.h>
51 #include <sys/mount.h>
52 #include <sys/socket.h>
53 #include <sys/errno.h>
54 #include <sys/signal.h>
55 #include <stdio.h>
56 #include <string.h>
57 #include <syslog.h>
58 #include <netdb.h>
59 #include <rpc/rpc.h>
60 #include <rpc/pmap_clnt.h>
61 #include <rpc/pmap_prot.h>
62 #include <nfs/rpcv2.h>
63 #include <nfs/nfsv2.h>
64 #include "pathnames.h"
65 
66 struct ufid {
67 	u_short	ufid_len;
68 	ino_t	ufid_ino;
69 	long	ufid_gen;
70 };
71 /*
72  * Structures for keeping the mount list and export list
73  */
74 struct mountlist {
75 	struct mountlist *ml_next;
76 	char	ml_host[RPCMNT_NAMELEN+1];
77 	char	ml_dirp[RPCMNT_PATHLEN+1];
78 };
79 
80 struct exportlist {
81 	struct exportlist *ex_next;
82 	struct exportlist *ex_prev;
83 	struct grouplist *ex_groups;
84 	int	ex_rootuid;
85 	int	ex_exflags;
86 	dev_t	ex_dev;
87 	char	ex_dirp[RPCMNT_PATHLEN+1];
88 };
89 
90 struct grouplist {
91 	struct grouplist *gr_next;
92 	struct hostent *gr_hp;
93 };
94 
95 /* Global defs */
96 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
97 void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
98 void send_umntall();
99 struct exportlist exphead;
100 struct mountlist *mlhead;
101 char exname[MAXPATHLEN];
102 int def_rootuid = -2;
103 int root_only = 1;
104 extern int errno;
105 #ifdef DEBUG
106 int debug = 1;
107 #else
108 int debug = 0;
109 #endif
110 
111 /*
112  * Mountd server for NFS mount protocol as described in:
113  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
114  * The optional arguments are the exports file name
115  * default: _PATH_EXPORTS
116  * and "-n" to allow nonroot mount.
117  */
main(argc,argv)118 main(argc, argv)
119 	int argc;
120 	char **argv;
121 {
122 	SVCXPRT *transp;
123 	int c;
124 	extern int optind;
125 	extern char *optarg;
126 
127 	while ((c = getopt(argc, argv, "n")) != EOF)
128 		switch (c) {
129 		case 'n':
130 			root_only = 0;
131 			break;
132 		default:
133 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
134 			exit(1);
135 		};
136 	argc -= optind;
137 	argv += optind;
138 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
139 	mlhead = (struct mountlist *)0;
140 	if (argc == 1) {
141 		strncpy(exname, *argv, MAXPATHLEN-1);
142 		exname[MAXPATHLEN-1] = '\0';
143 	} else
144 		strcpy(exname, _PATH_EXPORTS);
145 	openlog("mountd:", LOG_PID, LOG_DAEMON);
146 	get_exportlist();
147 	get_mountlist();
148 	if (debug == 0) {
149 		daemon(0, 0);
150 		signal(SIGINT, SIG_IGN);
151 		signal(SIGQUIT, SIG_IGN);
152 	}
153 	signal(SIGHUP, get_exportlist);
154 	signal(SIGTERM, send_umntall);
155 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
156 	  if (pidfile != NULL) {
157 		fprintf(pidfile, "%d\n", getpid());
158 		fclose(pidfile);
159 	  }
160 	}
161 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
162 		syslog(LOG_ERR, "Can't create socket");
163 		exit(1);
164 	}
165 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
166 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) {
167 		syslog(LOG_ERR, "Can't register mount");
168 		exit(1);
169 	}
170 	svc_run();
171 	syslog(LOG_ERR, "Mountd died");
172 	exit(1);
173 }
174 
175 /*
176  * The mount rpc service
177  */
mntsrv(rqstp,transp)178 mntsrv(rqstp, transp)
179 	register struct svc_req *rqstp;
180 	register SVCXPRT *transp;
181 {
182 	register struct grouplist *grp;
183 	register u_long **addrp;
184 	register struct exportlist *ep;
185 	nfsv2fh_t nfh;
186 	struct authunix_parms *ucr;
187 	struct stat stb;
188 	struct hostent *hp;
189 	u_long saddr;
190 	char dirpath[RPCMNT_PATHLEN+1];
191 	int bad = ENOENT;
192 	int omask;
193 	uid_t uid = -2;
194 
195 	/* Get authorization */
196 	switch (rqstp->rq_cred.oa_flavor) {
197 	case AUTH_UNIX:
198 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
199 		uid = ucr->aup_uid;
200 		break;
201 	case AUTH_NULL:
202 	default:
203 		break;
204 	}
205 
206 	saddr = transp->xp_raddr.sin_addr.s_addr;
207 	hp = (struct hostent *)0;
208 	switch (rqstp->rq_proc) {
209 	case NULLPROC:
210 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
211 			syslog(LOG_ERR, "Can't send reply");
212 		return;
213 	case RPCMNT_MOUNT:
214 		if (uid != 0 && root_only) {
215 			svcerr_weakauth(transp);
216 			return;
217 		}
218 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
219 			svcerr_decode(transp);
220 			return;
221 		}
222 
223 		/* Check to see if it's a valid dirpath */
224 		if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
225 			S_IFDIR) {
226 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
227 				syslog(LOG_ERR, "Can't send reply");
228 			return;
229 		}
230 
231 		/* Check in the exports list */
232 		omask = sigblock(sigmask(SIGHUP));
233 		ep = exphead.ex_next;
234 		while (ep != NULL) {
235 			if (!strcmp(ep->ex_dirp, dirpath)) {
236 				grp = ep->ex_groups;
237 				if (grp == NULL)
238 					break;
239 
240 				/* Check for a host match */
241 				addrp = (u_long **)grp->gr_hp->h_addr_list;
242 				for (;;) {
243 					if (**addrp == saddr)
244 						break;
245 					if (*++addrp == NULL)
246 						if (grp = grp->gr_next) {
247 							addrp = (u_long **)
248 								grp->gr_hp->h_addr_list;
249 						} else {
250 							bad = EACCES;
251 							if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
252 								syslog(LOG_ERR, "Can't send reply");
253 							sigsetmask(omask);
254 							return;
255 						}
256 				}
257 				hp = grp->gr_hp;
258 				break;
259 			}
260 			ep = ep->ex_next;
261 		}
262 		sigsetmask(omask);
263 		if (ep == NULL) {
264 			bad = EACCES;
265 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
266 				syslog(LOG_ERR, "Can't send reply");
267 			return;
268 		}
269 
270 		/* Get the file handle */
271 		bzero((caddr_t)&nfh, sizeof(nfh));
272 		if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
273 			bad = errno;
274 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
275 				syslog(LOG_ERR, "Can't send reply");
276 			return;
277 		}
278 		if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
279 			syslog(LOG_ERR, "Can't send reply");
280 		if (hp == NULL)
281 			hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
282 		if (hp)
283 			add_mlist(hp->h_name, dirpath);
284 		return;
285 	case RPCMNT_DUMP:
286 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
287 			syslog(LOG_ERR, "Can't send reply");
288 		return;
289 	case RPCMNT_UMOUNT:
290 		if (uid != 0 && root_only) {
291 			svcerr_weakauth(transp);
292 			return;
293 		}
294 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
295 			svcerr_decode(transp);
296 			return;
297 		}
298 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
299 			syslog(LOG_ERR, "Can't send reply");
300 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
301 		if (hp)
302 			del_mlist(hp->h_name, dirpath);
303 		return;
304 	case RPCMNT_UMNTALL:
305 		if (uid != 0 && root_only) {
306 			svcerr_weakauth(transp);
307 			return;
308 		}
309 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
310 			syslog(LOG_ERR, "Can't send reply");
311 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
312 		if (hp)
313 			del_mlist(hp->h_name, (char *)0);
314 		return;
315 	case RPCMNT_EXPORT:
316 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
317 			syslog(LOG_ERR, "Can't send reply");
318 		return;
319 	default:
320 		svcerr_noproc(transp);
321 		return;
322 	}
323 }
324 
325 /*
326  * Xdr conversion for a dirpath string
327  */
xdr_dir(xdrsp,dirp)328 xdr_dir(xdrsp, dirp)
329 	XDR *xdrsp;
330 	char *dirp;
331 {
332 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
333 }
334 
335 /*
336  * Xdr routine to generate fhstatus
337  */
xdr_fhs(xdrsp,nfh)338 xdr_fhs(xdrsp, nfh)
339 	XDR *xdrsp;
340 	nfsv2fh_t *nfh;
341 {
342 	int ok = 0;
343 
344 	if (!xdr_long(xdrsp, &ok))
345 		return (0);
346 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
347 }
348 
xdr_mlist(xdrsp,cp)349 xdr_mlist(xdrsp, cp)
350 	XDR *xdrsp;
351 	caddr_t cp;
352 {
353 	register struct mountlist *mlp;
354 	int true = 1;
355 	int false = 0;
356 	char *strp;
357 
358 	mlp = mlhead;
359 	while (mlp) {
360 		if (!xdr_bool(xdrsp, &true))
361 			return (0);
362 		strp = &mlp->ml_host[0];
363 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
364 			return (0);
365 		strp = &mlp->ml_dirp[0];
366 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
367 			return (0);
368 		mlp = mlp->ml_next;
369 	}
370 	if (!xdr_bool(xdrsp, &false))
371 		return (0);
372 	return (1);
373 }
374 
375 /*
376  * Xdr conversion for export list
377  */
xdr_explist(xdrsp,cp)378 xdr_explist(xdrsp, cp)
379 	XDR *xdrsp;
380 	caddr_t cp;
381 {
382 	register struct exportlist *ep;
383 	register struct grouplist *grp;
384 	int true = 1;
385 	int false = 0;
386 	char *strp;
387 	int omask;
388 
389 	omask = sigblock(sigmask(SIGHUP));
390 	ep = exphead.ex_next;
391 	while (ep != NULL) {
392 		if (!xdr_bool(xdrsp, &true))
393 			goto errout;
394 		strp = &ep->ex_dirp[0];
395 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
396 			goto errout;
397 		grp = ep->ex_groups;
398 		while (grp != NULL) {
399 			if (!xdr_bool(xdrsp, &true))
400 				goto errout;
401 			strp = grp->gr_hp->h_name;
402 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
403 				goto errout;
404 			grp = grp->gr_next;
405 		}
406 		if (!xdr_bool(xdrsp, &false))
407 			goto errout;
408 		ep = ep->ex_next;
409 	}
410 	sigsetmask(omask);
411 	if (!xdr_bool(xdrsp, &false))
412 		return (0);
413 	return (1);
414 errout:
415 	sigsetmask(omask);
416 	return (0);
417 }
418 
419 #define LINESIZ	10240
420 char line[LINESIZ];
421 
422 /*
423  * Get the export list
424  */
425 void
get_exportlist()426 get_exportlist()
427 {
428 	register struct hostent *hp, *nhp;
429 	register char **addrp, **naddrp;
430 	register int i;
431 	register struct grouplist *grp;
432 	register struct exportlist *ep, *ep2;
433 	struct statfs stfsbuf;
434 	struct ufs_args args;
435 	struct stat sb;
436 	FILE *inf;
437 	char *cp, *endcp;
438 	char savedc;
439 	int len, dirplen;
440 	int rootuid, exflags;
441 	u_long saddr;
442 	struct exportlist *fep;
443 
444 	/*
445 	 * First, get rid of the old list
446 	 */
447 	ep = exphead.ex_next;
448 	while (ep != NULL) {
449 		ep2 = ep;
450 		ep = ep->ex_next;
451 		free_exp(ep2);
452 	}
453 
454 	/*
455 	 * Read in the exports file and build the list, calling
456 	 * exportfs() as we go along
457 	 */
458 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
459 	if ((inf = fopen(exname, "r")) == NULL) {
460 		syslog(LOG_ERR, "Can't open %s", exname);
461 		exit(2);
462 	}
463 	while (fgets(line, LINESIZ, inf)) {
464 		exflags = MNT_EXPORTED;
465 		rootuid = def_rootuid;
466 		cp = line;
467 		nextfield(&cp, &endcp);
468 
469 		/*
470 		 * Get file system devno and see if an entry for this
471 		 * file system already exists.
472 		 */
473 		savedc = *endcp;
474 		*endcp = '\0';
475 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
476 			syslog(LOG_ERR,
477 			    "Bad Exports File, %s: %s, mountd Failed",
478 			    cp, "Not a directory");
479 			exit(2);
480 		}
481 		fep = (struct exportlist *)0;
482 		ep = exphead.ex_next;
483 		while (ep) {
484 			if (ep->ex_dev == sb.st_dev) {
485 				fep = ep;
486 				break;
487 			}
488 			ep = ep->ex_next;
489 		}
490 		*endcp = savedc;
491 
492 		/*
493 		 * Create new exports list entry
494 		 */
495 		len = endcp-cp;
496 		if (len <= RPCMNT_PATHLEN && len > 0) {
497 			ep = (struct exportlist *)malloc(sizeof(*ep));
498 			if (ep == NULL)
499 				goto err;
500 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
501 			ep->ex_groups = (struct grouplist *)0;
502 			bcopy(cp, ep->ex_dirp, len);
503 			ep->ex_dirp[len] = '\0';
504 			dirplen = len;
505 		} else {
506 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
507 			exit(2);
508 		}
509 		cp = endcp;
510 		nextfield(&cp, &endcp);
511 		len = endcp-cp;
512 		while (len > 0) {
513 			savedc = *endcp;
514 			*endcp = '\0';
515 			if (len > RPCMNT_NAMELEN)
516 				goto more;
517 			if (*cp == '-') {
518 				do_opt(cp + 1, fep, ep, &exflags, &rootuid);
519 				goto more;
520 			}
521 			if (isdigit(*cp)) {
522 				saddr = inet_addr(cp);
523 				if (saddr == -1 ||
524 				    (hp = gethostbyaddr((caddr_t)&saddr,
525 				     sizeof(saddr), AF_INET)) == NULL) {
526 					syslog(LOG_ERR,
527 					    "Bad Exports File, %s: %s", cp,
528 					    "Gethostbyaddr failed, ignored");
529 					goto more;
530 				}
531 			} else if ((hp = gethostbyname(cp)) == NULL) {
532 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
533 				    cp, "Gethostbyname failed, ignored");
534 				goto more;
535 			}
536 			grp = (struct grouplist *)
537 				malloc(sizeof(struct grouplist));
538 			if (grp == NULL)
539 				goto err;
540 			nhp = grp->gr_hp = (struct hostent *)
541 				malloc(sizeof(struct hostent));
542 			if (nhp == NULL)
543 				goto err;
544 			bcopy((caddr_t)hp, (caddr_t)nhp,
545 				sizeof(struct hostent));
546 			i = strlen(hp->h_name)+1;
547 			nhp->h_name = (char *)malloc(i);
548 			if (nhp->h_name == NULL)
549 				goto err;
550 			bcopy(hp->h_name, nhp->h_name, i);
551 			addrp = hp->h_addr_list;
552 			i = 1;
553 			while (*addrp++)
554 				i++;
555 			naddrp = nhp->h_addr_list = (char **)
556 				malloc(i*sizeof(char *));
557 			if (naddrp == NULL)
558 				goto err;
559 			addrp = hp->h_addr_list;
560 			while (*addrp) {
561 				*naddrp = (char *)
562 				    malloc(hp->h_length);
563 				if (*naddrp == NULL)
564 				    goto err;
565 				bcopy(*addrp, *naddrp,
566 					hp->h_length);
567 				addrp++;
568 				naddrp++;
569 			}
570 			*naddrp = (char *)0;
571 			grp->gr_next = ep->ex_groups;
572 			ep->ex_groups = grp;
573 		more:
574 			cp = endcp;
575 			*cp = savedc;
576 			nextfield(&cp, &endcp);
577 			len = endcp - cp;
578 		}
579 		if (fep == NULL) {
580 			args.fspec = 0;
581 			args.exflags = exflags;
582 			args.exroot = rootuid;
583 			cp = (char *)0;
584 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
585 			       mount(MOUNT_UFS, ep->ex_dirp,
586 				     stfsbuf.f_flags|MNT_UPDATE, &args) < 0) {
587 
588 				if (cp)
589 					*cp-- = savedc;
590 				else
591 					cp = ep->ex_dirp + dirplen - 1;
592 
593 				/* back up over the last component */
594 				while (*cp == '/' && cp > ep->ex_dirp)
595 					cp--;
596 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
597 					cp--;
598 				if (cp == ep->ex_dirp) {
599 					syslog(LOG_WARNING,
600 					      "Can't export %s", ep->ex_dirp);
601 					free_exp(ep);
602 					goto nextline;
603 				}
604 				savedc = *cp;
605 				*cp = '\0';
606 			}
607 			if (cp)
608 				*cp = savedc;
609 			ep->ex_rootuid = rootuid;
610 			ep->ex_exflags = exflags;
611 		} else {
612 			ep->ex_rootuid = fep->ex_rootuid;
613 			ep->ex_exflags = fep->ex_exflags;
614 		}
615 		ep->ex_dev = sb.st_dev;
616 		ep->ex_next = exphead.ex_next;
617 		ep->ex_prev = &exphead;
618 		if (ep->ex_next != NULL)
619 			ep->ex_next->ex_prev = ep;
620 		exphead.ex_next = ep;
621 nextline:
622 		;
623 	}
624 	fclose(inf);
625 	return;
626 err:
627 	syslog(LOG_ERR, "No more memory: mountd Failed");
628 	exit(2);
629 }
630 
631 /*
632  * Parse out the next white space separated field
633  */
nextfield(cp,endcp)634 nextfield(cp, endcp)
635 	char **cp;
636 	char **endcp;
637 {
638 	register char *p;
639 
640 	p = *cp;
641 	while (*p == ' ' || *p == '\t')
642 		p++;
643 	if (*p == '\n' || *p == '\0') {
644 		*cp = *endcp = p;
645 		return;
646 	}
647 	*cp = p++;
648 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
649 		p++;
650 	*endcp = p;
651 }
652 
653 /*
654  * Parse the option string
655  */
do_opt(cpopt,fep,ep,exflagsp,rootuidp)656 do_opt(cpopt, fep, ep, exflagsp, rootuidp)
657 	register char *cpopt;
658 	struct exportlist *fep, *ep;
659 	int *exflagsp, *rootuidp;
660 {
661 	register char *cpoptarg, *cpoptend;
662 
663 	while (cpopt && *cpopt) {
664 		if (cpoptend = index(cpopt, ','))
665 			*cpoptend++ = '\0';
666 		if (cpoptarg = index(cpopt, '='))
667 			*cpoptarg++ = '\0';
668 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
669 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
670 				syslog(LOG_WARNING, "ro failed for %s",
671 				       ep->ex_dirp);
672 			else
673 				*exflagsp |= MNT_EXRDONLY;
674 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
675 			if (cpoptarg && isdigit(*cpoptarg)) {
676 				*rootuidp = atoi(cpoptarg);
677 				if (fep && fep->ex_rootuid != *rootuidp)
678 					syslog(LOG_WARNING,
679 					       "uid failed for %s",
680 					       ep->ex_dirp);
681 			} else
682 				syslog(LOG_WARNING,
683 				       "uid failed for %s",
684 				       ep->ex_dirp);
685 		} else
686 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
687 			       ep->ex_dirp);
688 		cpopt = cpoptend;
689 	}
690 }
691 
692 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
693 /*
694  * Routines that maintain the remote mounttab
695  */
get_mountlist()696 void get_mountlist()
697 {
698 	register struct mountlist *mlp, **mlpp;
699 	register char *eos, *dirp;
700 	int len;
701 	char str[STRSIZ];
702 	FILE *mlfile;
703 
704 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
705 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
706 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
707 		return;
708 	}
709 	mlpp = &mlhead;
710 	while (fgets(str, STRSIZ, mlfile) != NULL) {
711 		if ((dirp = index(str, '\t')) == NULL &&
712 		    (dirp = index(str, ' ')) == NULL)
713 			continue;
714 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
715 		len = dirp-str;
716 		if (len > RPCMNT_NAMELEN)
717 			len = RPCMNT_NAMELEN;
718 		bcopy(str, mlp->ml_host, len);
719 		mlp->ml_host[len] = '\0';
720 		while (*dirp == '\t' || *dirp == ' ')
721 			dirp++;
722 		if ((eos = index(dirp, '\t')) == NULL &&
723 		    (eos = index(dirp, ' ')) == NULL &&
724 		    (eos = index(dirp, '\n')) == NULL)
725 			len = strlen(dirp);
726 		else
727 			len = eos-dirp;
728 		if (len > RPCMNT_PATHLEN)
729 			len = RPCMNT_PATHLEN;
730 		bcopy(dirp, mlp->ml_dirp, len);
731 		mlp->ml_dirp[len] = '\0';
732 		mlp->ml_next = (struct mountlist *)0;
733 		*mlpp = mlp;
734 		mlpp = &mlp->ml_next;
735 	}
736 	fclose(mlfile);
737 }
738 
del_mlist(hostp,dirp)739 void del_mlist(hostp, dirp)
740 	register char *hostp, *dirp;
741 {
742 	register struct mountlist *mlp, **mlpp;
743 	FILE *mlfile;
744 	int fnd = 0;
745 
746 	mlpp = &mlhead;
747 	mlp = mlhead;
748 	while (mlp) {
749 		if (!strcmp(mlp->ml_host, hostp) &&
750 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
751 			fnd = 1;
752 			*mlpp = mlp->ml_next;
753 			free((caddr_t)mlp);
754 		}
755 		mlpp = &mlp->ml_next;
756 		mlp = mlp->ml_next;
757 	}
758 	if (fnd) {
759 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
760 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
761 			return;
762 		}
763 		mlp = mlhead;
764 		while (mlp) {
765 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
766 			mlp = mlp->ml_next;
767 		}
768 		fclose(mlfile);
769 	}
770 }
771 
add_mlist(hostp,dirp)772 void add_mlist(hostp, dirp)
773 	register char *hostp, *dirp;
774 {
775 	register struct mountlist *mlp, **mlpp;
776 	FILE *mlfile;
777 
778 	mlpp = &mlhead;
779 	mlp = mlhead;
780 	while (mlp) {
781 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
782 			return;
783 		mlpp = &mlp->ml_next;
784 		mlp = mlp->ml_next;
785 	}
786 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
787 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
788 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
789 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
790 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
791 	mlp->ml_next = (struct mountlist *)0;
792 	*mlpp = mlp;
793 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
794 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
795 		return;
796 	}
797 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
798 	fclose(mlfile);
799 }
800 
801 /*
802  * This function is called via. SIGTERM when the system is going down.
803  * It sends a broadcast RPCMNT_UMNTALL.
804  */
805 void
send_umntall()806 send_umntall()
807 {
808 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
809 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
810 	exit();
811 }
812 
umntall_each(resultsp,raddr)813 umntall_each(resultsp, raddr)
814 	caddr_t resultsp;
815 	struct sockaddr_in *raddr;
816 {
817 	return (1);
818 }
819 
820 /*
821  * Free up an exports list component
822  */
free_exp(ep)823 free_exp(ep)
824 	register struct exportlist *ep;
825 {
826 	register struct grouplist *grp;
827 	register char **addrp;
828 	struct grouplist *grp2;
829 
830 	grp = ep->ex_groups;
831 	while (grp != NULL) {
832 		addrp = grp->gr_hp->h_addr_list;
833 		while (*addrp)
834 			free(*addrp++);
835 		free((caddr_t)grp->gr_hp->h_addr_list);
836 		free(grp->gr_hp->h_name);
837 		free((caddr_t)grp->gr_hp);
838 		grp2 = grp;
839 		grp = grp->gr_next;
840 		free((caddr_t)grp2);
841 	}
842 	free((caddr_t)ep);
843 }
844