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