xref: /csrg-svn/sbin/mountd/mountd.c (revision 68645)
1 /*
2  * Copyright (c) 1989, 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  * Herb Hasler and 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) 1989, 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[] = "@(#)mountd.c	8.12 (Berkeley) 03/29/95";
19 #endif not lint
20 
21 #include <sys/param.h>
22 #include <sys/file.h>
23 #include <sys/ioctl.h>
24 #include <sys/mount.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/syslog.h>
28 #include <sys/ucred.h>
29 
30 #include <rpc/rpc.h>
31 #include <rpc/pmap_clnt.h>
32 #include <rpc/pmap_prot.h>
33 #ifdef ISO
34 #include <netiso/iso.h>
35 #endif
36 #include <nfs/rpcv2.h>
37 #include <nfs/nfsproto.h>
38 #include <ufs/ufs/ufsmount.h>
39 #include <sys/../isofs/cd9660/cd9660_mount.h>	/* XXX need isofs in include */
40 
41 #include <arpa/inet.h>
42 
43 #include <ctype.h>
44 #include <errno.h>
45 #include <grp.h>
46 #include <netdb.h>
47 #include <pwd.h>
48 #include <signal.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 #include "pathnames.h"
54 
55 #ifdef DEBUG
56 #include <stdarg.h>
57 #endif
58 
59 /*
60  * Structures for keeping the mount list and export list
61  */
62 struct mountlist {
63 	struct mountlist *ml_next;
64 	char	ml_host[RPCMNT_NAMELEN+1];
65 	char	ml_dirp[RPCMNT_PATHLEN+1];
66 };
67 
68 struct dirlist {
69 	struct dirlist	*dp_left;
70 	struct dirlist	*dp_right;
71 	int		dp_flag;
72 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
73 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
74 };
75 /* dp_flag bits */
76 #define	DP_DEFSET	0x1
77 #define DP_HOSTSET	0x2
78 #define DP_KERB		0x4
79 
80 struct exportlist {
81 	struct exportlist *ex_next;
82 	struct dirlist	*ex_dirl;
83 	struct dirlist	*ex_defdir;
84 	int		ex_flag;
85 	fsid_t		ex_fs;
86 	char		*ex_fsdir;
87 };
88 /* ex_flag bits */
89 #define	EX_LINKED	0x1
90 
91 struct netmsk {
92 	u_long	nt_net;
93 	u_long	nt_mask;
94 	char *nt_name;
95 };
96 
97 union grouptypes {
98 	struct hostent *gt_hostent;
99 	struct netmsk	gt_net;
100 #ifdef ISO
101 	struct sockaddr_iso *gt_isoaddr;
102 #endif
103 };
104 
105 struct grouplist {
106 	int gr_type;
107 	union grouptypes gr_ptr;
108 	struct grouplist *gr_next;
109 };
110 /* Group types */
111 #define	GT_NULL		0x0
112 #define	GT_HOST		0x1
113 #define	GT_NET		0x2
114 #define	GT_ISO		0x4
115 
116 struct hostlist {
117 	int		 ht_flag;	/* Uses DP_xx bits */
118 	struct grouplist *ht_grp;
119 	struct hostlist	 *ht_next;
120 };
121 
122 struct fhreturn {
123 	int	fhr_flag;
124 	int	fhr_vers;
125 	nfsfh_t	fhr_fh;
126 };
127 
128 /* Global defs */
129 char	*add_expdir __P((struct dirlist **, char *, int));
130 void	add_dlist __P((struct dirlist **, struct dirlist *,
131 				struct grouplist *, int));
132 void	add_mlist __P((char *, char *));
133 int	check_dirpath __P((char *));
134 int	check_options __P((struct dirlist *));
135 int	chk_host __P((struct dirlist *, u_long, int *, int *));
136 void	del_mlist __P((char *, char *));
137 struct dirlist *dirp_search __P((struct dirlist *, char *));
138 int	do_mount __P((struct exportlist *, struct grouplist *, int,
139 		struct ucred *, char *, int, struct statfs *));
140 int	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
141 				int *, int *, struct ucred *));
142 struct	exportlist *ex_search __P((fsid_t *));
143 struct	exportlist *get_exp __P((void));
144 void	free_dir __P((struct dirlist *));
145 void	free_exp __P((struct exportlist *));
146 void	free_grp __P((struct grouplist *));
147 void	free_host __P((struct hostlist *));
148 void	get_exportlist __P((void));
149 int	get_host __P((char *, struct grouplist *));
150 int	get_num __P((char *));
151 struct hostlist *get_ht __P((void));
152 int	get_line __P((void));
153 void	get_mountlist __P((void));
154 int	get_net __P((char *, struct netmsk *, int));
155 void	getexp_err __P((struct exportlist *, struct grouplist *));
156 struct grouplist *get_grp __P((void));
157 void	hang_dirp __P((struct dirlist *, struct grouplist *,
158 				struct exportlist *, int));
159 void	mntsrv __P((struct svc_req *, SVCXPRT *));
160 void	nextfield __P((char **, char **));
161 void	out_of_mem __P((void));
162 void	parsecred __P((char *, struct ucred *));
163 int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
164 int	scan_tree __P((struct dirlist *, u_long));
165 void	send_umntall __P((void));
166 int	umntall_each __P((caddr_t, struct sockaddr_in *));
167 int	xdr_dir __P((XDR *, char *));
168 int	xdr_explist __P((XDR *, caddr_t));
169 int	xdr_fhs __P((XDR *, caddr_t));
170 int	xdr_mlist __P((XDR *, caddr_t));
171 
172 /* C library */
173 int	getnetgrent();
174 void	endnetgrent();
175 void	setnetgrent();
176 
177 #ifdef ISO
178 struct iso_addr *iso_addr();
179 #endif
180 
181 struct exportlist *exphead;
182 struct mountlist *mlhead;
183 struct grouplist *grphead;
184 char exname[MAXPATHLEN];
185 struct ucred def_anon = {
186 	1,
187 	(uid_t) -2,
188 	1,
189 	{ (gid_t) -2 }
190 };
191 int resvport_only = 1;
192 int dir_only = 1;
193 int opt_flags;
194 /* Bits for above */
195 #define	OP_MAPROOT	0x01
196 #define	OP_MAPALL	0x02
197 #define	OP_KERB		0x04
198 #define	OP_MASK		0x08
199 #define	OP_NET		0x10
200 #define	OP_ISO		0x20
201 #define	OP_ALLDIRS	0x40
202 
203 #ifdef DEBUG
204 int debug = 1;
205 void	SYSLOG __P((int, const char *, ...));
206 #define syslog SYSLOG
207 #else
208 int debug = 0;
209 #endif
210 
211 /*
212  * Mountd server for NFS mount protocol as described in:
213  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
214  * The optional arguments are the exports file name
215  * default: _PATH_EXPORTS
216  * and "-n" to allow nonroot mount.
217  */
218 int
219 main(argc, argv)
220 	int argc;
221 	char **argv;
222 {
223 	SVCXPRT *udptransp, *tcptransp;
224 	int c;
225 
226 	while ((c = getopt(argc, argv, "ntr")) != EOF)
227 		switch (c) {
228 		case 'n':
229 			resvport_only = 0;
230 			break;
231 		case 'r':
232 			dir_only = 0;
233 			break;
234 		default:
235 			fprintf(stderr, "Usage: mountd [-r] [-n] [export_file]\n");
236 			exit(1);
237 		};
238 	argc -= optind;
239 	argv += optind;
240 	grphead = (struct grouplist *)NULL;
241 	exphead = (struct exportlist *)NULL;
242 	mlhead = (struct mountlist *)NULL;
243 	if (argc == 1) {
244 		strncpy(exname, *argv, MAXPATHLEN-1);
245 		exname[MAXPATHLEN-1] = '\0';
246 	} else
247 		strcpy(exname, _PATH_EXPORTS);
248 	openlog("mountd", LOG_PID, LOG_DAEMON);
249 	if (debug)
250 		fprintf(stderr,"Getting export list.\n");
251 	get_exportlist();
252 	if (debug)
253 		fprintf(stderr,"Getting mount list.\n");
254 	get_mountlist();
255 	if (debug)
256 		fprintf(stderr,"Here we go.\n");
257 	if (debug == 0) {
258 		daemon(0, 0);
259 		signal(SIGINT, SIG_IGN);
260 		signal(SIGQUIT, SIG_IGN);
261 	}
262 	signal(SIGHUP, (void (*) __P((int))) get_exportlist);
263 	signal(SIGTERM, (void (*) __P((int))) send_umntall);
264 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
265 	  if (pidfile != NULL) {
266 		fprintf(pidfile, "%d\n", getpid());
267 		fclose(pidfile);
268 	  }
269 	}
270 	if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||
271 	    (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {
272 		syslog(LOG_ERR, "Can't create socket");
273 		exit(1);
274 	}
275 	pmap_unset(RPCPROG_MNT, 1);
276 	pmap_unset(RPCPROG_MNT, 3);
277 	if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
278 	    !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
279 	    !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) ||
280 	    !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
281 		syslog(LOG_ERR, "Can't register mount");
282 		exit(1);
283 	}
284 	svc_run();
285 	syslog(LOG_ERR, "Mountd died");
286 	exit(1);
287 }
288 
289 /*
290  * The mount rpc service
291  */
292 void
293 mntsrv(rqstp, transp)
294 	struct svc_req *rqstp;
295 	SVCXPRT *transp;
296 {
297 	struct exportlist *ep;
298 	struct dirlist *dp;
299 	struct fhreturn fhr;
300 	struct stat stb;
301 	struct statfs fsb;
302 	struct hostent *hp;
303 	u_long saddr;
304 	u_short sport;
305 	char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
306 	int bad = ENOENT, omask, defset, hostset;
307 
308 	saddr = transp->xp_raddr.sin_addr.s_addr;
309 	sport = ntohs(transp->xp_raddr.sin_port);
310 	hp = (struct hostent *)NULL;
311 	switch (rqstp->rq_proc) {
312 	case NULLPROC:
313 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
314 			syslog(LOG_ERR, "Can't send reply");
315 		return;
316 	case RPCMNT_MOUNT:
317 		if (sport >= IPPORT_RESERVED && resvport_only) {
318 			svcerr_weakauth(transp);
319 			return;
320 		}
321 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
322 			svcerr_decode(transp);
323 			return;
324 		}
325 
326 		/*
327 		 * Get the real pathname and make sure it is a directory
328 		 * or a regular file if the -r option was specified
329 		 * and it exists.
330 		 */
331 		if (realpath(rpcpath, dirpath) == 0 ||
332 		    stat(dirpath, &stb) < 0 ||
333 		    (!S_ISDIR(stb.st_mode) &&
334 		     (dir_only || !S_ISREG(stb.st_mode))) ||
335 		    statfs(dirpath, &fsb) < 0) {
336 			chdir("/");	/* Just in case realpath doesn't */
337 			if (debug)
338 				fprintf(stderr, "stat failed on %s\n", dirpath);
339 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
340 				syslog(LOG_ERR, "Can't send reply");
341 			return;
342 		}
343 
344 		/* Check in the exports list */
345 		omask = sigblock(sigmask(SIGHUP));
346 		ep = ex_search(&fsb.f_fsid);
347 		hostset = defset = 0;
348 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
349 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
350 		     chk_host(dp, saddr, &defset, &hostset)) ||
351 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
352 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
353 			if (hostset & DP_HOSTSET)
354 				fhr.fhr_flag = hostset;
355 			else
356 				fhr.fhr_flag = defset;
357 			fhr.fhr_vers = rqstp->rq_vers;
358 			/* Get the file handle */
359 			bzero((caddr_t)&fhr.fhr_fh, sizeof(nfsfh_t));
360 			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
361 				bad = errno;
362 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
363 				if (!svc_sendreply(transp, xdr_long,
364 				    (caddr_t)&bad))
365 					syslog(LOG_ERR, "Can't send reply");
366 				sigsetmask(omask);
367 				return;
368 			}
369 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
370 				syslog(LOG_ERR, "Can't send reply");
371 			if (hp == NULL)
372 				hp = gethostbyaddr((caddr_t)&saddr,
373 				    sizeof(saddr), AF_INET);
374 			if (hp)
375 				add_mlist(hp->h_name, dirpath);
376 			else
377 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
378 					dirpath);
379 			if (debug)
380 				fprintf(stderr,"Mount successfull.\n");
381 		} else {
382 			bad = EACCES;
383 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
384 				syslog(LOG_ERR, "Can't send reply");
385 		}
386 		sigsetmask(omask);
387 		return;
388 	case RPCMNT_DUMP:
389 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
390 			syslog(LOG_ERR, "Can't send reply");
391 		return;
392 	case RPCMNT_UMOUNT:
393 		if (sport >= IPPORT_RESERVED && resvport_only) {
394 			svcerr_weakauth(transp);
395 			return;
396 		}
397 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
398 			svcerr_decode(transp);
399 			return;
400 		}
401 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
402 			syslog(LOG_ERR, "Can't send reply");
403 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
404 		if (hp)
405 			del_mlist(hp->h_name, dirpath);
406 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
407 		return;
408 	case RPCMNT_UMNTALL:
409 		if (sport >= IPPORT_RESERVED && resvport_only) {
410 			svcerr_weakauth(transp);
411 			return;
412 		}
413 		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
414 			syslog(LOG_ERR, "Can't send reply");
415 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
416 		if (hp)
417 			del_mlist(hp->h_name, (char *)NULL);
418 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
419 		return;
420 	case RPCMNT_EXPORT:
421 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
422 			syslog(LOG_ERR, "Can't send reply");
423 		return;
424 	default:
425 		svcerr_noproc(transp);
426 		return;
427 	}
428 }
429 
430 /*
431  * Xdr conversion for a dirpath string
432  */
433 int
434 xdr_dir(xdrsp, dirp)
435 	XDR *xdrsp;
436 	char *dirp;
437 {
438 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
439 }
440 
441 /*
442  * Xdr routine to generate file handle reply
443  */
444 int
445 xdr_fhs(xdrsp, cp)
446 	XDR *xdrsp;
447 	caddr_t cp;
448 {
449 	register struct fhreturn *fhrp = (struct fhreturn *)cp;
450 	long ok = 0, len, auth;
451 
452 	if (!xdr_long(xdrsp, &ok))
453 		return (0);
454 	switch (fhrp->fhr_vers) {
455 	case 1:
456 		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
457 	case 3:
458 		len = NFSX_V3FH;
459 		if (!xdr_long(xdrsp, &len))
460 			return (0);
461 		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
462 			return (0);
463 		if (fhrp->fhr_flag & DP_KERB)
464 			auth = RPCAUTH_KERB4;
465 		else
466 			auth = RPCAUTH_UNIX;
467 		len = 1;
468 		if (!xdr_long(xdrsp, &len))
469 			return (0);
470 		return (xdr_long(xdrsp, &auth));
471 	};
472 	return (0);
473 }
474 
475 int
476 xdr_mlist(xdrsp, cp)
477 	XDR *xdrsp;
478 	caddr_t cp;
479 {
480 	struct mountlist *mlp;
481 	int true = 1;
482 	int false = 0;
483 	char *strp;
484 
485 	mlp = mlhead;
486 	while (mlp) {
487 		if (!xdr_bool(xdrsp, &true))
488 			return (0);
489 		strp = &mlp->ml_host[0];
490 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
491 			return (0);
492 		strp = &mlp->ml_dirp[0];
493 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
494 			return (0);
495 		mlp = mlp->ml_next;
496 	}
497 	if (!xdr_bool(xdrsp, &false))
498 		return (0);
499 	return (1);
500 }
501 
502 /*
503  * Xdr conversion for export list
504  */
505 int
506 xdr_explist(xdrsp, cp)
507 	XDR *xdrsp;
508 	caddr_t cp;
509 {
510 	struct exportlist *ep;
511 	int false = 0;
512 	int omask, putdef;
513 
514 	omask = sigblock(sigmask(SIGHUP));
515 	ep = exphead;
516 	while (ep) {
517 		putdef = 0;
518 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
519 			goto errout;
520 		if (ep->ex_defdir && putdef == 0 &&
521 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
522 			&putdef))
523 			goto errout;
524 		ep = ep->ex_next;
525 	}
526 	sigsetmask(omask);
527 	if (!xdr_bool(xdrsp, &false))
528 		return (0);
529 	return (1);
530 errout:
531 	sigsetmask(omask);
532 	return (0);
533 }
534 
535 /*
536  * Called from xdr_explist() to traverse the tree and export the
537  * directory paths.
538  */
539 int
540 put_exlist(dp, xdrsp, adp, putdefp)
541 	struct dirlist *dp;
542 	XDR *xdrsp;
543 	struct dirlist *adp;
544 	int *putdefp;
545 {
546 	struct grouplist *grp;
547 	struct hostlist *hp;
548 	int true = 1;
549 	int false = 0;
550 	int gotalldir = 0;
551 	char *strp;
552 
553 	if (dp) {
554 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
555 			return (1);
556 		if (!xdr_bool(xdrsp, &true))
557 			return (1);
558 		strp = dp->dp_dirp;
559 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
560 			return (1);
561 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
562 			gotalldir = 1;
563 			*putdefp = 1;
564 		}
565 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
566 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
567 			hp = dp->dp_hosts;
568 			while (hp) {
569 				grp = hp->ht_grp;
570 				if (grp->gr_type == GT_HOST) {
571 					if (!xdr_bool(xdrsp, &true))
572 						return (1);
573 					strp = grp->gr_ptr.gt_hostent->h_name;
574 					if (!xdr_string(xdrsp, &strp,
575 					    RPCMNT_NAMELEN))
576 						return (1);
577 				} else if (grp->gr_type == GT_NET) {
578 					if (!xdr_bool(xdrsp, &true))
579 						return (1);
580 					strp = grp->gr_ptr.gt_net.nt_name;
581 					if (!xdr_string(xdrsp, &strp,
582 					    RPCMNT_NAMELEN))
583 						return (1);
584 				}
585 				hp = hp->ht_next;
586 				if (gotalldir && hp == (struct hostlist *)NULL) {
587 					hp = adp->dp_hosts;
588 					gotalldir = 0;
589 				}
590 			}
591 		}
592 		if (!xdr_bool(xdrsp, &false))
593 			return (1);
594 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
595 			return (1);
596 	}
597 	return (0);
598 }
599 
600 #define LINESIZ	10240
601 char line[LINESIZ];
602 FILE *exp_file;
603 
604 /*
605  * Get the export list
606  */
607 void
608 get_exportlist()
609 {
610 	struct exportlist *ep, *ep2;
611 	struct grouplist *grp, *tgrp;
612 	struct exportlist **epp;
613 	struct dirlist *dirhead;
614 	struct statfs fsb, *fsp;
615 	struct hostent *hpe;
616 	struct ucred anon;
617 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
618 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
619 
620 	/*
621 	 * First, get rid of the old list
622 	 */
623 	ep = exphead;
624 	while (ep) {
625 		ep2 = ep;
626 		ep = ep->ex_next;
627 		free_exp(ep2);
628 	}
629 	exphead = (struct exportlist *)NULL;
630 
631 	grp = grphead;
632 	while (grp) {
633 		tgrp = grp;
634 		grp = grp->gr_next;
635 		free_grp(tgrp);
636 	}
637 	grphead = (struct grouplist *)NULL;
638 
639 	/*
640 	 * And delete exports that are in the kernel for all local
641 	 * file systems.
642 	 * XXX: Should know how to handle all local exportable file systems
643 	 *      instead of just "ufs".
644 	 */
645 	num = getmntinfo(&fsp, MNT_NOWAIT);
646 	for (i = 0; i < num; i++) {
647 		union {
648 			struct ufs_args ua;
649 			struct iso_args ia;
650 			struct mfs_args ma;
651 		} targs;
652 
653 		if (!strcmp(fsp->f_fstypename, "mfs") ||
654 		    !strcmp(fsp->f_fstypename, "ufs") ||
655 		    !strcmp(fsp->f_fstypename, "cd9660")) {
656 			targs.ua.fspec = NULL;
657 			targs.ua.export.ex_flags = MNT_DELEXPORT;
658 			if (mount(fsp->f_fstypename, fsp->f_mntonname,
659 				  fsp->f_flags | MNT_UPDATE,
660 				  (caddr_t)&targs) < 0)
661 				syslog(LOG_ERR, "Can't delete exports for %s",
662 				       fsp->f_mntonname);
663 		}
664 		fsp++;
665 	}
666 
667 	/*
668 	 * Read in the exports file and build the list, calling
669 	 * mount() as we go along to push the export rules into the kernel.
670 	 */
671 	if ((exp_file = fopen(exname, "r")) == NULL) {
672 		syslog(LOG_ERR, "Can't open %s", exname);
673 		exit(2);
674 	}
675 	dirhead = (struct dirlist *)NULL;
676 	while (get_line()) {
677 		if (debug)
678 			fprintf(stderr,"Got line %s\n",line);
679 		cp = line;
680 		nextfield(&cp, &endcp);
681 		if (*cp == '#')
682 			goto nextline;
683 
684 		/*
685 		 * Set defaults.
686 		 */
687 		has_host = FALSE;
688 		anon = def_anon;
689 		exflags = MNT_EXPORTED;
690 		got_nondir = 0;
691 		opt_flags = 0;
692 		ep = (struct exportlist *)NULL;
693 
694 		/*
695 		 * Create new exports list entry
696 		 */
697 		len = endcp-cp;
698 		tgrp = grp = get_grp();
699 		while (len > 0) {
700 			if (len > RPCMNT_NAMELEN) {
701 			    getexp_err(ep, tgrp);
702 			    goto nextline;
703 			}
704 			if (*cp == '-') {
705 			    if (ep == (struct exportlist *)NULL) {
706 				getexp_err(ep, tgrp);
707 				goto nextline;
708 			    }
709 			    if (debug)
710 				fprintf(stderr, "doing opt %s\n", cp);
711 			    got_nondir = 1;
712 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
713 				&exflags, &anon)) {
714 				getexp_err(ep, tgrp);
715 				goto nextline;
716 			    }
717 			} else if (*cp == '/') {
718 			    savedc = *endcp;
719 			    *endcp = '\0';
720 			    if (check_dirpath(cp) &&
721 				statfs(cp, &fsb) >= 0) {
722 				if (got_nondir) {
723 				    syslog(LOG_ERR, "Dirs must be first");
724 				    getexp_err(ep, tgrp);
725 				    goto nextline;
726 				}
727 				if (ep) {
728 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
729 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
730 					getexp_err(ep, tgrp);
731 					goto nextline;
732 				    }
733 				} else {
734 				    /*
735 				     * See if this directory is already
736 				     * in the list.
737 				     */
738 				    ep = ex_search(&fsb.f_fsid);
739 				    if (ep == (struct exportlist *)NULL) {
740 					ep = get_exp();
741 					ep->ex_fs = fsb.f_fsid;
742 					ep->ex_fsdir = (char *)
743 					    malloc(strlen(fsb.f_mntonname) + 1);
744 					if (ep->ex_fsdir)
745 					    strcpy(ep->ex_fsdir,
746 						fsb.f_mntonname);
747 					else
748 					    out_of_mem();
749 					if (debug)
750 					  fprintf(stderr,
751 					      "Making new ep fs=0x%x,0x%x\n",
752 					      fsb.f_fsid.val[0],
753 					      fsb.f_fsid.val[1]);
754 				    } else if (debug)
755 					fprintf(stderr,
756 					    "Found ep fs=0x%x,0x%x\n",
757 					    fsb.f_fsid.val[0],
758 					    fsb.f_fsid.val[1]);
759 				}
760 
761 				/*
762 				 * Add dirpath to export mount point.
763 				 */
764 				dirp = add_expdir(&dirhead, cp, len);
765 				dirplen = len;
766 			    } else {
767 				getexp_err(ep, tgrp);
768 				goto nextline;
769 			    }
770 			    *endcp = savedc;
771 			} else {
772 			    savedc = *endcp;
773 			    *endcp = '\0';
774 			    got_nondir = 1;
775 			    if (ep == (struct exportlist *)NULL) {
776 				getexp_err(ep, tgrp);
777 				goto nextline;
778 			    }
779 
780 			    /*
781 			     * Get the host or netgroup.
782 			     */
783 			    setnetgrent(cp);
784 			    netgrp = getnetgrent(&hst, &usr, &dom);
785 			    do {
786 				if (has_host) {
787 				    grp->gr_next = get_grp();
788 				    grp = grp->gr_next;
789 				}
790 				if (netgrp) {
791 				    if (get_host(hst, grp)) {
792 					syslog(LOG_ERR, "Bad netgroup %s", cp);
793 					getexp_err(ep, tgrp);
794 					endnetgrent();
795 					goto nextline;
796 				    }
797 				} else if (get_host(cp, grp)) {
798 				    getexp_err(ep, tgrp);
799 				    goto nextline;
800 				}
801 				has_host = TRUE;
802 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
803 			    endnetgrent();
804 			    *endcp = savedc;
805 			}
806 			cp = endcp;
807 			nextfield(&cp, &endcp);
808 			len = endcp - cp;
809 		}
810 		if (check_options(dirhead)) {
811 			getexp_err(ep, tgrp);
812 			goto nextline;
813 		}
814 		if (!has_host) {
815 			grp->gr_type = GT_HOST;
816 			if (debug)
817 				fprintf(stderr,"Adding a default entry\n");
818 			/* add a default group and make the grp list NULL */
819 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
820 			if (hpe == (struct hostent *)NULL)
821 				out_of_mem();
822 			hpe->h_name = "Default";
823 			hpe->h_addrtype = AF_INET;
824 			hpe->h_length = sizeof (u_long);
825 			hpe->h_addr_list = (char **)NULL;
826 			grp->gr_ptr.gt_hostent = hpe;
827 
828 		/*
829 		 * Don't allow a network export coincide with a list of
830 		 * host(s) on the same line.
831 		 */
832 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
833 			getexp_err(ep, tgrp);
834 			goto nextline;
835 		}
836 
837 		/*
838 		 * Loop through hosts, pushing the exports into the kernel.
839 		 * After loop, tgrp points to the start of the list and
840 		 * grp points to the last entry in the list.
841 		 */
842 		grp = tgrp;
843 		do {
844 		    if (do_mount(ep, grp, exflags, &anon, dirp,
845 			dirplen, &fsb)) {
846 			getexp_err(ep, tgrp);
847 			goto nextline;
848 		    }
849 		} while (grp->gr_next && (grp = grp->gr_next));
850 
851 		/*
852 		 * Success. Update the data structures.
853 		 */
854 		if (has_host) {
855 			hang_dirp(dirhead, tgrp, ep, opt_flags);
856 			grp->gr_next = grphead;
857 			grphead = tgrp;
858 		} else {
859 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
860 				opt_flags);
861 			free_grp(grp);
862 		}
863 		dirhead = (struct dirlist *)NULL;
864 		if ((ep->ex_flag & EX_LINKED) == 0) {
865 			ep2 = exphead;
866 			epp = &exphead;
867 
868 			/*
869 			 * Insert in the list in alphabetical order.
870 			 */
871 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
872 				epp = &ep2->ex_next;
873 				ep2 = ep2->ex_next;
874 			}
875 			if (ep2)
876 				ep->ex_next = ep2;
877 			*epp = ep;
878 			ep->ex_flag |= EX_LINKED;
879 		}
880 nextline:
881 		if (dirhead) {
882 			free_dir(dirhead);
883 			dirhead = (struct dirlist *)NULL;
884 		}
885 	}
886 	fclose(exp_file);
887 }
888 
889 /*
890  * Allocate an export list element
891  */
892 struct exportlist *
893 get_exp()
894 {
895 	struct exportlist *ep;
896 
897 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
898 	if (ep == (struct exportlist *)NULL)
899 		out_of_mem();
900 	bzero((caddr_t)ep, sizeof (struct exportlist));
901 	return (ep);
902 }
903 
904 /*
905  * Allocate a group list element
906  */
907 struct grouplist *
908 get_grp()
909 {
910 	struct grouplist *gp;
911 
912 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
913 	if (gp == (struct grouplist *)NULL)
914 		out_of_mem();
915 	bzero((caddr_t)gp, sizeof (struct grouplist));
916 	return (gp);
917 }
918 
919 /*
920  * Clean up upon an error in get_exportlist().
921  */
922 void
923 getexp_err(ep, grp)
924 	struct exportlist *ep;
925 	struct grouplist *grp;
926 {
927 	struct grouplist *tgrp;
928 
929 	syslog(LOG_ERR, "Bad exports list line %s", line);
930 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
931 		free_exp(ep);
932 	while (grp) {
933 		tgrp = grp;
934 		grp = grp->gr_next;
935 		free_grp(tgrp);
936 	}
937 }
938 
939 /*
940  * Search the export list for a matching fs.
941  */
942 struct exportlist *
943 ex_search(fsid)
944 	fsid_t *fsid;
945 {
946 	struct exportlist *ep;
947 
948 	ep = exphead;
949 	while (ep) {
950 		if (ep->ex_fs.val[0] == fsid->val[0] &&
951 		    ep->ex_fs.val[1] == fsid->val[1])
952 			return (ep);
953 		ep = ep->ex_next;
954 	}
955 	return (ep);
956 }
957 
958 /*
959  * Add a directory path to the list.
960  */
961 char *
962 add_expdir(dpp, cp, len)
963 	struct dirlist **dpp;
964 	char *cp;
965 	int len;
966 {
967 	struct dirlist *dp;
968 
969 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
970 	dp->dp_left = *dpp;
971 	dp->dp_right = (struct dirlist *)NULL;
972 	dp->dp_flag = 0;
973 	dp->dp_hosts = (struct hostlist *)NULL;
974 	strcpy(dp->dp_dirp, cp);
975 	*dpp = dp;
976 	return (dp->dp_dirp);
977 }
978 
979 /*
980  * Hang the dir list element off the dirpath binary tree as required
981  * and update the entry for host.
982  */
983 void
984 hang_dirp(dp, grp, ep, flags)
985 	struct dirlist *dp;
986 	struct grouplist *grp;
987 	struct exportlist *ep;
988 	int flags;
989 {
990 	struct hostlist *hp;
991 	struct dirlist *dp2;
992 
993 	if (flags & OP_ALLDIRS) {
994 		if (ep->ex_defdir)
995 			free((caddr_t)dp);
996 		else
997 			ep->ex_defdir = dp;
998 		if (grp == (struct grouplist *)NULL) {
999 			ep->ex_defdir->dp_flag |= DP_DEFSET;
1000 			if (flags & OP_KERB)
1001 				ep->ex_defdir->dp_flag |= DP_KERB;
1002 		} else while (grp) {
1003 			hp = get_ht();
1004 			if (flags & OP_KERB)
1005 				hp->ht_flag |= DP_KERB;
1006 			hp->ht_grp = grp;
1007 			hp->ht_next = ep->ex_defdir->dp_hosts;
1008 			ep->ex_defdir->dp_hosts = hp;
1009 			grp = grp->gr_next;
1010 		}
1011 	} else {
1012 
1013 		/*
1014 		 * Loop throught the directories adding them to the tree.
1015 		 */
1016 		while (dp) {
1017 			dp2 = dp->dp_left;
1018 			add_dlist(&ep->ex_dirl, dp, grp, flags);
1019 			dp = dp2;
1020 		}
1021 	}
1022 }
1023 
1024 /*
1025  * Traverse the binary tree either updating a node that is already there
1026  * for the new directory or adding the new node.
1027  */
1028 void
1029 add_dlist(dpp, newdp, grp, flags)
1030 	struct dirlist **dpp;
1031 	struct dirlist *newdp;
1032 	struct grouplist *grp;
1033 	int flags;
1034 {
1035 	struct dirlist *dp;
1036 	struct hostlist *hp;
1037 	int cmp;
1038 
1039 	dp = *dpp;
1040 	if (dp) {
1041 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1042 		if (cmp > 0) {
1043 			add_dlist(&dp->dp_left, newdp, grp, flags);
1044 			return;
1045 		} else if (cmp < 0) {
1046 			add_dlist(&dp->dp_right, newdp, grp, flags);
1047 			return;
1048 		} else
1049 			free((caddr_t)newdp);
1050 	} else {
1051 		dp = newdp;
1052 		dp->dp_left = (struct dirlist *)NULL;
1053 		*dpp = dp;
1054 	}
1055 	if (grp) {
1056 
1057 		/*
1058 		 * Hang all of the host(s) off of the directory point.
1059 		 */
1060 		do {
1061 			hp = get_ht();
1062 			if (flags & OP_KERB)
1063 				hp->ht_flag |= DP_KERB;
1064 			hp->ht_grp = grp;
1065 			hp->ht_next = dp->dp_hosts;
1066 			dp->dp_hosts = hp;
1067 			grp = grp->gr_next;
1068 		} while (grp);
1069 	} else {
1070 		dp->dp_flag |= DP_DEFSET;
1071 		if (flags & OP_KERB)
1072 			dp->dp_flag |= DP_KERB;
1073 	}
1074 }
1075 
1076 /*
1077  * Search for a dirpath on the export point.
1078  */
1079 struct dirlist *
1080 dirp_search(dp, dirpath)
1081 	struct dirlist *dp;
1082 	char *dirpath;
1083 {
1084 	int cmp;
1085 
1086 	if (dp) {
1087 		cmp = strcmp(dp->dp_dirp, dirpath);
1088 		if (cmp > 0)
1089 			return (dirp_search(dp->dp_left, dirpath));
1090 		else if (cmp < 0)
1091 			return (dirp_search(dp->dp_right, dirpath));
1092 		else
1093 			return (dp);
1094 	}
1095 	return (dp);
1096 }
1097 
1098 /*
1099  * Scan for a host match in a directory tree.
1100  */
1101 int
1102 chk_host(dp, saddr, defsetp, hostsetp)
1103 	struct dirlist *dp;
1104 	u_long saddr;
1105 	int *defsetp;
1106 	int *hostsetp;
1107 {
1108 	struct hostlist *hp;
1109 	struct grouplist *grp;
1110 	u_long **addrp;
1111 
1112 	if (dp) {
1113 		if (dp->dp_flag & DP_DEFSET)
1114 			*defsetp = dp->dp_flag;
1115 		hp = dp->dp_hosts;
1116 		while (hp) {
1117 			grp = hp->ht_grp;
1118 			switch (grp->gr_type) {
1119 			case GT_HOST:
1120 			    addrp = (u_long **)
1121 				grp->gr_ptr.gt_hostent->h_addr_list;
1122 			    while (*addrp) {
1123 				if (**addrp == saddr) {
1124 				    *hostsetp = (hp->ht_flag | DP_HOSTSET);
1125 				    return (1);
1126 				}
1127 				addrp++;
1128 			    }
1129 			    break;
1130 			case GT_NET:
1131 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1132 				grp->gr_ptr.gt_net.nt_net) {
1133 				*hostsetp = (hp->ht_flag | DP_HOSTSET);
1134 				return (1);
1135 			    }
1136 			    break;
1137 			};
1138 			hp = hp->ht_next;
1139 		}
1140 	}
1141 	return (0);
1142 }
1143 
1144 /*
1145  * Scan tree for a host that matches the address.
1146  */
1147 int
1148 scan_tree(dp, saddr)
1149 	struct dirlist *dp;
1150 	u_long saddr;
1151 {
1152 	int defset, hostset;
1153 
1154 	if (dp) {
1155 		if (scan_tree(dp->dp_left, saddr))
1156 			return (1);
1157 		if (chk_host(dp, saddr, &defset, &hostset))
1158 			return (1);
1159 		if (scan_tree(dp->dp_right, saddr))
1160 			return (1);
1161 	}
1162 	return (0);
1163 }
1164 
1165 /*
1166  * Traverse the dirlist tree and free it up.
1167  */
1168 void
1169 free_dir(dp)
1170 	struct dirlist *dp;
1171 {
1172 
1173 	if (dp) {
1174 		free_dir(dp->dp_left);
1175 		free_dir(dp->dp_right);
1176 		free_host(dp->dp_hosts);
1177 		free((caddr_t)dp);
1178 	}
1179 }
1180 
1181 /*
1182  * Parse the option string and update fields.
1183  * Option arguments may either be -<option>=<value> or
1184  * -<option> <value>
1185  */
1186 int
1187 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1188 	char **cpp, **endcpp;
1189 	struct exportlist *ep;
1190 	struct grouplist *grp;
1191 	int *has_hostp;
1192 	int *exflagsp;
1193 	struct ucred *cr;
1194 {
1195 	char *cpoptarg, *cpoptend;
1196 	char *cp, *endcp, *cpopt, savedc, savedc2;
1197 	int allflag, usedarg;
1198 
1199 	cpopt = *cpp;
1200 	cpopt++;
1201 	cp = *endcpp;
1202 	savedc = *cp;
1203 	*cp = '\0';
1204 	while (cpopt && *cpopt) {
1205 		allflag = 1;
1206 		usedarg = -2;
1207 		if (cpoptend = index(cpopt, ',')) {
1208 			*cpoptend++ = '\0';
1209 			if (cpoptarg = index(cpopt, '='))
1210 				*cpoptarg++ = '\0';
1211 		} else {
1212 			if (cpoptarg = index(cpopt, '='))
1213 				*cpoptarg++ = '\0';
1214 			else {
1215 				*cp = savedc;
1216 				nextfield(&cp, &endcp);
1217 				**endcpp = '\0';
1218 				if (endcp > cp && *cp != '-') {
1219 					cpoptarg = cp;
1220 					savedc2 = *endcp;
1221 					*endcp = '\0';
1222 					usedarg = 0;
1223 				}
1224 			}
1225 		}
1226 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1227 			*exflagsp |= MNT_EXRDONLY;
1228 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1229 		    !(allflag = strcmp(cpopt, "mapall")) ||
1230 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1231 			usedarg++;
1232 			parsecred(cpoptarg, cr);
1233 			if (allflag == 0) {
1234 				*exflagsp |= MNT_EXPORTANON;
1235 				opt_flags |= OP_MAPALL;
1236 			} else
1237 				opt_flags |= OP_MAPROOT;
1238 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1239 			*exflagsp |= MNT_EXKERB;
1240 			opt_flags |= OP_KERB;
1241 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1242 			!strcmp(cpopt, "m"))) {
1243 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1244 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1245 				return (1);
1246 			}
1247 			usedarg++;
1248 			opt_flags |= OP_MASK;
1249 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
1250 			!strcmp(cpopt, "n"))) {
1251 			if (grp->gr_type != GT_NULL) {
1252 				syslog(LOG_ERR, "Network/host conflict");
1253 				return (1);
1254 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1255 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1256 				return (1);
1257 			}
1258 			grp->gr_type = GT_NET;
1259 			*has_hostp = 1;
1260 			usedarg++;
1261 			opt_flags |= OP_NET;
1262 		} else if (!strcmp(cpopt, "alldirs")) {
1263 			opt_flags |= OP_ALLDIRS;
1264 #ifdef ISO
1265 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1266 			if (get_isoaddr(cpoptarg, grp)) {
1267 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1268 				return (1);
1269 			}
1270 			*has_hostp = 1;
1271 			usedarg++;
1272 			opt_flags |= OP_ISO;
1273 #endif /* ISO */
1274 		} else {
1275 			syslog(LOG_ERR, "Bad opt %s", cpopt);
1276 			return (1);
1277 		}
1278 		if (usedarg >= 0) {
1279 			*endcp = savedc2;
1280 			**endcpp = savedc;
1281 			if (usedarg > 0) {
1282 				*cpp = cp;
1283 				*endcpp = endcp;
1284 			}
1285 			return (0);
1286 		}
1287 		cpopt = cpoptend;
1288 	}
1289 	**endcpp = savedc;
1290 	return (0);
1291 }
1292 
1293 /*
1294  * Translate a character string to the corresponding list of network
1295  * addresses for a hostname.
1296  */
1297 int
1298 get_host(cp, grp)
1299 	char *cp;
1300 	struct grouplist *grp;
1301 {
1302 	struct hostent *hp, *nhp;
1303 	char **addrp, **naddrp;
1304 	struct hostent t_host;
1305 	int i;
1306 	u_long saddr;
1307 	char *aptr[2];
1308 
1309 	if (grp->gr_type != GT_NULL)
1310 		return (1);
1311 	if ((hp = gethostbyname(cp)) == NULL) {
1312 		if (isdigit(*cp)) {
1313 			saddr = inet_addr(cp);
1314 			if (saddr == -1) {
1315 				syslog(LOG_ERR, "Inet_addr failed for %s", cp);
1316 				return (1);
1317 			}
1318 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1319 				AF_INET)) == NULL) {
1320 				hp = &t_host;
1321 				hp->h_name = cp;
1322 				hp->h_addrtype = AF_INET;
1323 				hp->h_length = sizeof (u_long);
1324 				hp->h_addr_list = aptr;
1325 				aptr[0] = (char *)&saddr;
1326 				aptr[1] = (char *)NULL;
1327 			}
1328 		} else {
1329 			syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
1330 			return (1);
1331 		}
1332 	}
1333 	grp->gr_type = GT_HOST;
1334 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1335 		malloc(sizeof(struct hostent));
1336 	if (nhp == (struct hostent *)NULL)
1337 		out_of_mem();
1338 	bcopy((caddr_t)hp, (caddr_t)nhp,
1339 		sizeof(struct hostent));
1340 	i = strlen(hp->h_name)+1;
1341 	nhp->h_name = (char *)malloc(i);
1342 	if (nhp->h_name == (char *)NULL)
1343 		out_of_mem();
1344 	bcopy(hp->h_name, nhp->h_name, i);
1345 	addrp = hp->h_addr_list;
1346 	i = 1;
1347 	while (*addrp++)
1348 		i++;
1349 	naddrp = nhp->h_addr_list = (char **)
1350 		malloc(i*sizeof(char *));
1351 	if (naddrp == (char **)NULL)
1352 		out_of_mem();
1353 	addrp = hp->h_addr_list;
1354 	while (*addrp) {
1355 		*naddrp = (char *)
1356 		    malloc(hp->h_length);
1357 		if (*naddrp == (char *)NULL)
1358 		    out_of_mem();
1359 		bcopy(*addrp, *naddrp,
1360 			hp->h_length);
1361 		addrp++;
1362 		naddrp++;
1363 	}
1364 	*naddrp = (char *)NULL;
1365 	if (debug)
1366 		fprintf(stderr, "got host %s\n", hp->h_name);
1367 	return (0);
1368 }
1369 
1370 /*
1371  * Free up an exports list component
1372  */
1373 void
1374 free_exp(ep)
1375 	struct exportlist *ep;
1376 {
1377 
1378 	if (ep->ex_defdir) {
1379 		free_host(ep->ex_defdir->dp_hosts);
1380 		free((caddr_t)ep->ex_defdir);
1381 	}
1382 	if (ep->ex_fsdir)
1383 		free(ep->ex_fsdir);
1384 	free_dir(ep->ex_dirl);
1385 	free((caddr_t)ep);
1386 }
1387 
1388 /*
1389  * Free hosts.
1390  */
1391 void
1392 free_host(hp)
1393 	struct hostlist *hp;
1394 {
1395 	struct hostlist *hp2;
1396 
1397 	while (hp) {
1398 		hp2 = hp;
1399 		hp = hp->ht_next;
1400 		free((caddr_t)hp2);
1401 	}
1402 }
1403 
1404 struct hostlist *
1405 get_ht()
1406 {
1407 	struct hostlist *hp;
1408 
1409 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1410 	if (hp == (struct hostlist *)NULL)
1411 		out_of_mem();
1412 	hp->ht_next = (struct hostlist *)NULL;
1413 	hp->ht_flag = 0;
1414 	return (hp);
1415 }
1416 
1417 #ifdef ISO
1418 /*
1419  * Translate an iso address.
1420  */
1421 get_isoaddr(cp, grp)
1422 	char *cp;
1423 	struct grouplist *grp;
1424 {
1425 	struct iso_addr *isop;
1426 	struct sockaddr_iso *isoaddr;
1427 
1428 	if (grp->gr_type != GT_NULL)
1429 		return (1);
1430 	if ((isop = iso_addr(cp)) == NULL) {
1431 		syslog(LOG_ERR,
1432 		    "iso_addr failed, ignored");
1433 		return (1);
1434 	}
1435 	isoaddr = (struct sockaddr_iso *)
1436 	    malloc(sizeof (struct sockaddr_iso));
1437 	if (isoaddr == (struct sockaddr_iso *)NULL)
1438 		out_of_mem();
1439 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1440 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1441 		sizeof (struct iso_addr));
1442 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
1443 	isoaddr->siso_family = AF_ISO;
1444 	grp->gr_type = GT_ISO;
1445 	grp->gr_ptr.gt_isoaddr = isoaddr;
1446 	return (0);
1447 }
1448 #endif	/* ISO */
1449 
1450 /*
1451  * Out of memory, fatal
1452  */
1453 void
1454 out_of_mem()
1455 {
1456 
1457 	syslog(LOG_ERR, "Out of memory");
1458 	exit(2);
1459 }
1460 
1461 /*
1462  * Do the mount syscall with the update flag to push the export info into
1463  * the kernel.
1464  */
1465 int
1466 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1467 	struct exportlist *ep;
1468 	struct grouplist *grp;
1469 	int exflags;
1470 	struct ucred *anoncrp;
1471 	char *dirp;
1472 	int dirplen;
1473 	struct statfs *fsb;
1474 {
1475 	char *cp = (char *)NULL;
1476 	u_long **addrp;
1477 	int done;
1478 	char savedc = '\0';
1479 	struct sockaddr_in sin, imask;
1480 	union {
1481 		struct ufs_args ua;
1482 		struct iso_args ia;
1483 		struct mfs_args ma;
1484 	} args;
1485 	u_long net;
1486 
1487 	args.ua.fspec = 0;
1488 	args.ua.export.ex_flags = exflags;
1489 	args.ua.export.ex_anon = *anoncrp;
1490 	bzero((char *)&sin, sizeof(sin));
1491 	bzero((char *)&imask, sizeof(imask));
1492 	sin.sin_family = AF_INET;
1493 	sin.sin_len = sizeof(sin);
1494 	imask.sin_family = AF_INET;
1495 	imask.sin_len = sizeof(sin);
1496 	if (grp->gr_type == GT_HOST)
1497 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1498 	else
1499 		addrp = (u_long **)NULL;
1500 	done = FALSE;
1501 	while (!done) {
1502 		switch (grp->gr_type) {
1503 		case GT_HOST:
1504 			if (addrp) {
1505 				sin.sin_addr.s_addr = **addrp;
1506 				args.ua.export.ex_addrlen = sizeof(sin);
1507 			} else
1508 				args.ua.export.ex_addrlen = 0;
1509 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1510 			args.ua.export.ex_masklen = 0;
1511 			break;
1512 		case GT_NET:
1513 			if (grp->gr_ptr.gt_net.nt_mask)
1514 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1515 			else {
1516 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1517 			    if (IN_CLASSA(net))
1518 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1519 			    else if (IN_CLASSB(net))
1520 				imask.sin_addr.s_addr =
1521 				    inet_addr("255.255.0.0");
1522 			    else
1523 				imask.sin_addr.s_addr =
1524 				    inet_addr("255.255.255.0");
1525 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1526 			}
1527 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1528 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1529 			args.ua.export.ex_addrlen = sizeof (sin);
1530 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
1531 			args.ua.export.ex_masklen = sizeof (imask);
1532 			break;
1533 #ifdef ISO
1534 		case GT_ISO:
1535 			args.ua.export.ex_addr =
1536 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1537 			args.ua.export.ex_addrlen =
1538 				sizeof(struct sockaddr_iso);
1539 			args.ua.export.ex_masklen = 0;
1540 			break;
1541 #endif	/* ISO */
1542 		default:
1543 			syslog(LOG_ERR, "Bad grouptype");
1544 			if (cp)
1545 				*cp = savedc;
1546 			return (1);
1547 		};
1548 
1549 		/*
1550 		 * XXX:
1551 		 * Maybe I should just use the fsb->f_mntonname path instead
1552 		 * of looping back up the dirp to the mount point??
1553 		 * Also, needs to know how to export all types of local
1554 		 * exportable file systems and not just "ufs".
1555 		 */
1556 		while (mount(fsb->f_fstypename, dirp,
1557 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1558 			if (cp)
1559 				*cp-- = savedc;
1560 			else
1561 				cp = dirp + dirplen - 1;
1562 			if (errno == EPERM) {
1563 				syslog(LOG_ERR,
1564 				   "Can't change attributes for %s.\n", dirp);
1565 				return (1);
1566 			}
1567 			if (opt_flags & OP_ALLDIRS) {
1568 				syslog(LOG_ERR, "Not root dir");
1569 				return (1);
1570 			}
1571 			/* back up over the last component */
1572 			while (*cp == '/' && cp > dirp)
1573 				cp--;
1574 			while (*(cp - 1) != '/' && cp > dirp)
1575 				cp--;
1576 			if (cp == dirp) {
1577 				if (debug)
1578 					fprintf(stderr,"mnt unsucc\n");
1579 				syslog(LOG_ERR, "Can't export %s", dirp);
1580 				return (1);
1581 			}
1582 			savedc = *cp;
1583 			*cp = '\0';
1584 		}
1585 		if (addrp) {
1586 			++addrp;
1587 			if (*addrp == (u_long *)NULL)
1588 				done = TRUE;
1589 		} else
1590 			done = TRUE;
1591 	}
1592 	if (cp)
1593 		*cp = savedc;
1594 	return (0);
1595 }
1596 
1597 /*
1598  * Translate a net address.
1599  */
1600 int
1601 get_net(cp, net, maskflg)
1602 	char *cp;
1603 	struct netmsk *net;
1604 	int maskflg;
1605 {
1606 	struct netent *np;
1607 	long netaddr;
1608 	struct in_addr inetaddr, inetaddr2;
1609 	char *name;
1610 
1611 	if (np = getnetbyname(cp))
1612 		inetaddr = inet_makeaddr(np->n_net, 0);
1613 	else if (isdigit(*cp)) {
1614 		if ((netaddr = inet_network(cp)) == -1)
1615 			return (1);
1616 		inetaddr = inet_makeaddr(netaddr, 0);
1617 		/*
1618 		 * Due to arbritrary subnet masks, you don't know how many
1619 		 * bits to shift the address to make it into a network,
1620 		 * however you do know how to make a network address into
1621 		 * a host with host == 0 and then compare them.
1622 		 * (What a pest)
1623 		 */
1624 		if (!maskflg) {
1625 			setnetent(0);
1626 			while (np = getnetent()) {
1627 				inetaddr2 = inet_makeaddr(np->n_net, 0);
1628 				if (inetaddr2.s_addr == inetaddr.s_addr)
1629 					break;
1630 			}
1631 			endnetent();
1632 		}
1633 	} else
1634 		return (1);
1635 	if (maskflg)
1636 		net->nt_mask = inetaddr.s_addr;
1637 	else {
1638 		if (np)
1639 			name = np->n_name;
1640 		else
1641 			name = inet_ntoa(inetaddr);
1642 		net->nt_name = (char *)malloc(strlen(name) + 1);
1643 		if (net->nt_name == (char *)NULL)
1644 			out_of_mem();
1645 		strcpy(net->nt_name, name);
1646 		net->nt_net = inetaddr.s_addr;
1647 	}
1648 	return (0);
1649 }
1650 
1651 /*
1652  * Parse out the next white space separated field
1653  */
1654 void
1655 nextfield(cp, endcp)
1656 	char **cp;
1657 	char **endcp;
1658 {
1659 	char *p;
1660 
1661 	p = *cp;
1662 	while (*p == ' ' || *p == '\t')
1663 		p++;
1664 	if (*p == '\n' || *p == '\0')
1665 		*cp = *endcp = p;
1666 	else {
1667 		*cp = p++;
1668 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1669 			p++;
1670 		*endcp = p;
1671 	}
1672 }
1673 
1674 /*
1675  * Get an exports file line. Skip over blank lines and handle line
1676  * continuations.
1677  */
1678 int
1679 get_line()
1680 {
1681 	char *p, *cp;
1682 	int len;
1683 	int totlen, cont_line;
1684 
1685 	/*
1686 	 * Loop around ignoring blank lines and getting all continuation lines.
1687 	 */
1688 	p = line;
1689 	totlen = 0;
1690 	do {
1691 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1692 			return (0);
1693 		len = strlen(p);
1694 		cp = p + len - 1;
1695 		cont_line = 0;
1696 		while (cp >= p &&
1697 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1698 			if (*cp == '\\')
1699 				cont_line = 1;
1700 			cp--;
1701 			len--;
1702 		}
1703 		*++cp = '\0';
1704 		if (len > 0) {
1705 			totlen += len;
1706 			if (totlen >= LINESIZ) {
1707 				syslog(LOG_ERR, "Exports line too long");
1708 				exit(2);
1709 			}
1710 			p = cp;
1711 		}
1712 	} while (totlen == 0 || cont_line);
1713 	return (1);
1714 }
1715 
1716 /*
1717  * Parse a description of a credential.
1718  */
1719 void
1720 parsecred(namelist, cr)
1721 	char *namelist;
1722 	struct ucred *cr;
1723 {
1724 	char *name;
1725 	int cnt;
1726 	char *names;
1727 	struct passwd *pw;
1728 	struct group *gr;
1729 	int ngroups, groups[NGROUPS + 1];
1730 
1731 	/*
1732 	 * Set up the unpriviledged user.
1733 	 */
1734 	cr->cr_ref = 1;
1735 	cr->cr_uid = -2;
1736 	cr->cr_groups[0] = -2;
1737 	cr->cr_ngroups = 1;
1738 	/*
1739 	 * Get the user's password table entry.
1740 	 */
1741 	names = strsep(&namelist, " \t\n");
1742 	name = strsep(&names, ":");
1743 	if (isdigit(*name) || *name == '-')
1744 		pw = getpwuid(atoi(name));
1745 	else
1746 		pw = getpwnam(name);
1747 	/*
1748 	 * Credentials specified as those of a user.
1749 	 */
1750 	if (names == NULL) {
1751 		if (pw == NULL) {
1752 			syslog(LOG_ERR, "Unknown user: %s", name);
1753 			return;
1754 		}
1755 		cr->cr_uid = pw->pw_uid;
1756 		ngroups = NGROUPS + 1;
1757 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1758 			syslog(LOG_ERR, "Too many groups");
1759 		/*
1760 		 * Convert from int's to gid_t's and compress out duplicate
1761 		 */
1762 		cr->cr_ngroups = ngroups - 1;
1763 		cr->cr_groups[0] = groups[0];
1764 		for (cnt = 2; cnt < ngroups; cnt++)
1765 			cr->cr_groups[cnt - 1] = groups[cnt];
1766 		return;
1767 	}
1768 	/*
1769 	 * Explicit credential specified as a colon separated list:
1770 	 *	uid:gid:gid:...
1771 	 */
1772 	if (pw != NULL)
1773 		cr->cr_uid = pw->pw_uid;
1774 	else if (isdigit(*name) || *name == '-')
1775 		cr->cr_uid = atoi(name);
1776 	else {
1777 		syslog(LOG_ERR, "Unknown user: %s", name);
1778 		return;
1779 	}
1780 	cr->cr_ngroups = 0;
1781 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1782 		name = strsep(&names, ":");
1783 		if (isdigit(*name) || *name == '-') {
1784 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1785 		} else {
1786 			if ((gr = getgrnam(name)) == NULL) {
1787 				syslog(LOG_ERR, "Unknown group: %s", name);
1788 				continue;
1789 			}
1790 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1791 		}
1792 	}
1793 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1794 		syslog(LOG_ERR, "Too many groups");
1795 }
1796 
1797 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1798 /*
1799  * Routines that maintain the remote mounttab
1800  */
1801 void
1802 get_mountlist()
1803 {
1804 	struct mountlist *mlp, **mlpp;
1805 	char *eos, *dirp;
1806 	int len;
1807 	char str[STRSIZ];
1808 	FILE *mlfile;
1809 
1810 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1811 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1812 		return;
1813 	}
1814 	mlpp = &mlhead;
1815 	while (fgets(str, STRSIZ, mlfile) != NULL) {
1816 		if ((dirp = index(str, '\t')) == NULL &&
1817 		    (dirp = index(str, ' ')) == NULL)
1818 			continue;
1819 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1820 		len = dirp-str;
1821 		if (len > RPCMNT_NAMELEN)
1822 			len = RPCMNT_NAMELEN;
1823 		bcopy(str, mlp->ml_host, len);
1824 		mlp->ml_host[len] = '\0';
1825 		while (*dirp == '\t' || *dirp == ' ')
1826 			dirp++;
1827 		if ((eos = index(dirp, '\t')) == NULL &&
1828 		    (eos = index(dirp, ' ')) == NULL &&
1829 		    (eos = index(dirp, '\n')) == NULL)
1830 			len = strlen(dirp);
1831 		else
1832 			len = eos-dirp;
1833 		if (len > RPCMNT_PATHLEN)
1834 			len = RPCMNT_PATHLEN;
1835 		bcopy(dirp, mlp->ml_dirp, len);
1836 		mlp->ml_dirp[len] = '\0';
1837 		mlp->ml_next = (struct mountlist *)NULL;
1838 		*mlpp = mlp;
1839 		mlpp = &mlp->ml_next;
1840 	}
1841 	fclose(mlfile);
1842 }
1843 
1844 void
1845 del_mlist(hostp, dirp)
1846 	char *hostp, *dirp;
1847 {
1848 	struct mountlist *mlp, **mlpp;
1849 	struct mountlist *mlp2;
1850 	FILE *mlfile;
1851 	int fnd = 0;
1852 
1853 	mlpp = &mlhead;
1854 	mlp = mlhead;
1855 	while (mlp) {
1856 		if (!strcmp(mlp->ml_host, hostp) &&
1857 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1858 			fnd = 1;
1859 			mlp2 = mlp;
1860 			*mlpp = mlp = mlp->ml_next;
1861 			free((caddr_t)mlp2);
1862 		} else {
1863 			mlpp = &mlp->ml_next;
1864 			mlp = mlp->ml_next;
1865 		}
1866 	}
1867 	if (fnd) {
1868 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1869 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1870 			return;
1871 		}
1872 		mlp = mlhead;
1873 		while (mlp) {
1874 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1875 			mlp = mlp->ml_next;
1876 		}
1877 		fclose(mlfile);
1878 	}
1879 }
1880 
1881 void
1882 add_mlist(hostp, dirp)
1883 	char *hostp, *dirp;
1884 {
1885 	struct mountlist *mlp, **mlpp;
1886 	FILE *mlfile;
1887 
1888 	mlpp = &mlhead;
1889 	mlp = mlhead;
1890 	while (mlp) {
1891 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1892 			return;
1893 		mlpp = &mlp->ml_next;
1894 		mlp = mlp->ml_next;
1895 	}
1896 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1897 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1898 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1899 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1900 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1901 	mlp->ml_next = (struct mountlist *)NULL;
1902 	*mlpp = mlp;
1903 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1904 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1905 		return;
1906 	}
1907 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1908 	fclose(mlfile);
1909 }
1910 
1911 /*
1912  * This function is called via. SIGTERM when the system is going down.
1913  * It sends a broadcast RPCMNT_UMNTALL.
1914  */
1915 void
1916 send_umntall()
1917 {
1918 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1919 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1920 	exit(0);
1921 }
1922 
1923 int
1924 umntall_each(resultsp, raddr)
1925 	caddr_t resultsp;
1926 	struct sockaddr_in *raddr;
1927 {
1928 	return (1);
1929 }
1930 
1931 /*
1932  * Free up a group list.
1933  */
1934 void
1935 free_grp(grp)
1936 	struct grouplist *grp;
1937 {
1938 	char **addrp;
1939 
1940 	if (grp->gr_type == GT_HOST) {
1941 		if (grp->gr_ptr.gt_hostent->h_name) {
1942 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1943 			while (addrp && *addrp)
1944 				free(*addrp++);
1945 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1946 			free(grp->gr_ptr.gt_hostent->h_name);
1947 		}
1948 		free((caddr_t)grp->gr_ptr.gt_hostent);
1949 	} else if (grp->gr_type == GT_NET) {
1950 		if (grp->gr_ptr.gt_net.nt_name)
1951 			free(grp->gr_ptr.gt_net.nt_name);
1952 	}
1953 #ifdef ISO
1954 	else if (grp->gr_type == GT_ISO)
1955 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
1956 #endif
1957 	free((caddr_t)grp);
1958 }
1959 
1960 #ifdef DEBUG
1961 void
1962 SYSLOG(int pri, const char *fmt, ...)
1963 {
1964 	va_list ap;
1965 
1966 	va_start(ap, fmt);
1967 	vfprintf(stderr, fmt, ap);
1968 	va_end(ap);
1969 }
1970 #endif /* DEBUG */
1971 
1972 /*
1973  * Check options for consistency.
1974  */
1975 int
1976 check_options(dp)
1977 	struct dirlist *dp;
1978 {
1979 
1980 	if (dp == (struct dirlist *)NULL)
1981 	    return (1);
1982 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1983 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1984 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1985 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1986 	    return (1);
1987 	}
1988 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1989 	    syslog(LOG_ERR, "-mask requires -net");
1990 	    return (1);
1991 	}
1992 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1993 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
1994 	    return (1);
1995 	}
1996 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1997 	    syslog(LOG_ERR, "-alldir has multiple directories");
1998 	    return (1);
1999 	}
2000 	return (0);
2001 }
2002 
2003 /*
2004  * Check an absolute directory path for any symbolic links. Return true
2005  * if no symbolic links are found.
2006  */
2007 int
2008 check_dirpath(dirp)
2009 	char *dirp;
2010 {
2011 	char *cp;
2012 	int ret = 1;
2013 	struct stat sb;
2014 
2015 	cp = dirp + 1;
2016 	while (*cp && ret) {
2017 		if (*cp == '/') {
2018 			*cp = '\0';
2019 			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2020 				ret = 0;
2021 			*cp = '/';
2022 		}
2023 		cp++;
2024 	}
2025 	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2026 		ret = 0;
2027 	return (ret);
2028 }
2029 
2030 /*
2031  * Just translate an ascii string to an integer.
2032  */
2033 int
2034 get_num(cp)
2035 	register char *cp;
2036 {
2037 	register int res = 0;
2038 
2039 	while (*cp) {
2040 		if (*cp < '0' || *cp > '9')
2041 			return (-1);
2042 		res = res * 10 + (*cp++ - '0');
2043 	}
2044 	return (res);
2045 }
2046