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