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