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