xref: /original-bsd/sbin/mountd/mountd.c (revision 3b235ced)
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.6 (Berkeley) 01/28/94";
19 #endif not lint
20 
21 #include <sys/param.h>
22 #include <sys/file.h>
23 #include <sys/ioctl.h>
24 #include <sys/mount.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/syslog.h>
28 #include <sys/ucred.h>
29 
30 #include <rpc/rpc.h>
31 #include <rpc/pmap_clnt.h>
32 #include <rpc/pmap_prot.h>
33 #ifdef ISO
34 #include <netiso/iso.h>
35 #endif
36 #include <nfs/rpcv2.h>
37 #include <nfs/nfsv2.h>
38 
39 #include <errno.h>
40 #include <grp.h>
41 #include <netdb.h>
42 #include <pwd.h>
43 #include <signal.h>
44 #ifdef DEBUG
45 #include <stdarg.h>
46 #endif
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include "pathnames.h"
52 
53 /*
54  * Structures for keeping the mount list and export list
55  */
56 struct mountlist {
57 	struct mountlist *ml_next;
58 	char	ml_host[RPCMNT_NAMELEN+1];
59 	char	ml_dirp[RPCMNT_PATHLEN+1];
60 };
61 
62 struct dirlist {
63 	struct dirlist	*dp_left;
64 	struct dirlist	*dp_right;
65 	int		dp_flag;
66 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
67 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
68 };
69 /* dp_flag bits */
70 #define	DP_DEFSET	0x1
71 
72 struct exportlist {
73 	struct exportlist *ex_next;
74 	struct dirlist	*ex_dirl;
75 	struct dirlist	*ex_defdir;
76 	int		ex_flag;
77 	fsid_t		ex_fs;
78 	char		*ex_fsdir;
79 };
80 /* ex_flag bits */
81 #define	EX_LINKED	0x1
82 
83 struct netmsk {
84 	u_long	nt_net;
85 	u_long	nt_mask;
86 	char *nt_name;
87 };
88 
89 union grouptypes {
90 	struct hostent *gt_hostent;
91 	struct netmsk	gt_net;
92 #ifdef ISO
93 	struct sockaddr_iso *gt_isoaddr;
94 #endif
95 };
96 
97 struct grouplist {
98 	int gr_type;
99 	union grouptypes gr_ptr;
100 	struct grouplist *gr_next;
101 };
102 /* Group types */
103 #define	GT_NULL		0x0
104 #define	GT_HOST		0x1
105 #define	GT_NET		0x2
106 #define	GT_ISO		0x4
107 
108 struct hostlist {
109 	struct grouplist *ht_grp;
110 	struct hostlist	 *ht_next;
111 };
112 
113 /* Global defs */
114 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
115 int check_dirpath();
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 statfs fsb, *fsp;
538 	struct hostent *hpe;
539 	struct ucred anon;
540 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
541 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
542 
543 	/*
544 	 * First, get rid of the old list
545 	 */
546 	ep = exphead;
547 	while (ep) {
548 		ep2 = ep;
549 		ep = ep->ex_next;
550 		free_exp(ep2);
551 	}
552 	exphead = (struct exportlist *)0;
553 
554 	grp = grphead;
555 	while (grp) {
556 		tgrp = grp;
557 		grp = grp->gr_next;
558 		free_grp(tgrp);
559 	}
560 	grphead = (struct grouplist *)0;
561 
562 	/*
563 	 * And delete exports that are in the kernel for all local
564 	 * file systems.
565 	 * XXX: Should know how to handle all local exportable file systems
566 	 *      instead of just MOUNT_UFS.
567 	 */
568 	num = getmntinfo(&fsp, MNT_NOWAIT);
569 	for (i = 0; i < num; i++) {
570 		union {
571 			struct ufs_args ua;
572 			struct iso_args ia;
573 			struct mfs_args ma;
574 		} targs;
575 
576 		switch (fsp->f_type) {
577 		case MOUNT_MFS:
578 		case MOUNT_UFS:
579 		case MOUNT_CD9660:
580 			targs.ua.fspec = NULL;
581 			targs.ua.export.ex_flags = MNT_DELEXPORT;
582 			if (mount(fsp->f_type, fsp->f_mntonname,
583 				  fsp->f_flags | MNT_UPDATE,
584 				  (caddr_t)&targs) < 0)
585 				syslog(LOG_ERR, "Can't delete exports for %s",
586 				       fsp->f_mntonname);
587 		}
588 		fsp++;
589 	}
590 
591 	/*
592 	 * Read in the exports file and build the list, calling
593 	 * mount() as we go along to push the export rules into the kernel.
594 	 */
595 	if ((exp_file = fopen(exname, "r")) == NULL) {
596 		syslog(LOG_ERR, "Can't open %s", exname);
597 		exit(2);
598 	}
599 	dirhead = (struct dirlist *)0;
600 	while (get_line()) {
601 		if (debug)
602 			fprintf(stderr,"Got line %s\n",line);
603 		cp = line;
604 		nextfield(&cp, &endcp);
605 		if (*cp == '#')
606 			goto nextline;
607 
608 		/*
609 		 * Set defaults.
610 		 */
611 		has_host = FALSE;
612 		anon = def_anon;
613 		exflags = MNT_EXPORTED;
614 		got_nondir = 0;
615 		opt_flags = 0;
616 		ep = (struct exportlist *)0;
617 
618 		/*
619 		 * Create new exports list entry
620 		 */
621 		len = endcp-cp;
622 		tgrp = grp = get_grp();
623 		while (len > 0) {
624 			if (len > RPCMNT_NAMELEN) {
625 			    getexp_err(ep, tgrp);
626 			    goto nextline;
627 			}
628 			if (*cp == '-') {
629 			    if (ep == (struct exportlist *)0) {
630 				getexp_err(ep, tgrp);
631 				goto nextline;
632 			    }
633 			    if (debug)
634 				fprintf(stderr, "doing opt %s\n", cp);
635 			    got_nondir = 1;
636 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
637 				&exflags, &anon)) {
638 				getexp_err(ep, tgrp);
639 				goto nextline;
640 			    }
641 			} else if (*cp == '/') {
642 			    savedc = *endcp;
643 			    *endcp = '\0';
644 			    if (check_dirpath(cp) &&
645 				statfs(cp, &fsb) >= 0) {
646 				if (got_nondir) {
647 				    syslog(LOG_ERR, "Dirs must be first");
648 				    getexp_err(ep, tgrp);
649 				    goto nextline;
650 				}
651 				if (ep) {
652 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
653 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
654 					getexp_err(ep, tgrp);
655 					goto nextline;
656 				    }
657 				} else {
658 				    /*
659 				     * See if this directory is already
660 				     * in the list.
661 				     */
662 				    ep = ex_search(&fsb.f_fsid);
663 				    if (ep == (struct exportlist *)0) {
664 					ep = get_exp();
665 					ep->ex_fs = fsb.f_fsid;
666 					ep->ex_fsdir = (char *)
667 					    malloc(strlen(fsb.f_mntonname) + 1);
668 					if (ep->ex_fsdir)
669 					    strcpy(ep->ex_fsdir,
670 						fsb.f_mntonname);
671 					else
672 					    out_of_mem();
673 					if (debug)
674 					  fprintf(stderr,
675 					      "Making new ep fs=0x%x,0x%x\n",
676 					      fsb.f_fsid.val[0],
677 					      fsb.f_fsid.val[1]);
678 				    } else if (debug)
679 					fprintf(stderr,
680 					    "Found ep fs=0x%x,0x%x\n",
681 					    fsb.f_fsid.val[0],
682 					    fsb.f_fsid.val[1]);
683 				}
684 
685 				/*
686 				 * Add dirpath to export mount point.
687 				 */
688 				dirp = add_expdir(&dirhead, cp, len);
689 				dirplen = len;
690 			    } else {
691 				getexp_err(ep, tgrp);
692 				goto nextline;
693 			    }
694 			    *endcp = savedc;
695 			} else {
696 			    savedc = *endcp;
697 			    *endcp = '\0';
698 			    got_nondir = 1;
699 			    if (ep == (struct exportlist *)0) {
700 				getexp_err(ep, tgrp);
701 				goto nextline;
702 			    }
703 
704 			    /*
705 			     * Get the host or netgroup.
706 			     */
707 			    setnetgrent(cp);
708 			    netgrp = getnetgrent(&hst, &usr, &dom);
709 			    do {
710 				if (has_host) {
711 				    grp->gr_next = get_grp();
712 				    grp = grp->gr_next;
713 				}
714 				if (netgrp) {
715 				    if (get_host(hst, grp)) {
716 					syslog(LOG_ERR, "Bad netgroup %s", cp);
717 					getexp_err(ep, tgrp);
718 					goto nextline;
719 				    }
720 				} else if (get_host(cp, grp)) {
721 				    getexp_err(ep, tgrp);
722 				    goto nextline;
723 				}
724 				has_host = TRUE;
725 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
726 			    endnetgrent();
727 			    *endcp = savedc;
728 			}
729 			cp = endcp;
730 			nextfield(&cp, &endcp);
731 			len = endcp - cp;
732 		}
733 		if (check_options(dirhead)) {
734 			getexp_err(ep, tgrp);
735 			goto nextline;
736 		}
737 		if (!has_host) {
738 			grp->gr_type = GT_HOST;
739 			if (debug)
740 				fprintf(stderr,"Adding a default entry\n");
741 			/* add a default group and make the grp list NULL */
742 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
743 			if (hpe == (struct hostent *)0)
744 				out_of_mem();
745 			hpe->h_name = "Default";
746 			hpe->h_addrtype = AF_INET;
747 			hpe->h_length = sizeof (u_long);
748 			hpe->h_addr_list = (char **)0;
749 			grp->gr_ptr.gt_hostent = hpe;
750 
751 		/*
752 		 * Don't allow a network export coincide with a list of
753 		 * host(s) on the same line.
754 		 */
755 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
756 			getexp_err(ep, tgrp);
757 			goto nextline;
758 		}
759 
760 		/*
761 		 * Loop through hosts, pushing the exports into the kernel.
762 		 * After loop, tgrp points to the start of the list and
763 		 * grp points to the last entry in the list.
764 		 */
765 		grp = tgrp;
766 		do {
767 		    if (do_mount(ep, grp, exflags, &anon, dirp,
768 			dirplen, &fsb)) {
769 			getexp_err(ep, tgrp);
770 			goto nextline;
771 		    }
772 		} while (grp->gr_next && (grp = grp->gr_next));
773 
774 		/*
775 		 * Success. Update the data structures.
776 		 */
777 		if (has_host) {
778 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
779 			grp->gr_next = grphead;
780 			grphead = tgrp;
781 		} else {
782 			hang_dirp(dirhead, (struct grouplist *)0, ep,
783 			(opt_flags & OP_ALLDIRS));
784 			free_grp(grp);
785 		}
786 		dirhead = (struct dirlist *)0;
787 		if ((ep->ex_flag & EX_LINKED) == 0) {
788 			ep2 = exphead;
789 			epp = &exphead;
790 
791 			/*
792 			 * Insert in the list in alphabetical order.
793 			 */
794 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
795 				epp = &ep2->ex_next;
796 				ep2 = ep2->ex_next;
797 			}
798 			if (ep2)
799 				ep->ex_next = ep2;
800 			*epp = ep;
801 			ep->ex_flag |= EX_LINKED;
802 		}
803 nextline:
804 		if (dirhead) {
805 			free_dir(dirhead);
806 			dirhead = (struct dirlist *)0;
807 		}
808 	}
809 	fclose(exp_file);
810 }
811 
812 /*
813  * Allocate an export list element
814  */
815 struct exportlist *
816 get_exp()
817 {
818 	register struct exportlist *ep;
819 
820 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
821 	if (ep == (struct exportlist *)0)
822 		out_of_mem();
823 	bzero((caddr_t)ep, sizeof (struct exportlist));
824 	return (ep);
825 }
826 
827 /*
828  * Allocate a group list element
829  */
830 struct grouplist *
831 get_grp()
832 {
833 	register struct grouplist *gp;
834 
835 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
836 	if (gp == (struct grouplist *)0)
837 		out_of_mem();
838 	bzero((caddr_t)gp, sizeof (struct grouplist));
839 	return (gp);
840 }
841 
842 /*
843  * Clean up upon an error in get_exportlist().
844  */
845 void
846 getexp_err(ep, grp)
847 	struct exportlist *ep;
848 	struct grouplist *grp;
849 {
850 	struct grouplist *tgrp;
851 
852 	syslog(LOG_ERR, "Bad exports list line %s", line);
853 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
854 		free_exp(ep);
855 	while (grp) {
856 		tgrp = grp;
857 		grp = grp->gr_next;
858 		free_grp(tgrp);
859 	}
860 }
861 
862 /*
863  * Search the export list for a matching fs.
864  */
865 struct exportlist *
866 ex_search(fsid)
867 	fsid_t *fsid;
868 {
869 	register struct exportlist *ep;
870 
871 	ep = exphead;
872 	while (ep) {
873 		if (ep->ex_fs.val[0] == fsid->val[0] &&
874 		    ep->ex_fs.val[1] == fsid->val[1])
875 			return (ep);
876 		ep = ep->ex_next;
877 	}
878 	return (ep);
879 }
880 
881 /*
882  * Add a directory path to the list.
883  */
884 char *
885 add_expdir(dpp, cp, len)
886 	struct dirlist **dpp;
887 	char *cp;
888 	int len;
889 {
890 	register struct dirlist *dp;
891 
892 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
893 	dp->dp_left = *dpp;
894 	dp->dp_right = (struct dirlist *)0;
895 	dp->dp_flag = 0;
896 	dp->dp_hosts = (struct hostlist *)0;
897 	strcpy(dp->dp_dirp, cp);
898 	*dpp = dp;
899 	return (dp->dp_dirp);
900 }
901 
902 /*
903  * Hang the dir list element off the dirpath binary tree as required
904  * and update the entry for host.
905  */
906 void
907 hang_dirp(dp, grp, ep, alldirs)
908 	register struct dirlist *dp;
909 	struct grouplist *grp;
910 	struct exportlist *ep;
911 	int alldirs;
912 {
913 	register struct hostlist *hp;
914 	struct dirlist *dp2;
915 
916 	if (alldirs) {
917 		if (ep->ex_defdir)
918 			free((caddr_t)dp);
919 		else
920 			ep->ex_defdir = dp;
921 		if (grp == (struct grouplist *)0)
922 			ep->ex_defdir->dp_flag |= DP_DEFSET;
923 		else while (grp) {
924 			hp = get_ht();
925 			hp->ht_grp = grp;
926 			hp->ht_next = ep->ex_defdir->dp_hosts;
927 			ep->ex_defdir->dp_hosts = hp;
928 			grp = grp->gr_next;
929 		}
930 	} else {
931 
932 		/*
933 		 * Loop throught the directories adding them to the tree.
934 		 */
935 		while (dp) {
936 			dp2 = dp->dp_left;
937 			add_dlist(&ep->ex_dirl, dp, grp);
938 			dp = dp2;
939 		}
940 	}
941 }
942 
943 /*
944  * Traverse the binary tree either updating a node that is already there
945  * for the new directory or adding the new node.
946  */
947 void
948 add_dlist(dpp, newdp, grp)
949 	struct dirlist **dpp;
950 	struct dirlist *newdp;
951 	register struct grouplist *grp;
952 {
953 	register struct dirlist *dp;
954 	register struct hostlist *hp;
955 	int cmp;
956 
957 	dp = *dpp;
958 	if (dp) {
959 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
960 		if (cmp > 0) {
961 			add_dlist(&dp->dp_left, newdp, grp);
962 			return;
963 		} else if (cmp < 0) {
964 			add_dlist(&dp->dp_right, newdp, grp);
965 			return;
966 		} else
967 			free((caddr_t)newdp);
968 	} else {
969 		dp = newdp;
970 		dp->dp_left = (struct dirlist *)0;
971 		*dpp = dp;
972 	}
973 	if (grp) {
974 
975 		/*
976 		 * Hang all of the host(s) off of the directory point.
977 		 */
978 		do {
979 			hp = get_ht();
980 			hp->ht_grp = grp;
981 			hp->ht_next = dp->dp_hosts;
982 			dp->dp_hosts = hp;
983 			grp = grp->gr_next;
984 		} while (grp);
985 	} else
986 		dp->dp_flag |= DP_DEFSET;
987 }
988 
989 /*
990  * Search for a dirpath on the export point.
991  */
992 struct dirlist *
993 dirp_search(dp, dirpath)
994 	register struct dirlist *dp;
995 	char *dirpath;
996 {
997 	register int cmp;
998 
999 	if (dp) {
1000 		cmp = strcmp(dp->dp_dirp, dirpath);
1001 		if (cmp > 0)
1002 			return (dirp_search(dp->dp_left, dirpath));
1003 		else if (cmp < 0)
1004 			return (dirp_search(dp->dp_right, dirpath));
1005 		else
1006 			return (dp);
1007 	}
1008 	return (dp);
1009 }
1010 
1011 /*
1012  * Scan for a host match in a directory tree.
1013  */
1014 chk_host(dp, saddr, defsetp)
1015 	struct dirlist *dp;
1016 	u_long saddr;
1017 	int *defsetp;
1018 {
1019 	register struct hostlist *hp;
1020 	register struct grouplist *grp;
1021 	register u_long **addrp;
1022 
1023 	if (dp) {
1024 		if (dp->dp_flag & DP_DEFSET)
1025 			*defsetp = 1;
1026 		hp = dp->dp_hosts;
1027 		while (hp) {
1028 			grp = hp->ht_grp;
1029 			switch (grp->gr_type) {
1030 			case GT_HOST:
1031 			    addrp = (u_long **)
1032 				grp->gr_ptr.gt_hostent->h_addr_list;
1033 			    while (*addrp) {
1034 				if (**addrp == saddr)
1035 				    return (1);
1036 				addrp++;
1037 			    }
1038 			    break;
1039 			case GT_NET:
1040 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1041 				grp->gr_ptr.gt_net.nt_net)
1042 				return (1);
1043 			    break;
1044 			};
1045 			hp = hp->ht_next;
1046 		}
1047 	}
1048 	return (0);
1049 }
1050 
1051 /*
1052  * Scan tree for a host that matches the address.
1053  */
1054 scan_tree(dp, saddr)
1055 	register struct dirlist *dp;
1056 	u_long saddr;
1057 {
1058 	int defset;
1059 
1060 	if (dp) {
1061 		if (scan_tree(dp->dp_left, saddr))
1062 			return (1);
1063 		if (chk_host(dp, saddr, &defset))
1064 			return (1);
1065 		if (scan_tree(dp->dp_right, saddr))
1066 			return (1);
1067 	}
1068 	return (0);
1069 }
1070 
1071 /*
1072  * Traverse the dirlist tree and free it up.
1073  */
1074 void
1075 free_dir(dp)
1076 	register struct dirlist *dp;
1077 {
1078 
1079 	if (dp) {
1080 		free_dir(dp->dp_left);
1081 		free_dir(dp->dp_right);
1082 		free_host(dp->dp_hosts);
1083 		free((caddr_t)dp);
1084 	}
1085 }
1086 
1087 /*
1088  * Parse the option string and update fields.
1089  * Option arguments may either be -<option>=<value> or
1090  * -<option> <value>
1091  */
1092 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1093 	char **cpp, **endcpp;
1094 	struct exportlist *ep;
1095 	struct grouplist *grp;
1096 	int *has_hostp;
1097 	int *exflagsp;
1098 	struct ucred *cr;
1099 {
1100 	register char *cpoptarg, *cpoptend;
1101 	char *cp, *endcp, *cpopt, savedc, savedc2;
1102 	int allflag, usedarg;
1103 
1104 	cpopt = *cpp;
1105 	cpopt++;
1106 	cp = *endcpp;
1107 	savedc = *cp;
1108 	*cp = '\0';
1109 	while (cpopt && *cpopt) {
1110 		allflag = 1;
1111 		usedarg = -2;
1112 		if (cpoptend = index(cpopt, ',')) {
1113 			*cpoptend++ = '\0';
1114 			if (cpoptarg = index(cpopt, '='))
1115 				*cpoptarg++ = '\0';
1116 		} else {
1117 			if (cpoptarg = index(cpopt, '='))
1118 				*cpoptarg++ = '\0';
1119 			else {
1120 				*cp = savedc;
1121 				nextfield(&cp, &endcp);
1122 				**endcpp = '\0';
1123 				if (endcp > cp && *cp != '-') {
1124 					cpoptarg = cp;
1125 					savedc2 = *endcp;
1126 					*endcp = '\0';
1127 					usedarg = 0;
1128 				}
1129 			}
1130 		}
1131 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1132 			*exflagsp |= MNT_EXRDONLY;
1133 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1134 		    !(allflag = strcmp(cpopt, "mapall")) ||
1135 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1136 			usedarg++;
1137 			parsecred(cpoptarg, cr);
1138 			if (allflag == 0) {
1139 				*exflagsp |= MNT_EXPORTANON;
1140 				opt_flags |= OP_MAPALL;
1141 			} else
1142 				opt_flags |= OP_MAPROOT;
1143 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1144 			*exflagsp |= MNT_EXKERB;
1145 			opt_flags |= OP_KERB;
1146 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1147 			!strcmp(cpopt, "m"))) {
1148 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1149 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1150 				return (1);
1151 			}
1152 			usedarg++;
1153 			opt_flags |= OP_MASK;
1154 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
1155 			!strcmp(cpopt, "n"))) {
1156 			if (grp->gr_type != GT_NULL) {
1157 				syslog(LOG_ERR, "Network/host conflict");
1158 				return (1);
1159 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1160 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1161 				return (1);
1162 			}
1163 			grp->gr_type = GT_NET;
1164 			*has_hostp = 1;
1165 			usedarg++;
1166 			opt_flags |= OP_NET;
1167 		} else if (!strcmp(cpopt, "alldirs")) {
1168 			opt_flags |= OP_ALLDIRS;
1169 #ifdef ISO
1170 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1171 			if (get_isoaddr(cpoptarg, grp)) {
1172 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1173 				return (1);
1174 			}
1175 			*has_hostp = 1;
1176 			usedarg++;
1177 			opt_flags |= OP_ISO;
1178 #endif /* ISO */
1179 		} else {
1180 			syslog(LOG_ERR, "Bad opt %s", cpopt);
1181 			return (1);
1182 		}
1183 		if (usedarg >= 0) {
1184 			*endcp = savedc2;
1185 			**endcpp = savedc;
1186 			if (usedarg > 0) {
1187 				*cpp = cp;
1188 				*endcpp = endcp;
1189 			}
1190 			return (0);
1191 		}
1192 		cpopt = cpoptend;
1193 	}
1194 	**endcpp = savedc;
1195 	return (0);
1196 }
1197 
1198 /*
1199  * Translate a character string to the corresponding list of network
1200  * addresses for a hostname.
1201  */
1202 get_host(cp, grp)
1203 	char *cp;
1204 	register struct grouplist *grp;
1205 {
1206 	register struct hostent *hp, *nhp;
1207 	register char **addrp, **naddrp;
1208 	struct hostent t_host;
1209 	int i;
1210 	u_long saddr;
1211 	char *aptr[2];
1212 
1213 	if (grp->gr_type != GT_NULL)
1214 		return (1);
1215 	if ((hp = gethostbyname(cp)) == NULL) {
1216 		if (isdigit(*cp)) {
1217 			saddr = inet_addr(cp);
1218 			if (saddr == -1) {
1219 				syslog(LOG_ERR, "Inet_addr failed");
1220 				return (1);
1221 			}
1222 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1223 				AF_INET)) == NULL) {
1224 				hp = &t_host;
1225 				hp->h_name = cp;
1226 				hp->h_addrtype = AF_INET;
1227 				hp->h_length = sizeof (u_long);
1228 				hp->h_addr_list = aptr;
1229 				aptr[0] = (char *)&saddr;
1230 				aptr[1] = (char *)0;
1231 			}
1232 		} else {
1233 			syslog(LOG_ERR, "Gethostbyname failed");
1234 			return (1);
1235 		}
1236 	}
1237 	grp->gr_type = GT_HOST;
1238 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1239 		malloc(sizeof(struct hostent));
1240 	if (nhp == (struct hostent *)0)
1241 		out_of_mem();
1242 	bcopy((caddr_t)hp, (caddr_t)nhp,
1243 		sizeof(struct hostent));
1244 	i = strlen(hp->h_name)+1;
1245 	nhp->h_name = (char *)malloc(i);
1246 	if (nhp->h_name == (char *)0)
1247 		out_of_mem();
1248 	bcopy(hp->h_name, nhp->h_name, i);
1249 	addrp = hp->h_addr_list;
1250 	i = 1;
1251 	while (*addrp++)
1252 		i++;
1253 	naddrp = nhp->h_addr_list = (char **)
1254 		malloc(i*sizeof(char *));
1255 	if (naddrp == (char **)0)
1256 		out_of_mem();
1257 	addrp = hp->h_addr_list;
1258 	while (*addrp) {
1259 		*naddrp = (char *)
1260 		    malloc(hp->h_length);
1261 		if (*naddrp == (char *)0)
1262 		    out_of_mem();
1263 		bcopy(*addrp, *naddrp,
1264 			hp->h_length);
1265 		addrp++;
1266 		naddrp++;
1267 	}
1268 	*naddrp = (char *)0;
1269 	if (debug)
1270 		fprintf(stderr, "got host %s\n", hp->h_name);
1271 	return (0);
1272 }
1273 
1274 /*
1275  * Free up an exports list component
1276  */
1277 void
1278 free_exp(ep)
1279 	register struct exportlist *ep;
1280 {
1281 
1282 	if (ep->ex_defdir) {
1283 		free_host(ep->ex_defdir->dp_hosts);
1284 		free((caddr_t)ep->ex_defdir);
1285 	}
1286 	if (ep->ex_fsdir)
1287 		free(ep->ex_fsdir);
1288 	free_dir(ep->ex_dirl);
1289 	free((caddr_t)ep);
1290 }
1291 
1292 /*
1293  * Free hosts.
1294  */
1295 void
1296 free_host(hp)
1297 	register struct hostlist *hp;
1298 {
1299 	register struct hostlist *hp2;
1300 
1301 	while (hp) {
1302 		hp2 = hp;
1303 		hp = hp->ht_next;
1304 		free((caddr_t)hp2);
1305 	}
1306 }
1307 
1308 struct hostlist *
1309 get_ht()
1310 {
1311 	register struct hostlist *hp;
1312 
1313 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1314 	if (hp == (struct hostlist *)0)
1315 		out_of_mem();
1316 	hp->ht_next = (struct hostlist *)0;
1317 	return (hp);
1318 }
1319 
1320 #ifdef ISO
1321 /*
1322  * Translate an iso address.
1323  */
1324 get_isoaddr(cp, grp)
1325 	char *cp;
1326 	struct grouplist *grp;
1327 {
1328 	struct iso_addr *isop;
1329 	struct sockaddr_iso *isoaddr;
1330 
1331 	if (grp->gr_type != GT_NULL)
1332 		return (1);
1333 	if ((isop = iso_addr(cp)) == NULL) {
1334 		syslog(LOG_ERR,
1335 		    "iso_addr failed, ignored");
1336 		return (1);
1337 	}
1338 	isoaddr = (struct sockaddr_iso *)
1339 	    malloc(sizeof (struct sockaddr_iso));
1340 	if (isoaddr == (struct sockaddr_iso *)0)
1341 		out_of_mem();
1342 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1343 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1344 		sizeof (struct iso_addr));
1345 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
1346 	isoaddr->siso_family = AF_ISO;
1347 	grp->gr_type = GT_ISO;
1348 	grp->gr_ptr.gt_isoaddr = isoaddr;
1349 	return (0);
1350 }
1351 #endif	/* ISO */
1352 
1353 /*
1354  * Out of memory, fatal
1355  */
1356 void
1357 out_of_mem()
1358 {
1359 
1360 	syslog(LOG_ERR, "Out of memory");
1361 	exit(2);
1362 }
1363 
1364 /*
1365  * Do the mount syscall with the update flag to push the export info into
1366  * the kernel.
1367  */
1368 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1369 	struct exportlist *ep;
1370 	struct grouplist *grp;
1371 	int exflags;
1372 	struct ucred *anoncrp;
1373 	char *dirp;
1374 	int dirplen;
1375 	struct statfs *fsb;
1376 {
1377 	register char *cp = (char *)0;
1378 	register u_long **addrp;
1379 	int done;
1380 	char savedc;
1381 	struct sockaddr_in sin, imask;
1382 	union {
1383 		struct ufs_args ua;
1384 		struct iso_args ia;
1385 		struct mfs_args ma;
1386 	} args;
1387 	u_long net;
1388 
1389 	args.ua.fspec = 0;
1390 	args.ua.export.ex_flags = exflags;
1391 	args.ua.export.ex_anon = *anoncrp;
1392 	bzero((char *)&sin, sizeof(sin));
1393 	bzero((char *)&imask, sizeof(imask));
1394 	sin.sin_family = AF_INET;
1395 	sin.sin_len = sizeof(sin);
1396 	imask.sin_family = AF_INET;
1397 	imask.sin_len = sizeof(sin);
1398 	if (grp->gr_type == GT_HOST)
1399 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1400 	else
1401 		addrp = (u_long **)0;
1402 	done = FALSE;
1403 	while (!done) {
1404 		switch (grp->gr_type) {
1405 		case GT_HOST:
1406 			if (addrp) {
1407 				sin.sin_addr.s_addr = **addrp;
1408 				args.ua.export.ex_addrlen = sizeof(sin);
1409 			} else
1410 				args.ua.export.ex_addrlen = 0;
1411 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1412 			args.ua.export.ex_masklen = 0;
1413 			break;
1414 		case GT_NET:
1415 			if (grp->gr_ptr.gt_net.nt_mask)
1416 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1417 			else {
1418 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1419 			    if (IN_CLASSA(net))
1420 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1421 			    else if (IN_CLASSB(net))
1422 				imask.sin_addr.s_addr =
1423 				    inet_addr("255.255.0.0");
1424 			    else
1425 				imask.sin_addr.s_addr =
1426 				    inet_addr("255.255.255.0");
1427 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1428 			}
1429 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1430 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1431 			args.ua.export.ex_addrlen = sizeof (sin);
1432 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
1433 			args.ua.export.ex_masklen = sizeof (imask);
1434 			break;
1435 #ifdef ISO
1436 		case GT_ISO:
1437 			args.ua.export.ex_addr =
1438 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1439 			args.ua.export.ex_addrlen =
1440 				sizeof(struct sockaddr_iso);
1441 			args.ua.export.ex_masklen = 0;
1442 			break;
1443 #endif	/* ISO */
1444 		default:
1445 			syslog(LOG_ERR, "Bad grouptype");
1446 			if (cp)
1447 				*cp = savedc;
1448 			return (1);
1449 		};
1450 
1451 		/*
1452 		 * XXX:
1453 		 * Maybe I should just use the fsb->f_mntonname path instead
1454 		 * of looping back up the dirp to the mount point??
1455 		 * Also, needs to know how to export all types of local
1456 		 * exportable file systems and not just MOUNT_UFS.
1457 		 */
1458 		while (mount(fsb->f_type, dirp,
1459 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1460 			if (cp)
1461 				*cp-- = savedc;
1462 			else
1463 				cp = dirp + dirplen - 1;
1464 			if (errno == EPERM) {
1465 				syslog(LOG_ERR,
1466 				   "Can't change attributes for %s.\n", dirp);
1467 				return (1);
1468 			}
1469 			if (opt_flags & OP_ALLDIRS) {
1470 				syslog(LOG_ERR, "Not root dir");
1471 				return (1);
1472 			}
1473 			/* back up over the last component */
1474 			while (*cp == '/' && cp > dirp)
1475 				cp--;
1476 			while (*(cp - 1) != '/' && cp > dirp)
1477 				cp--;
1478 			if (cp == dirp) {
1479 				if (debug)
1480 					fprintf(stderr,"mnt unsucc\n");
1481 				syslog(LOG_ERR, "Can't export %s", dirp);
1482 				return (1);
1483 			}
1484 			savedc = *cp;
1485 			*cp = '\0';
1486 		}
1487 		if (addrp) {
1488 			++addrp;
1489 			if (*addrp == (u_long *)0)
1490 				done = TRUE;
1491 		} else
1492 			done = TRUE;
1493 	}
1494 	if (cp)
1495 		*cp = savedc;
1496 	return (0);
1497 }
1498 
1499 /*
1500  * Translate a net address.
1501  */
1502 get_net(cp, net, maskflg)
1503 	char *cp;
1504 	struct netmsk *net;
1505 	int maskflg;
1506 {
1507 	register struct netent *np;
1508 	register long netaddr;
1509 	struct in_addr inetaddr, inetaddr2;
1510 	char *name;
1511 
1512 	if (np = getnetbyname(cp))
1513 		inetaddr = inet_makeaddr(np->n_net, 0);
1514 	else if (isdigit(*cp)) {
1515 		if ((netaddr = inet_network(cp)) == -1)
1516 			return (1);
1517 		inetaddr = inet_makeaddr(netaddr, 0);
1518 		/*
1519 		 * Due to arbritrary subnet masks, you don't know how many
1520 		 * bits to shift the address to make it into a network,
1521 		 * however you do know how to make a network address into
1522 		 * a host with host == 0 and then compare them.
1523 		 * (What a pest)
1524 		 */
1525 		if (!maskflg) {
1526 			setnetent(0);
1527 			while (np = getnetent()) {
1528 				inetaddr2 = inet_makeaddr(np->n_net, 0);
1529 				if (inetaddr2.s_addr == inetaddr.s_addr)
1530 					break;
1531 			}
1532 			endnetent();
1533 		}
1534 	} else
1535 		return (1);
1536 	if (maskflg)
1537 		net->nt_mask = inetaddr.s_addr;
1538 	else {
1539 		if (np)
1540 			name = np->n_name;
1541 		else
1542 			name = inet_ntoa(inetaddr);
1543 		net->nt_name = (char *)malloc(strlen(name) + 1);
1544 		if (net->nt_name == (char *)0)
1545 			out_of_mem();
1546 		strcpy(net->nt_name, name);
1547 		net->nt_net = inetaddr.s_addr;
1548 	}
1549 	return (0);
1550 }
1551 
1552 /*
1553  * Parse out the next white space separated field
1554  */
1555 void
1556 nextfield(cp, endcp)
1557 	char **cp;
1558 	char **endcp;
1559 {
1560 	register char *p;
1561 
1562 	p = *cp;
1563 	while (*p == ' ' || *p == '\t')
1564 		p++;
1565 	if (*p == '\n' || *p == '\0')
1566 		*cp = *endcp = p;
1567 	else {
1568 		*cp = p++;
1569 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1570 			p++;
1571 		*endcp = p;
1572 	}
1573 }
1574 
1575 /*
1576  * Get an exports file line. Skip over blank lines and handle line
1577  * continuations.
1578  */
1579 get_line()
1580 {
1581 	register char *p, *cp;
1582 	register int len;
1583 	int totlen, cont_line;
1584 
1585 	/*
1586 	 * Loop around ignoring blank lines and getting all continuation lines.
1587 	 */
1588 	p = line;
1589 	totlen = 0;
1590 	do {
1591 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1592 			return (0);
1593 		len = strlen(p);
1594 		cp = p + len - 1;
1595 		cont_line = 0;
1596 		while (cp >= p &&
1597 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1598 			if (*cp == '\\')
1599 				cont_line = 1;
1600 			cp--;
1601 			len--;
1602 		}
1603 		*++cp = '\0';
1604 		if (len > 0) {
1605 			totlen += len;
1606 			if (totlen >= LINESIZ) {
1607 				syslog(LOG_ERR, "Exports line too long");
1608 				exit(2);
1609 			}
1610 			p = cp;
1611 		}
1612 	} while (totlen == 0 || cont_line);
1613 	return (1);
1614 }
1615 
1616 /*
1617  * Parse a description of a credential.
1618  */
1619 parsecred(namelist, cr)
1620 	char *namelist;
1621 	register struct ucred *cr;
1622 {
1623 	register char *name;
1624 	register int cnt;
1625 	char *names;
1626 	struct passwd *pw;
1627 	struct group *gr;
1628 	int ngroups, groups[NGROUPS + 1];
1629 
1630 	/*
1631 	 * Set up the unpriviledged user.
1632 	 */
1633 	cr->cr_ref = 1;
1634 	cr->cr_uid = -2;
1635 	cr->cr_groups[0] = -2;
1636 	cr->cr_ngroups = 1;
1637 	/*
1638 	 * Get the user's password table entry.
1639 	 */
1640 	names = strsep(&namelist, " \t\n");
1641 	name = strsep(&names, ":");
1642 	if (isdigit(*name) || *name == '-')
1643 		pw = getpwuid(atoi(name));
1644 	else
1645 		pw = getpwnam(name);
1646 	/*
1647 	 * Credentials specified as those of a user.
1648 	 */
1649 	if (names == NULL) {
1650 		if (pw == NULL) {
1651 			syslog(LOG_ERR, "Unknown user: %s\n", name);
1652 			return;
1653 		}
1654 		cr->cr_uid = pw->pw_uid;
1655 		ngroups = NGROUPS + 1;
1656 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1657 			syslog(LOG_ERR, "Too many groups\n");
1658 		/*
1659 		 * Convert from int's to gid_t's and compress out duplicate
1660 		 */
1661 		cr->cr_ngroups = ngroups - 1;
1662 		cr->cr_groups[0] = groups[0];
1663 		for (cnt = 2; cnt < ngroups; cnt++)
1664 			cr->cr_groups[cnt - 1] = groups[cnt];
1665 		return;
1666 	}
1667 	/*
1668 	 * Explicit credential specified as a colon separated list:
1669 	 *	uid:gid:gid:...
1670 	 */
1671 	if (pw != NULL)
1672 		cr->cr_uid = pw->pw_uid;
1673 	else if (isdigit(*name) || *name == '-')
1674 		cr->cr_uid = atoi(name);
1675 	else {
1676 		syslog(LOG_ERR, "Unknown user: %s\n", name);
1677 		return;
1678 	}
1679 	cr->cr_ngroups = 0;
1680 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1681 		name = strsep(&names, ":");
1682 		if (isdigit(*name) || *name == '-') {
1683 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1684 		} else {
1685 			if ((gr = getgrnam(name)) == NULL) {
1686 				syslog(LOG_ERR, "Unknown group: %s\n", name);
1687 				continue;
1688 			}
1689 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1690 		}
1691 	}
1692 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1693 		syslog(LOG_ERR, "Too many groups\n");
1694 }
1695 
1696 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1697 /*
1698  * Routines that maintain the remote mounttab
1699  */
1700 void
1701 get_mountlist()
1702 {
1703 	register struct mountlist *mlp, **mlpp;
1704 	register char *eos, *dirp;
1705 	int len;
1706 	char str[STRSIZ];
1707 	FILE *mlfile;
1708 
1709 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1710 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1711 		return;
1712 	}
1713 	mlpp = &mlhead;
1714 	while (fgets(str, STRSIZ, mlfile) != NULL) {
1715 		if ((dirp = index(str, '\t')) == NULL &&
1716 		    (dirp = index(str, ' ')) == NULL)
1717 			continue;
1718 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1719 		len = dirp-str;
1720 		if (len > RPCMNT_NAMELEN)
1721 			len = RPCMNT_NAMELEN;
1722 		bcopy(str, mlp->ml_host, len);
1723 		mlp->ml_host[len] = '\0';
1724 		while (*dirp == '\t' || *dirp == ' ')
1725 			dirp++;
1726 		if ((eos = index(dirp, '\t')) == NULL &&
1727 		    (eos = index(dirp, ' ')) == NULL &&
1728 		    (eos = index(dirp, '\n')) == NULL)
1729 			len = strlen(dirp);
1730 		else
1731 			len = eos-dirp;
1732 		if (len > RPCMNT_PATHLEN)
1733 			len = RPCMNT_PATHLEN;
1734 		bcopy(dirp, mlp->ml_dirp, len);
1735 		mlp->ml_dirp[len] = '\0';
1736 		mlp->ml_next = (struct mountlist *)0;
1737 		*mlpp = mlp;
1738 		mlpp = &mlp->ml_next;
1739 	}
1740 	fclose(mlfile);
1741 }
1742 
1743 void
1744 del_mlist(hostp, dirp)
1745 	register char *hostp, *dirp;
1746 {
1747 	register struct mountlist *mlp, **mlpp;
1748 	struct mountlist *mlp2;
1749 	FILE *mlfile;
1750 	int fnd = 0;
1751 
1752 	mlpp = &mlhead;
1753 	mlp = mlhead;
1754 	while (mlp) {
1755 		if (!strcmp(mlp->ml_host, hostp) &&
1756 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1757 			fnd = 1;
1758 			mlp2 = mlp;
1759 			*mlpp = mlp = mlp->ml_next;
1760 			free((caddr_t)mlp2);
1761 		} else {
1762 			mlpp = &mlp->ml_next;
1763 			mlp = mlp->ml_next;
1764 		}
1765 	}
1766 	if (fnd) {
1767 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1768 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1769 			return;
1770 		}
1771 		mlp = mlhead;
1772 		while (mlp) {
1773 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1774 			mlp = mlp->ml_next;
1775 		}
1776 		fclose(mlfile);
1777 	}
1778 }
1779 
1780 void
1781 add_mlist(hostp, dirp)
1782 	register char *hostp, *dirp;
1783 {
1784 	register struct mountlist *mlp, **mlpp;
1785 	FILE *mlfile;
1786 
1787 	mlpp = &mlhead;
1788 	mlp = mlhead;
1789 	while (mlp) {
1790 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1791 			return;
1792 		mlpp = &mlp->ml_next;
1793 		mlp = mlp->ml_next;
1794 	}
1795 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1796 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1797 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1798 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1799 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1800 	mlp->ml_next = (struct mountlist *)0;
1801 	*mlpp = mlp;
1802 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1803 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1804 		return;
1805 	}
1806 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1807 	fclose(mlfile);
1808 }
1809 
1810 /*
1811  * This function is called via. SIGTERM when the system is going down.
1812  * It sends a broadcast RPCMNT_UMNTALL.
1813  */
1814 void
1815 send_umntall()
1816 {
1817 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1818 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1819 	exit(0);
1820 }
1821 
1822 umntall_each(resultsp, raddr)
1823 	caddr_t resultsp;
1824 	struct sockaddr_in *raddr;
1825 {
1826 	return (1);
1827 }
1828 
1829 /*
1830  * Free up a group list.
1831  */
1832 void
1833 free_grp(grp)
1834 	register struct grouplist *grp;
1835 {
1836 	register char **addrp;
1837 
1838 	if (grp->gr_type == GT_HOST) {
1839 		if (grp->gr_ptr.gt_hostent->h_name) {
1840 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1841 			while (addrp && *addrp)
1842 				free(*addrp++);
1843 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1844 			free(grp->gr_ptr.gt_hostent->h_name);
1845 		}
1846 		free((caddr_t)grp->gr_ptr.gt_hostent);
1847 	} else if (grp->gr_type == GT_NET) {
1848 		if (grp->gr_ptr.gt_net.nt_name)
1849 			free(grp->gr_ptr.gt_net.nt_name);
1850 	}
1851 #ifdef ISO
1852 	else if (grp->gr_type == GT_ISO)
1853 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
1854 #endif
1855 	free((caddr_t)grp);
1856 }
1857 
1858 /*
1859  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
1860  *
1861  * find the real name of path, by removing all ".", ".."
1862  * and symlink components.
1863  *
1864  * Jan-Simon Pendry, September 1991.
1865  */
1866 char *
1867 realpath(path, resolved)
1868 	char *path;
1869 	char resolved[MAXPATHLEN];
1870 {
1871 	int d = open(".", O_RDONLY);
1872 	int rootd = 0;
1873 	char *p, *q;
1874 	struct stat stb;
1875 	char wbuf[MAXPATHLEN];
1876 
1877 	strcpy(resolved, path);
1878 
1879 	if (d < 0)
1880 		return 0;
1881 
1882 loop:;
1883 	q = strrchr(resolved, '/');
1884 	if (q) {
1885 		p = q + 1;
1886 		if (q == resolved)
1887 			q = "/";
1888 		else {
1889 			do
1890 				--q;
1891 			while (q > resolved && *q == '/');
1892 			q[1] = '\0';
1893 			q = resolved;
1894 		}
1895 		if (chdir(q) < 0)
1896 			goto out;
1897 	} else
1898 		p = resolved;
1899 
1900 	if (lstat(p, &stb) == 0) {
1901 		if (S_ISLNK(stb.st_mode)) {
1902 			int n = readlink(p, resolved, MAXPATHLEN);
1903 			if (n < 0)
1904 				goto out;
1905 			resolved[n] = '\0';
1906 			goto loop;
1907 		}
1908 		if (S_ISDIR(stb.st_mode)) {
1909 			if (chdir(p) < 0)
1910 				goto out;
1911 			p = "";
1912 		}
1913 	}
1914 
1915 	strcpy(wbuf, p);
1916 	if (getcwd(resolved, MAXPATHLEN) == 0)
1917 		goto out;
1918 	if (resolved[0] == '/' && resolved[1] == '\0')
1919 		rootd = 1;
1920 
1921 	if (*wbuf) {
1922 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
1923 			errno = ENAMETOOLONG;
1924 			goto out;
1925 		}
1926 		if (rootd == 0)
1927 			strcat(resolved, "/");
1928 		strcat(resolved, wbuf);
1929 	}
1930 
1931 	if (fchdir(d) < 0)
1932 		goto out;
1933 	(void) close(d);
1934 
1935 	return resolved;
1936 
1937 out:;
1938 	(void) close(d);
1939 	return 0;
1940 }
1941 
1942 #ifdef DEBUG
1943 void
1944 SYSLOG(int pri, const char *fmt, ...)
1945 {
1946 	va_list ap;
1947 
1948 	va_start(ap, fmt);
1949 	vfprintf(stderr, fmt, ap);
1950 	va_end(ap);
1951 }
1952 #endif /* DEBUG */
1953 
1954 /*
1955  * Check options for consistency.
1956  */
1957 check_options(dp)
1958 	struct dirlist *dp;
1959 {
1960 
1961 	if (dp == (struct dirlist *)0)
1962 	    return (1);
1963 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1964 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1965 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1966 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1967 	    return (1);
1968 	}
1969 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1970 	    syslog(LOG_ERR, "-mask requires -net");
1971 	    return (1);
1972 	}
1973 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1974 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
1975 	    return (1);
1976 	}
1977 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1978 	    syslog(LOG_ERR, "-alldir has multiple directories");
1979 	    return (1);
1980 	}
1981 	return (0);
1982 }
1983 
1984 /*
1985  * Check an absolute directory path for any symbolic links. Return true
1986  * if no symbolic links are found.
1987  */
1988 int
1989 check_dirpath(dirp)
1990 	register char *dirp;
1991 {
1992 	register char *cp;
1993 	int ret = 1;
1994 	struct stat sb;
1995 
1996 	cp = dirp + 1;
1997 	while (*cp && ret) {
1998 		if (*cp == '/') {
1999 			*cp = '\0';
2000 			if (lstat(dirp, &sb) < 0 ||
2001 				(sb.st_mode & S_IFMT) != S_IFDIR)
2002 				ret = 0;
2003 			*cp = '/';
2004 		}
2005 		cp++;
2006 	}
2007 	if (lstat(dirp, &sb) < 0 ||
2008 		(sb.st_mode & S_IFMT) != S_IFDIR)
2009 		ret = 0;
2010 	return (ret);
2011 }
2012