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