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