mountd.c revision 4895
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
38static 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";*/
45static 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 */
88struct mountlist {
89	struct mountlist *ml_next;
90	char	ml_host[RPCMNT_NAMELEN+1];
91	char	ml_dirp[RPCMNT_PATHLEN+1];
92};
93
94struct 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
104struct 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
115struct netmsk {
116	u_long	nt_net;
117	u_long	nt_mask;
118	char *nt_name;
119};
120
121union grouptypes {
122	struct hostent *gt_hostent;
123	struct netmsk	gt_net;
124#ifdef ISO
125	struct sockaddr_iso *gt_isoaddr;
126#endif
127};
128
129struct 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
140struct hostlist {
141	struct grouplist *ht_grp;
142	struct hostlist	 *ht_next;
143};
144
145/* Global defs */
146char	*add_expdir __P((struct dirlist **, char *, int));
147void	add_dlist __P((struct dirlist **, struct dirlist *,
148				struct grouplist *));
149void	add_mlist __P((char *, char *));
150int	check_dirpath __P((char *));
151int	check_options __P((struct dirlist *));
152int	chk_host __P((struct dirlist *, u_long, int *));
153void	del_mlist __P((char *, char *));
154struct dirlist *dirp_search __P((struct dirlist *, char *));
155int	do_mount __P((struct exportlist *, struct grouplist *, int,
156				struct ucred *, char *, int, struct statfs *));
157int	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
158				int *, int *, struct ucred *));
159struct	exportlist *ex_search __P((fsid_t *));
160struct	exportlist *get_exp __P((void));
161void	free_dir __P((struct dirlist *));
162void	free_exp __P((struct exportlist *));
163void	free_grp __P((struct grouplist *));
164void	free_host __P((struct hostlist *));
165void	get_exportlist __P((void));
166int	get_host __P((char *, struct grouplist *));
167struct hostlist *get_ht __P((void));
168int	get_line __P((void));
169void	get_mountlist __P((void));
170int	get_net __P((char *, struct netmsk *, int));
171void	getexp_err __P((struct exportlist *, struct grouplist *));
172struct grouplist *get_grp __P((void));
173void	hang_dirp __P((struct dirlist *, struct grouplist *,
174				struct exportlist *, int));
175void	mntsrv __P((struct svc_req *, SVCXPRT *));
176void	nextfield __P((char **, char **));
177void	out_of_mem __P((void));
178void	parsecred __P((char *, struct ucred *));
179int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
180int	scan_tree __P((struct dirlist *, u_long));
181void	send_umntall __P((void));
182int	umntall_each __P((caddr_t, struct sockaddr_in *));
183int	xdr_dir __P((XDR *, char *));
184int	xdr_explist __P((XDR *, caddr_t));
185int	xdr_fhs __P((XDR *, nfsv2fh_t *));
186int	xdr_mlist __P((XDR *, caddr_t));
187
188/* C library */
189int	getnetgrent();
190void	endnetgrent();
191void	setnetgrent();
192
193#ifdef ISO
194struct iso_addr *iso_addr();
195#endif
196
197struct exportlist *exphead;
198struct mountlist *mlhead;
199struct grouplist *grphead;
200char exname[MAXPATHLEN];
201struct ucred def_anon = {
202	1,
203	(uid_t) -2,
204	1,
205	{ (gid_t) -2 }
206};
207int root_only = 1;
208int 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
219int debug = 1;
220void	SYSLOG __P((int, const char *, ...));
221#define syslog SYSLOG
222#else
223int 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 */
233int
234main(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 */
312void
313mntsrv(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 */
457int
458xdr_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 */
468int
469xdr_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
480int
481xdr_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 */
510int
511xdr_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);
535errout:
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 */
544int
545put_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
606char line[LINESIZ];
607FILE *exp_file;
608
609/*
610 * Get the export list
611 */
612void
613get_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		}
886nextline:
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 */
898struct exportlist *
899get_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 */
913struct grouplist *
914get_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 */
928void
929getexp_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 */
948struct exportlist *
949ex_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 */
967char *
968add_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 */
989void
990hang_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 */
1030void
1031add_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 */
1075struct dirlist *
1076dirp_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 */
1097int
1098chk_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 */
1138int
1139scan_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 */
1159void
1160free_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 */
1177int
1178do_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 */
1288int
1289get_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 */
1364void
1365free_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 */
1382void
1383free_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
1395struct hostlist *
1396get_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 */
1411get_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 */
1443void
1444out_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 */
1455int
1456do_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 */
1591int
1592get_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 */
1645void
1646nextfield(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 */
1669int
1670get_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 */
1710void
1711parsecred(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 */
1792void
1793get_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
1835void
1836del_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
1872void
1873add_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 */
1906void
1907send_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
1914int
1915umntall_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 */
1925void
1926free_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
1952void
1953SYSLOG(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 */
1966int
1967check_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 */
1998int
1999check_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