xref: /original-bsd/sbin/mountd/mountd.c (revision deff14a8)
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.10 (Berkeley) 08/17/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 					goto nextline;
750 				    }
751 				} else if (get_host(cp, grp)) {
752 				    getexp_err(ep, tgrp);
753 				    goto nextline;
754 				}
755 				has_host = TRUE;
756 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
757 			    endnetgrent();
758 			    *endcp = savedc;
759 			}
760 			cp = endcp;
761 			nextfield(&cp, &endcp);
762 			len = endcp - cp;
763 		}
764 		if (check_options(dirhead)) {
765 			getexp_err(ep, tgrp);
766 			goto nextline;
767 		}
768 		if (!has_host) {
769 			grp->gr_type = GT_HOST;
770 			if (debug)
771 				fprintf(stderr,"Adding a default entry\n");
772 			/* add a default group and make the grp list NULL */
773 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
774 			if (hpe == (struct hostent *)NULL)
775 				out_of_mem();
776 			hpe->h_name = "Default";
777 			hpe->h_addrtype = AF_INET;
778 			hpe->h_length = sizeof (u_long);
779 			hpe->h_addr_list = (char **)NULL;
780 			grp->gr_ptr.gt_hostent = hpe;
781 
782 		/*
783 		 * Don't allow a network export coincide with a list of
784 		 * host(s) on the same line.
785 		 */
786 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
787 			getexp_err(ep, tgrp);
788 			goto nextline;
789 		}
790 
791 		/*
792 		 * Loop through hosts, pushing the exports into the kernel.
793 		 * After loop, tgrp points to the start of the list and
794 		 * grp points to the last entry in the list.
795 		 */
796 		grp = tgrp;
797 		do {
798 		    if (do_mount(ep, grp, exflags, &anon, dirp,
799 			dirplen, &fsb)) {
800 			getexp_err(ep, tgrp);
801 			goto nextline;
802 		    }
803 		} while (grp->gr_next && (grp = grp->gr_next));
804 
805 		/*
806 		 * Success. Update the data structures.
807 		 */
808 		if (has_host) {
809 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
810 			grp->gr_next = grphead;
811 			grphead = tgrp;
812 		} else {
813 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
814 			(opt_flags & OP_ALLDIRS));
815 			free_grp(grp);
816 		}
817 		dirhead = (struct dirlist *)NULL;
818 		if ((ep->ex_flag & EX_LINKED) == 0) {
819 			ep2 = exphead;
820 			epp = &exphead;
821 
822 			/*
823 			 * Insert in the list in alphabetical order.
824 			 */
825 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
826 				epp = &ep2->ex_next;
827 				ep2 = ep2->ex_next;
828 			}
829 			if (ep2)
830 				ep->ex_next = ep2;
831 			*epp = ep;
832 			ep->ex_flag |= EX_LINKED;
833 		}
834 nextline:
835 		if (dirhead) {
836 			free_dir(dirhead);
837 			dirhead = (struct dirlist *)NULL;
838 		}
839 	}
840 	fclose(exp_file);
841 }
842 
843 /*
844  * Allocate an export list element
845  */
846 struct exportlist *
847 get_exp()
848 {
849 	struct exportlist *ep;
850 
851 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
852 	if (ep == (struct exportlist *)NULL)
853 		out_of_mem();
854 	bzero((caddr_t)ep, sizeof (struct exportlist));
855 	return (ep);
856 }
857 
858 /*
859  * Allocate a group list element
860  */
861 struct grouplist *
862 get_grp()
863 {
864 	struct grouplist *gp;
865 
866 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
867 	if (gp == (struct grouplist *)NULL)
868 		out_of_mem();
869 	bzero((caddr_t)gp, sizeof (struct grouplist));
870 	return (gp);
871 }
872 
873 /*
874  * Clean up upon an error in get_exportlist().
875  */
876 void
877 getexp_err(ep, grp)
878 	struct exportlist *ep;
879 	struct grouplist *grp;
880 {
881 	struct grouplist *tgrp;
882 
883 	syslog(LOG_ERR, "Bad exports list line %s", line);
884 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
885 		free_exp(ep);
886 	while (grp) {
887 		tgrp = grp;
888 		grp = grp->gr_next;
889 		free_grp(tgrp);
890 	}
891 }
892 
893 /*
894  * Search the export list for a matching fs.
895  */
896 struct exportlist *
897 ex_search(fsid)
898 	fsid_t *fsid;
899 {
900 	struct exportlist *ep;
901 
902 	ep = exphead;
903 	while (ep) {
904 		if (ep->ex_fs.val[0] == fsid->val[0] &&
905 		    ep->ex_fs.val[1] == fsid->val[1])
906 			return (ep);
907 		ep = ep->ex_next;
908 	}
909 	return (ep);
910 }
911 
912 /*
913  * Add a directory path to the list.
914  */
915 char *
916 add_expdir(dpp, cp, len)
917 	struct dirlist **dpp;
918 	char *cp;
919 	int len;
920 {
921 	struct dirlist *dp;
922 
923 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
924 	dp->dp_left = *dpp;
925 	dp->dp_right = (struct dirlist *)NULL;
926 	dp->dp_flag = 0;
927 	dp->dp_hosts = (struct hostlist *)NULL;
928 	strcpy(dp->dp_dirp, cp);
929 	*dpp = dp;
930 	return (dp->dp_dirp);
931 }
932 
933 /*
934  * Hang the dir list element off the dirpath binary tree as required
935  * and update the entry for host.
936  */
937 void
938 hang_dirp(dp, grp, ep, alldirs)
939 	struct dirlist *dp;
940 	struct grouplist *grp;
941 	struct exportlist *ep;
942 	int alldirs;
943 {
944 	struct hostlist *hp;
945 	struct dirlist *dp2;
946 
947 	if (alldirs) {
948 		if (ep->ex_defdir)
949 			free((caddr_t)dp);
950 		else
951 			ep->ex_defdir = dp;
952 		if (grp == (struct grouplist *)NULL)
953 			ep->ex_defdir->dp_flag |= DP_DEFSET;
954 		else while (grp) {
955 			hp = get_ht();
956 			hp->ht_grp = grp;
957 			hp->ht_next = ep->ex_defdir->dp_hosts;
958 			ep->ex_defdir->dp_hosts = hp;
959 			grp = grp->gr_next;
960 		}
961 	} else {
962 
963 		/*
964 		 * Loop throught the directories adding them to the tree.
965 		 */
966 		while (dp) {
967 			dp2 = dp->dp_left;
968 			add_dlist(&ep->ex_dirl, dp, grp);
969 			dp = dp2;
970 		}
971 	}
972 }
973 
974 /*
975  * Traverse the binary tree either updating a node that is already there
976  * for the new directory or adding the new node.
977  */
978 void
979 add_dlist(dpp, newdp, grp)
980 	struct dirlist **dpp;
981 	struct dirlist *newdp;
982 	struct grouplist *grp;
983 {
984 	struct dirlist *dp;
985 	struct hostlist *hp;
986 	int cmp;
987 
988 	dp = *dpp;
989 	if (dp) {
990 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
991 		if (cmp > 0) {
992 			add_dlist(&dp->dp_left, newdp, grp);
993 			return;
994 		} else if (cmp < 0) {
995 			add_dlist(&dp->dp_right, newdp, grp);
996 			return;
997 		} else
998 			free((caddr_t)newdp);
999 	} else {
1000 		dp = newdp;
1001 		dp->dp_left = (struct dirlist *)NULL;
1002 		*dpp = dp;
1003 	}
1004 	if (grp) {
1005 
1006 		/*
1007 		 * Hang all of the host(s) off of the directory point.
1008 		 */
1009 		do {
1010 			hp = get_ht();
1011 			hp->ht_grp = grp;
1012 			hp->ht_next = dp->dp_hosts;
1013 			dp->dp_hosts = hp;
1014 			grp = grp->gr_next;
1015 		} while (grp);
1016 	} else
1017 		dp->dp_flag |= DP_DEFSET;
1018 }
1019 
1020 /*
1021  * Search for a dirpath on the export point.
1022  */
1023 struct dirlist *
1024 dirp_search(dp, dirpath)
1025 	struct dirlist *dp;
1026 	char *dirpath;
1027 {
1028 	int cmp;
1029 
1030 	if (dp) {
1031 		cmp = strcmp(dp->dp_dirp, dirpath);
1032 		if (cmp > 0)
1033 			return (dirp_search(dp->dp_left, dirpath));
1034 		else if (cmp < 0)
1035 			return (dirp_search(dp->dp_right, dirpath));
1036 		else
1037 			return (dp);
1038 	}
1039 	return (dp);
1040 }
1041 
1042 /*
1043  * Scan for a host match in a directory tree.
1044  */
1045 int
1046 chk_host(dp, saddr, defsetp)
1047 	struct dirlist *dp;
1048 	u_long saddr;
1049 	int *defsetp;
1050 {
1051 	struct hostlist *hp;
1052 	struct grouplist *grp;
1053 	u_long **addrp;
1054 
1055 	if (dp) {
1056 		if (dp->dp_flag & DP_DEFSET)
1057 			*defsetp = 1;
1058 		hp = dp->dp_hosts;
1059 		while (hp) {
1060 			grp = hp->ht_grp;
1061 			switch (grp->gr_type) {
1062 			case GT_HOST:
1063 			    addrp = (u_long **)
1064 				grp->gr_ptr.gt_hostent->h_addr_list;
1065 			    while (*addrp) {
1066 				if (**addrp == saddr)
1067 				    return (1);
1068 				addrp++;
1069 			    }
1070 			    break;
1071 			case GT_NET:
1072 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1073 				grp->gr_ptr.gt_net.nt_net)
1074 				return (1);
1075 			    break;
1076 			};
1077 			hp = hp->ht_next;
1078 		}
1079 	}
1080 	return (0);
1081 }
1082 
1083 /*
1084  * Scan tree for a host that matches the address.
1085  */
1086 int
1087 scan_tree(dp, saddr)
1088 	struct dirlist *dp;
1089 	u_long saddr;
1090 {
1091 	int defset;
1092 
1093 	if (dp) {
1094 		if (scan_tree(dp->dp_left, saddr))
1095 			return (1);
1096 		if (chk_host(dp, saddr, &defset))
1097 			return (1);
1098 		if (scan_tree(dp->dp_right, saddr))
1099 			return (1);
1100 	}
1101 	return (0);
1102 }
1103 
1104 /*
1105  * Traverse the dirlist tree and free it up.
1106  */
1107 void
1108 free_dir(dp)
1109 	struct dirlist *dp;
1110 {
1111 
1112 	if (dp) {
1113 		free_dir(dp->dp_left);
1114 		free_dir(dp->dp_right);
1115 		free_host(dp->dp_hosts);
1116 		free((caddr_t)dp);
1117 	}
1118 }
1119 
1120 /*
1121  * Parse the option string and update fields.
1122  * Option arguments may either be -<option>=<value> or
1123  * -<option> <value>
1124  */
1125 int
1126 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1127 	char **cpp, **endcpp;
1128 	struct exportlist *ep;
1129 	struct grouplist *grp;
1130 	int *has_hostp;
1131 	int *exflagsp;
1132 	struct ucred *cr;
1133 {
1134 	char *cpoptarg, *cpoptend;
1135 	char *cp, *endcp, *cpopt, savedc, savedc2;
1136 	int allflag, usedarg;
1137 
1138 	cpopt = *cpp;
1139 	cpopt++;
1140 	cp = *endcpp;
1141 	savedc = *cp;
1142 	*cp = '\0';
1143 	while (cpopt && *cpopt) {
1144 		allflag = 1;
1145 		usedarg = -2;
1146 		if (cpoptend = index(cpopt, ',')) {
1147 			*cpoptend++ = '\0';
1148 			if (cpoptarg = index(cpopt, '='))
1149 				*cpoptarg++ = '\0';
1150 		} else {
1151 			if (cpoptarg = index(cpopt, '='))
1152 				*cpoptarg++ = '\0';
1153 			else {
1154 				*cp = savedc;
1155 				nextfield(&cp, &endcp);
1156 				**endcpp = '\0';
1157 				if (endcp > cp && *cp != '-') {
1158 					cpoptarg = cp;
1159 					savedc2 = *endcp;
1160 					*endcp = '\0';
1161 					usedarg = 0;
1162 				}
1163 			}
1164 		}
1165 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1166 			*exflagsp |= MNT_EXRDONLY;
1167 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1168 		    !(allflag = strcmp(cpopt, "mapall")) ||
1169 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1170 			usedarg++;
1171 			parsecred(cpoptarg, cr);
1172 			if (allflag == 0) {
1173 				*exflagsp |= MNT_EXPORTANON;
1174 				opt_flags |= OP_MAPALL;
1175 			} else
1176 				opt_flags |= OP_MAPROOT;
1177 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1178 			*exflagsp |= MNT_EXKERB;
1179 			opt_flags |= OP_KERB;
1180 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1181 			!strcmp(cpopt, "m"))) {
1182 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1183 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1184 				return (1);
1185 			}
1186 			usedarg++;
1187 			opt_flags |= OP_MASK;
1188 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
1189 			!strcmp(cpopt, "n"))) {
1190 			if (grp->gr_type != GT_NULL) {
1191 				syslog(LOG_ERR, "Network/host conflict");
1192 				return (1);
1193 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1194 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1195 				return (1);
1196 			}
1197 			grp->gr_type = GT_NET;
1198 			*has_hostp = 1;
1199 			usedarg++;
1200 			opt_flags |= OP_NET;
1201 		} else if (!strcmp(cpopt, "alldirs")) {
1202 			opt_flags |= OP_ALLDIRS;
1203 #ifdef ISO
1204 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1205 			if (get_isoaddr(cpoptarg, grp)) {
1206 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1207 				return (1);
1208 			}
1209 			*has_hostp = 1;
1210 			usedarg++;
1211 			opt_flags |= OP_ISO;
1212 #endif /* ISO */
1213 		} else {
1214 			syslog(LOG_ERR, "Bad opt %s", cpopt);
1215 			return (1);
1216 		}
1217 		if (usedarg >= 0) {
1218 			*endcp = savedc2;
1219 			**endcpp = savedc;
1220 			if (usedarg > 0) {
1221 				*cpp = cp;
1222 				*endcpp = endcp;
1223 			}
1224 			return (0);
1225 		}
1226 		cpopt = cpoptend;
1227 	}
1228 	**endcpp = savedc;
1229 	return (0);
1230 }
1231 
1232 /*
1233  * Translate a character string to the corresponding list of network
1234  * addresses for a hostname.
1235  */
1236 int
1237 get_host(cp, grp)
1238 	char *cp;
1239 	struct grouplist *grp;
1240 {
1241 	struct hostent *hp, *nhp;
1242 	char **addrp, **naddrp;
1243 	struct hostent t_host;
1244 	int i;
1245 	u_long saddr;
1246 	char *aptr[2];
1247 
1248 	if (grp->gr_type != GT_NULL)
1249 		return (1);
1250 	if ((hp = gethostbyname(cp)) == NULL) {
1251 		if (isdigit(*cp)) {
1252 			saddr = inet_addr(cp);
1253 			if (saddr == -1) {
1254 				syslog(LOG_ERR, "Inet_addr failed");
1255 				return (1);
1256 			}
1257 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1258 				AF_INET)) == NULL) {
1259 				hp = &t_host;
1260 				hp->h_name = cp;
1261 				hp->h_addrtype = AF_INET;
1262 				hp->h_length = sizeof (u_long);
1263 				hp->h_addr_list = aptr;
1264 				aptr[0] = (char *)&saddr;
1265 				aptr[1] = (char *)NULL;
1266 			}
1267 		} else {
1268 			syslog(LOG_ERR, "Gethostbyname failed");
1269 			return (1);
1270 		}
1271 	}
1272 	grp->gr_type = GT_HOST;
1273 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1274 		malloc(sizeof(struct hostent));
1275 	if (nhp == (struct hostent *)NULL)
1276 		out_of_mem();
1277 	bcopy((caddr_t)hp, (caddr_t)nhp,
1278 		sizeof(struct hostent));
1279 	i = strlen(hp->h_name)+1;
1280 	nhp->h_name = (char *)malloc(i);
1281 	if (nhp->h_name == (char *)NULL)
1282 		out_of_mem();
1283 	bcopy(hp->h_name, nhp->h_name, i);
1284 	addrp = hp->h_addr_list;
1285 	i = 1;
1286 	while (*addrp++)
1287 		i++;
1288 	naddrp = nhp->h_addr_list = (char **)
1289 		malloc(i*sizeof(char *));
1290 	if (naddrp == (char **)NULL)
1291 		out_of_mem();
1292 	addrp = hp->h_addr_list;
1293 	while (*addrp) {
1294 		*naddrp = (char *)
1295 		    malloc(hp->h_length);
1296 		if (*naddrp == (char *)NULL)
1297 		    out_of_mem();
1298 		bcopy(*addrp, *naddrp,
1299 			hp->h_length);
1300 		addrp++;
1301 		naddrp++;
1302 	}
1303 	*naddrp = (char *)NULL;
1304 	if (debug)
1305 		fprintf(stderr, "got host %s\n", hp->h_name);
1306 	return (0);
1307 }
1308 
1309 /*
1310  * Free up an exports list component
1311  */
1312 void
1313 free_exp(ep)
1314 	struct exportlist *ep;
1315 {
1316 
1317 	if (ep->ex_defdir) {
1318 		free_host(ep->ex_defdir->dp_hosts);
1319 		free((caddr_t)ep->ex_defdir);
1320 	}
1321 	if (ep->ex_fsdir)
1322 		free(ep->ex_fsdir);
1323 	free_dir(ep->ex_dirl);
1324 	free((caddr_t)ep);
1325 }
1326 
1327 /*
1328  * Free hosts.
1329  */
1330 void
1331 free_host(hp)
1332 	struct hostlist *hp;
1333 {
1334 	struct hostlist *hp2;
1335 
1336 	while (hp) {
1337 		hp2 = hp;
1338 		hp = hp->ht_next;
1339 		free((caddr_t)hp2);
1340 	}
1341 }
1342 
1343 struct hostlist *
1344 get_ht()
1345 {
1346 	struct hostlist *hp;
1347 
1348 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1349 	if (hp == (struct hostlist *)NULL)
1350 		out_of_mem();
1351 	hp->ht_next = (struct hostlist *)NULL;
1352 	return (hp);
1353 }
1354 
1355 #ifdef ISO
1356 /*
1357  * Translate an iso address.
1358  */
1359 get_isoaddr(cp, grp)
1360 	char *cp;
1361 	struct grouplist *grp;
1362 {
1363 	struct iso_addr *isop;
1364 	struct sockaddr_iso *isoaddr;
1365 
1366 	if (grp->gr_type != GT_NULL)
1367 		return (1);
1368 	if ((isop = iso_addr(cp)) == NULL) {
1369 		syslog(LOG_ERR,
1370 		    "iso_addr failed, ignored");
1371 		return (1);
1372 	}
1373 	isoaddr = (struct sockaddr_iso *)
1374 	    malloc(sizeof (struct sockaddr_iso));
1375 	if (isoaddr == (struct sockaddr_iso *)NULL)
1376 		out_of_mem();
1377 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1378 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1379 		sizeof (struct iso_addr));
1380 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
1381 	isoaddr->siso_family = AF_ISO;
1382 	grp->gr_type = GT_ISO;
1383 	grp->gr_ptr.gt_isoaddr = isoaddr;
1384 	return (0);
1385 }
1386 #endif	/* ISO */
1387 
1388 /*
1389  * Out of memory, fatal
1390  */
1391 void
1392 out_of_mem()
1393 {
1394 
1395 	syslog(LOG_ERR, "Out of memory");
1396 	exit(2);
1397 }
1398 
1399 /*
1400  * Do the mount syscall with the update flag to push the export info into
1401  * the kernel.
1402  */
1403 int
1404 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1405 	struct exportlist *ep;
1406 	struct grouplist *grp;
1407 	int exflags;
1408 	struct ucred *anoncrp;
1409 	char *dirp;
1410 	int dirplen;
1411 	struct statfs *fsb;
1412 {
1413 	char *cp = (char *)NULL;
1414 	u_long **addrp;
1415 	int done;
1416 	char savedc = '\0';
1417 	struct sockaddr_in sin, imask;
1418 	union {
1419 		struct ufs_args ua;
1420 		struct iso_args ia;
1421 		struct mfs_args ma;
1422 	} args;
1423 	u_long net;
1424 
1425 	args.ua.fspec = 0;
1426 	args.ua.export.ex_flags = exflags;
1427 	args.ua.export.ex_anon = *anoncrp;
1428 	bzero((char *)&sin, sizeof(sin));
1429 	bzero((char *)&imask, sizeof(imask));
1430 	sin.sin_family = AF_INET;
1431 	sin.sin_len = sizeof(sin);
1432 	imask.sin_family = AF_INET;
1433 	imask.sin_len = sizeof(sin);
1434 	if (grp->gr_type == GT_HOST)
1435 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1436 	else
1437 		addrp = (u_long **)NULL;
1438 	done = FALSE;
1439 	while (!done) {
1440 		switch (grp->gr_type) {
1441 		case GT_HOST:
1442 			if (addrp) {
1443 				sin.sin_addr.s_addr = **addrp;
1444 				args.ua.export.ex_addrlen = sizeof(sin);
1445 			} else
1446 				args.ua.export.ex_addrlen = 0;
1447 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1448 			args.ua.export.ex_masklen = 0;
1449 			break;
1450 		case GT_NET:
1451 			if (grp->gr_ptr.gt_net.nt_mask)
1452 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1453 			else {
1454 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1455 			    if (IN_CLASSA(net))
1456 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1457 			    else if (IN_CLASSB(net))
1458 				imask.sin_addr.s_addr =
1459 				    inet_addr("255.255.0.0");
1460 			    else
1461 				imask.sin_addr.s_addr =
1462 				    inet_addr("255.255.255.0");
1463 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1464 			}
1465 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1466 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1467 			args.ua.export.ex_addrlen = sizeof (sin);
1468 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
1469 			args.ua.export.ex_masklen = sizeof (imask);
1470 			break;
1471 #ifdef ISO
1472 		case GT_ISO:
1473 			args.ua.export.ex_addr =
1474 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1475 			args.ua.export.ex_addrlen =
1476 				sizeof(struct sockaddr_iso);
1477 			args.ua.export.ex_masklen = 0;
1478 			break;
1479 #endif	/* ISO */
1480 		default:
1481 			syslog(LOG_ERR, "Bad grouptype");
1482 			if (cp)
1483 				*cp = savedc;
1484 			return (1);
1485 		};
1486 
1487 		/*
1488 		 * XXX:
1489 		 * Maybe I should just use the fsb->f_mntonname path instead
1490 		 * of looping back up the dirp to the mount point??
1491 		 * Also, needs to know how to export all types of local
1492 		 * exportable file systems and not just MOUNT_UFS.
1493 		 */
1494 		while (mount(fsb->f_type, dirp,
1495 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1496 			if (cp)
1497 				*cp-- = savedc;
1498 			else
1499 				cp = dirp + dirplen - 1;
1500 			if (errno == EPERM) {
1501 				syslog(LOG_ERR,
1502 				   "Can't change attributes for %s.\n", dirp);
1503 				return (1);
1504 			}
1505 			if (opt_flags & OP_ALLDIRS) {
1506 				syslog(LOG_ERR, "Not root dir");
1507 				return (1);
1508 			}
1509 			/* back up over the last component */
1510 			while (*cp == '/' && cp > dirp)
1511 				cp--;
1512 			while (*(cp - 1) != '/' && cp > dirp)
1513 				cp--;
1514 			if (cp == dirp) {
1515 				if (debug)
1516 					fprintf(stderr,"mnt unsucc\n");
1517 				syslog(LOG_ERR, "Can't export %s", dirp);
1518 				return (1);
1519 			}
1520 			savedc = *cp;
1521 			*cp = '\0';
1522 		}
1523 		if (addrp) {
1524 			++addrp;
1525 			if (*addrp == (u_long *)NULL)
1526 				done = TRUE;
1527 		} else
1528 			done = TRUE;
1529 	}
1530 	if (cp)
1531 		*cp = savedc;
1532 	return (0);
1533 }
1534 
1535 /*
1536  * Translate a net address.
1537  */
1538 int
1539 get_net(cp, net, maskflg)
1540 	char *cp;
1541 	struct netmsk *net;
1542 	int maskflg;
1543 {
1544 	struct netent *np;
1545 	long netaddr;
1546 	struct in_addr inetaddr, inetaddr2;
1547 	char *name;
1548 
1549 	if (np = getnetbyname(cp))
1550 		inetaddr = inet_makeaddr(np->n_net, 0);
1551 	else if (isdigit(*cp)) {
1552 		if ((netaddr = inet_network(cp)) == -1)
1553 			return (1);
1554 		inetaddr = inet_makeaddr(netaddr, 0);
1555 		/*
1556 		 * Due to arbritrary subnet masks, you don't know how many
1557 		 * bits to shift the address to make it into a network,
1558 		 * however you do know how to make a network address into
1559 		 * a host with host == 0 and then compare them.
1560 		 * (What a pest)
1561 		 */
1562 		if (!maskflg) {
1563 			setnetent(0);
1564 			while (np = getnetent()) {
1565 				inetaddr2 = inet_makeaddr(np->n_net, 0);
1566 				if (inetaddr2.s_addr == inetaddr.s_addr)
1567 					break;
1568 			}
1569 			endnetent();
1570 		}
1571 	} else
1572 		return (1);
1573 	if (maskflg)
1574 		net->nt_mask = inetaddr.s_addr;
1575 	else {
1576 		if (np)
1577 			name = np->n_name;
1578 		else
1579 			name = inet_ntoa(inetaddr);
1580 		net->nt_name = (char *)malloc(strlen(name) + 1);
1581 		if (net->nt_name == (char *)NULL)
1582 			out_of_mem();
1583 		strcpy(net->nt_name, name);
1584 		net->nt_net = inetaddr.s_addr;
1585 	}
1586 	return (0);
1587 }
1588 
1589 /*
1590  * Parse out the next white space separated field
1591  */
1592 void
1593 nextfield(cp, endcp)
1594 	char **cp;
1595 	char **endcp;
1596 {
1597 	char *p;
1598 
1599 	p = *cp;
1600 	while (*p == ' ' || *p == '\t')
1601 		p++;
1602 	if (*p == '\n' || *p == '\0')
1603 		*cp = *endcp = p;
1604 	else {
1605 		*cp = p++;
1606 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1607 			p++;
1608 		*endcp = p;
1609 	}
1610 }
1611 
1612 /*
1613  * Get an exports file line. Skip over blank lines and handle line
1614  * continuations.
1615  */
1616 int
1617 get_line()
1618 {
1619 	char *p, *cp;
1620 	int len;
1621 	int totlen, cont_line;
1622 
1623 	/*
1624 	 * Loop around ignoring blank lines and getting all continuation lines.
1625 	 */
1626 	p = line;
1627 	totlen = 0;
1628 	do {
1629 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1630 			return (0);
1631 		len = strlen(p);
1632 		cp = p + len - 1;
1633 		cont_line = 0;
1634 		while (cp >= p &&
1635 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1636 			if (*cp == '\\')
1637 				cont_line = 1;
1638 			cp--;
1639 			len--;
1640 		}
1641 		*++cp = '\0';
1642 		if (len > 0) {
1643 			totlen += len;
1644 			if (totlen >= LINESIZ) {
1645 				syslog(LOG_ERR, "Exports line too long");
1646 				exit(2);
1647 			}
1648 			p = cp;
1649 		}
1650 	} while (totlen == 0 || cont_line);
1651 	return (1);
1652 }
1653 
1654 /*
1655  * Parse a description of a credential.
1656  */
1657 void
1658 parsecred(namelist, cr)
1659 	char *namelist;
1660 	struct ucred *cr;
1661 {
1662 	char *name;
1663 	int cnt;
1664 	char *names;
1665 	struct passwd *pw;
1666 	struct group *gr;
1667 	int ngroups, groups[NGROUPS + 1];
1668 
1669 	/*
1670 	 * Set up the unpriviledged user.
1671 	 */
1672 	cr->cr_ref = 1;
1673 	cr->cr_uid = -2;
1674 	cr->cr_groups[0] = -2;
1675 	cr->cr_ngroups = 1;
1676 	/*
1677 	 * Get the user's password table entry.
1678 	 */
1679 	names = strsep(&namelist, " \t\n");
1680 	name = strsep(&names, ":");
1681 	if (isdigit(*name) || *name == '-')
1682 		pw = getpwuid(atoi(name));
1683 	else
1684 		pw = getpwnam(name);
1685 	/*
1686 	 * Credentials specified as those of a user.
1687 	 */
1688 	if (names == NULL) {
1689 		if (pw == NULL) {
1690 			syslog(LOG_ERR, "Unknown user: %s", name);
1691 			return;
1692 		}
1693 		cr->cr_uid = pw->pw_uid;
1694 		ngroups = NGROUPS + 1;
1695 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1696 			syslog(LOG_ERR, "Too many groups");
1697 		/*
1698 		 * Convert from int's to gid_t's and compress out duplicate
1699 		 */
1700 		cr->cr_ngroups = ngroups - 1;
1701 		cr->cr_groups[0] = groups[0];
1702 		for (cnt = 2; cnt < ngroups; cnt++)
1703 			cr->cr_groups[cnt - 1] = groups[cnt];
1704 		return;
1705 	}
1706 	/*
1707 	 * Explicit credential specified as a colon separated list:
1708 	 *	uid:gid:gid:...
1709 	 */
1710 	if (pw != NULL)
1711 		cr->cr_uid = pw->pw_uid;
1712 	else if (isdigit(*name) || *name == '-')
1713 		cr->cr_uid = atoi(name);
1714 	else {
1715 		syslog(LOG_ERR, "Unknown user: %s", name);
1716 		return;
1717 	}
1718 	cr->cr_ngroups = 0;
1719 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1720 		name = strsep(&names, ":");
1721 		if (isdigit(*name) || *name == '-') {
1722 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1723 		} else {
1724 			if ((gr = getgrnam(name)) == NULL) {
1725 				syslog(LOG_ERR, "Unknown group: %s", name);
1726 				continue;
1727 			}
1728 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1729 		}
1730 	}
1731 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1732 		syslog(LOG_ERR, "Too many groups");
1733 }
1734 
1735 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1736 /*
1737  * Routines that maintain the remote mounttab
1738  */
1739 void
1740 get_mountlist()
1741 {
1742 	struct mountlist *mlp, **mlpp;
1743 	char *eos, *dirp;
1744 	int len;
1745 	char str[STRSIZ];
1746 	FILE *mlfile;
1747 
1748 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1749 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1750 		return;
1751 	}
1752 	mlpp = &mlhead;
1753 	while (fgets(str, STRSIZ, mlfile) != NULL) {
1754 		if ((dirp = index(str, '\t')) == NULL &&
1755 		    (dirp = index(str, ' ')) == NULL)
1756 			continue;
1757 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1758 		len = dirp-str;
1759 		if (len > RPCMNT_NAMELEN)
1760 			len = RPCMNT_NAMELEN;
1761 		bcopy(str, mlp->ml_host, len);
1762 		mlp->ml_host[len] = '\0';
1763 		while (*dirp == '\t' || *dirp == ' ')
1764 			dirp++;
1765 		if ((eos = index(dirp, '\t')) == NULL &&
1766 		    (eos = index(dirp, ' ')) == NULL &&
1767 		    (eos = index(dirp, '\n')) == NULL)
1768 			len = strlen(dirp);
1769 		else
1770 			len = eos-dirp;
1771 		if (len > RPCMNT_PATHLEN)
1772 			len = RPCMNT_PATHLEN;
1773 		bcopy(dirp, mlp->ml_dirp, len);
1774 		mlp->ml_dirp[len] = '\0';
1775 		mlp->ml_next = (struct mountlist *)NULL;
1776 		*mlpp = mlp;
1777 		mlpp = &mlp->ml_next;
1778 	}
1779 	fclose(mlfile);
1780 }
1781 
1782 void
1783 del_mlist(hostp, dirp)
1784 	char *hostp, *dirp;
1785 {
1786 	struct mountlist *mlp, **mlpp;
1787 	struct mountlist *mlp2;
1788 	FILE *mlfile;
1789 	int fnd = 0;
1790 
1791 	mlpp = &mlhead;
1792 	mlp = mlhead;
1793 	while (mlp) {
1794 		if (!strcmp(mlp->ml_host, hostp) &&
1795 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1796 			fnd = 1;
1797 			mlp2 = mlp;
1798 			*mlpp = mlp = mlp->ml_next;
1799 			free((caddr_t)mlp2);
1800 		} else {
1801 			mlpp = &mlp->ml_next;
1802 			mlp = mlp->ml_next;
1803 		}
1804 	}
1805 	if (fnd) {
1806 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1807 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1808 			return;
1809 		}
1810 		mlp = mlhead;
1811 		while (mlp) {
1812 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1813 			mlp = mlp->ml_next;
1814 		}
1815 		fclose(mlfile);
1816 	}
1817 }
1818 
1819 void
1820 add_mlist(hostp, dirp)
1821 	char *hostp, *dirp;
1822 {
1823 	struct mountlist *mlp, **mlpp;
1824 	FILE *mlfile;
1825 
1826 	mlpp = &mlhead;
1827 	mlp = mlhead;
1828 	while (mlp) {
1829 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1830 			return;
1831 		mlpp = &mlp->ml_next;
1832 		mlp = mlp->ml_next;
1833 	}
1834 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1835 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1836 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1837 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1838 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1839 	mlp->ml_next = (struct mountlist *)NULL;
1840 	*mlpp = mlp;
1841 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1842 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1843 		return;
1844 	}
1845 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1846 	fclose(mlfile);
1847 }
1848 
1849 /*
1850  * This function is called via. SIGTERM when the system is going down.
1851  * It sends a broadcast RPCMNT_UMNTALL.
1852  */
1853 void
1854 send_umntall()
1855 {
1856 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1857 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1858 	exit(0);
1859 }
1860 
1861 int
1862 umntall_each(resultsp, raddr)
1863 	caddr_t resultsp;
1864 	struct sockaddr_in *raddr;
1865 {
1866 	return (1);
1867 }
1868 
1869 /*
1870  * Free up a group list.
1871  */
1872 void
1873 free_grp(grp)
1874 	struct grouplist *grp;
1875 {
1876 	char **addrp;
1877 
1878 	if (grp->gr_type == GT_HOST) {
1879 		if (grp->gr_ptr.gt_hostent->h_name) {
1880 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1881 			while (addrp && *addrp)
1882 				free(*addrp++);
1883 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1884 			free(grp->gr_ptr.gt_hostent->h_name);
1885 		}
1886 		free((caddr_t)grp->gr_ptr.gt_hostent);
1887 	} else if (grp->gr_type == GT_NET) {
1888 		if (grp->gr_ptr.gt_net.nt_name)
1889 			free(grp->gr_ptr.gt_net.nt_name);
1890 	}
1891 #ifdef ISO
1892 	else if (grp->gr_type == GT_ISO)
1893 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
1894 #endif
1895 	free((caddr_t)grp);
1896 }
1897 
1898 #ifdef DEBUG
1899 void
1900 SYSLOG(int pri, const char *fmt, ...)
1901 {
1902 	va_list ap;
1903 
1904 	va_start(ap, fmt);
1905 	vfprintf(stderr, fmt, ap);
1906 	va_end(ap);
1907 }
1908 #endif /* DEBUG */
1909 
1910 /*
1911  * Check options for consistency.
1912  */
1913 int
1914 check_options(dp)
1915 	struct dirlist *dp;
1916 {
1917 
1918 	if (dp == (struct dirlist *)NULL)
1919 	    return (1);
1920 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1921 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1922 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1923 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1924 	    return (1);
1925 	}
1926 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1927 	    syslog(LOG_ERR, "-mask requires -net");
1928 	    return (1);
1929 	}
1930 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1931 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
1932 	    return (1);
1933 	}
1934 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1935 	    syslog(LOG_ERR, "-alldir has multiple directories");
1936 	    return (1);
1937 	}
1938 	return (0);
1939 }
1940 
1941 /*
1942  * Check an absolute directory path for any symbolic links. Return true
1943  * if no symbolic links are found.
1944  */
1945 int
1946 check_dirpath(dirp)
1947 	char *dirp;
1948 {
1949 	char *cp;
1950 	int ret = 1;
1951 	struct stat sb;
1952 
1953 	cp = dirp + 1;
1954 	while (*cp && ret) {
1955 		if (*cp == '/') {
1956 			*cp = '\0';
1957 			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
1958 				ret = 0;
1959 			*cp = '/';
1960 		}
1961 		cp++;
1962 	}
1963 	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
1964 		ret = 0;
1965 	return (ret);
1966 }
1967