xref: /csrg-svn/sbin/mountd/mountd.c (revision 51898)
138460Smckusick /*
238460Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338460Smckusick  * All rights reserved.
438460Smckusick  *
538460Smckusick  * This code is derived from software contributed to Berkeley by
651667Smckusick  * Herb Hasler and Rick Macklem at The University of Guelph.
738460Smckusick  *
842703Sbostic  * %sccs.include.redist.c%
938460Smckusick  */
1038460Smckusick 
1138460Smckusick #ifndef lint
1238460Smckusick char copyright[] =
1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1438460Smckusick  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*51898Smckusick static char sccsid[] = "@(#)mountd.c	5.19 (Berkeley) 12/12/91";
1938460Smckusick #endif not lint
2038460Smckusick 
2151667Smckusick #include <pwd.h>
2251667Smckusick #include <grp.h>
2351667Smckusick #include <unistd.h>
2451667Smckusick #include <stdlib.h>
2551667Smckusick #include <fcntl.h>
2638460Smckusick #include <sys/param.h>
2738460Smckusick #include <sys/ioctl.h>
2838460Smckusick #include <sys/stat.h>
2939681Smckusick #include <sys/file.h>
3051667Smckusick #include <sys/ucred.h>
3138460Smckusick #include <sys/mount.h>
3238460Smckusick #include <sys/socket.h>
3338460Smckusick #include <sys/errno.h>
3442038Sbostic #include <sys/signal.h>
3542038Sbostic #include <stdio.h>
3642038Sbostic #include <string.h>
3742038Sbostic #include <syslog.h>
3838460Smckusick #include <netdb.h>
3938460Smckusick #include <rpc/rpc.h>
4038460Smckusick #include <rpc/pmap_clnt.h>
4138460Smckusick #include <rpc/pmap_prot.h>
4251667Smckusick #ifdef ISO
4351667Smckusick #include <netiso/iso.h>
4451667Smckusick #endif
4538460Smckusick #include <nfs/rpcv2.h>
4638460Smckusick #include <nfs/nfsv2.h>
4739681Smckusick #include "pathnames.h"
4838460Smckusick 
4938460Smckusick /*
5038460Smckusick  * Structures for keeping the mount list and export list
5138460Smckusick  */
5238460Smckusick struct mountlist {
5344015Smckusick 	struct mountlist *ml_next;
5438460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
5538460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
5638460Smckusick };
5738460Smckusick 
58*51898Smckusick struct dirlist {
59*51898Smckusick 	struct dirlist	*dp_left;
60*51898Smckusick 	struct dirlist	*dp_right;
61*51898Smckusick 	int		dp_flag;
62*51898Smckusick 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
63*51898Smckusick 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
64*51898Smckusick };
65*51898Smckusick /* dp_flag bits */
66*51898Smckusick #define	DP_DEFSET	0x1
67*51898Smckusick 
6838460Smckusick struct exportlist {
6938460Smckusick 	struct exportlist *ex_next;
70*51898Smckusick 	struct dirlist	*ex_dirl;
71*51898Smckusick 	struct dirlist	*ex_defdir;
72*51898Smckusick 	int		ex_flag;
73*51898Smckusick 	fsid_t		ex_fs;
74*51898Smckusick 	char		*ex_fsdir;
7538460Smckusick };
76*51898Smckusick /* ex_flag bits */
77*51898Smckusick #define	EX_DONEDEL	0x2
78*51898Smckusick #define	EX_LINKED	0x4
7938460Smckusick 
80*51898Smckusick struct netmsk {
81*51898Smckusick 	u_long	nt_net;
82*51898Smckusick 	u_long	nt_mask;
83*51898Smckusick 	char *nt_name;
84*51898Smckusick };
85*51898Smckusick 
8651667Smckusick union grouptypes {
8751667Smckusick 	struct hostent *gt_hostent;
88*51898Smckusick 	struct netmsk	gt_net;
8951667Smckusick #ifdef ISO
9051667Smckusick 	struct sockaddr_iso *gt_isoaddr;
9151667Smckusick #endif
9251667Smckusick };
9351667Smckusick 
9438460Smckusick struct grouplist {
95*51898Smckusick 	int gr_type;
9651667Smckusick 	union grouptypes gr_ptr;
9738460Smckusick 	struct grouplist *gr_next;
9838460Smckusick };
99*51898Smckusick /* Group types */
100*51898Smckusick #define	GT_NULL		0x0
101*51898Smckusick #define	GT_HOST		0x1
102*51898Smckusick #define	GT_NET		0x2
103*51898Smckusick #define	GT_ISO		0x4
10438460Smckusick 
105*51898Smckusick struct hostlist {
106*51898Smckusick 	struct grouplist *ht_grp;
107*51898Smckusick 	struct hostlist	 *ht_next;
10851667Smckusick };
10951667Smckusick 
11038460Smckusick /* Global defs */
11146709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
112*51898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem();
11351667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
114*51898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host();
115*51898Smckusick struct exportlist *ex_search(), *get_exp();
116*51898Smckusick struct grouplist *get_grp();
117*51898Smckusick char *realpath(), *add_expdir();
118*51898Smckusick struct in_addr inet_makeaddr();
119*51898Smckusick char *inet_ntoa();
120*51898Smckusick struct dirlist *dirp_search();
121*51898Smckusick struct hostlist *get_ht();
12251667Smckusick #ifdef ISO
12351667Smckusick struct iso_addr *iso_addr();
12451667Smckusick #endif
125*51898Smckusick struct exportlist *exphead;
12644015Smckusick struct mountlist *mlhead;
127*51898Smckusick struct grouplist *grphead;
12838460Smckusick char exname[MAXPATHLEN];
12951667Smckusick struct ucred def_anon = {
13051667Smckusick 	(u_short) 1,
13151667Smckusick 	(uid_t) -2,
13251667Smckusick 	1,
13351667Smckusick 	(gid_t) -2,
13451667Smckusick };
13544015Smckusick int root_only = 1;
136*51898Smckusick int opt_flags;
137*51898Smckusick /* Bits for above */
138*51898Smckusick #define	OP_MAPROOT	0x01
139*51898Smckusick #define	OP_MAPALL	0x02
140*51898Smckusick #define	OP_KERB		0x04
141*51898Smckusick #define	OP_MASK		0x08
142*51898Smckusick #define	OP_NET		0x10
143*51898Smckusick #define	OP_ISO		0x20
144*51898Smckusick #define	OP_ALLDIRS	0x40
145*51898Smckusick 
14638460Smckusick extern int errno;
14738460Smckusick #ifdef DEBUG
14838460Smckusick int debug = 1;
14951711Smckusick void	SYSLOG __P((int, const char *, ...));
15051711Smckusick #define syslog SYSLOG
15138460Smckusick #else
15238460Smckusick int debug = 0;
15338460Smckusick #endif
15438460Smckusick 
15538460Smckusick /*
15638460Smckusick  * Mountd server for NFS mount protocol as described in:
15739681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
15844015Smckusick  * The optional arguments are the exports file name
15939681Smckusick  * default: _PATH_EXPORTS
16044015Smckusick  * and "-n" to allow nonroot mount.
16138460Smckusick  */
16238460Smckusick main(argc, argv)
16338460Smckusick 	int argc;
16444015Smckusick 	char **argv;
16538460Smckusick {
16638460Smckusick 	SVCXPRT *transp;
16744015Smckusick 	int c;
16844015Smckusick 	extern int optind;
16944015Smckusick 	extern char *optarg;
17038460Smckusick 
17144015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
17244015Smckusick 		switch (c) {
17344015Smckusick 		case 'n':
17444015Smckusick 			root_only = 0;
17544015Smckusick 			break;
17644015Smckusick 		default:
17744015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
17844015Smckusick 			exit(1);
17944015Smckusick 		};
18044015Smckusick 	argc -= optind;
18144015Smckusick 	argv += optind;
182*51898Smckusick 	grphead = (struct grouplist *)0;
183*51898Smckusick 	exphead = (struct exportlist *)0;
18444015Smckusick 	mlhead = (struct mountlist *)0;
18544015Smckusick 	if (argc == 1) {
18644015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
18744015Smckusick 		exname[MAXPATHLEN-1] = '\0';
18844015Smckusick 	} else
18944015Smckusick 		strcpy(exname, _PATH_EXPORTS);
19044338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
19151667Smckusick 	if (debug)
19251667Smckusick 		fprintf(stderr,"Getting export list.\n");
19344015Smckusick 	get_exportlist();
19451667Smckusick 	if (debug)
19551667Smckusick 		fprintf(stderr,"Getting mount list.\n");
19644015Smckusick 	get_mountlist();
19751667Smckusick 	if (debug)
19851667Smckusick 		fprintf(stderr,"Here we go.\n");
19938460Smckusick 	if (debug == 0) {
20044690Skarels 		daemon(0, 0);
20138460Smckusick 		signal(SIGINT, SIG_IGN);
20238460Smckusick 		signal(SIGQUIT, SIG_IGN);
20338460Smckusick 	}
20438460Smckusick 	signal(SIGHUP, get_exportlist);
20544015Smckusick 	signal(SIGTERM, send_umntall);
20640494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
20740494Smckusick 	  if (pidfile != NULL) {
20840494Smckusick 		fprintf(pidfile, "%d\n", getpid());
20940494Smckusick 		fclose(pidfile);
21040494Smckusick 	  }
21140494Smckusick 	}
21238460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
21338460Smckusick 		syslog(LOG_ERR, "Can't create socket");
21438460Smckusick 		exit(1);
21538460Smckusick 	}
21638460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
21751667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
21851667Smckusick 	    IPPROTO_UDP)) {
21938460Smckusick 		syslog(LOG_ERR, "Can't register mount");
22038460Smckusick 		exit(1);
22138460Smckusick 	}
22238460Smckusick 	svc_run();
22338460Smckusick 	syslog(LOG_ERR, "Mountd died");
22444690Skarels 	exit(1);
22538460Smckusick }
22638460Smckusick 
22738460Smckusick /*
22838460Smckusick  * The mount rpc service
22938460Smckusick  */
23038460Smckusick mntsrv(rqstp, transp)
23138460Smckusick 	register struct svc_req *rqstp;
23238460Smckusick 	register SVCXPRT *transp;
23338460Smckusick {
23438460Smckusick 	register struct exportlist *ep;
235*51898Smckusick 	register struct dirlist *dp;
23638460Smckusick 	nfsv2fh_t nfh;
23738460Smckusick 	struct authunix_parms *ucr;
23838460Smckusick 	struct stat stb;
239*51898Smckusick 	struct statfs fsb;
24038460Smckusick 	struct hostent *hp;
24139681Smckusick 	u_long saddr;
24251667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
243*51898Smckusick 	int bad = ENOENT, omask, defset;
24439681Smckusick 	uid_t uid = -2;
24538460Smckusick 
24638460Smckusick 	/* Get authorization */
24738460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
24838460Smckusick 	case AUTH_UNIX:
24938460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
25039681Smckusick 		uid = ucr->aup_uid;
25139681Smckusick 		break;
25238460Smckusick 	case AUTH_NULL:
25338460Smckusick 	default:
25439681Smckusick 		break;
25538460Smckusick 	}
25638460Smckusick 
25739681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
25839681Smckusick 	hp = (struct hostent *)0;
25938460Smckusick 	switch (rqstp->rq_proc) {
26039681Smckusick 	case NULLPROC:
26139681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
26239681Smckusick 			syslog(LOG_ERR, "Can't send reply");
26339681Smckusick 		return;
26438460Smckusick 	case RPCMNT_MOUNT:
26551667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
26639681Smckusick 			svcerr_weakauth(transp);
26739681Smckusick 			return;
26839681Smckusick 		}
26951667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
27038460Smckusick 			svcerr_decode(transp);
27138460Smckusick 			return;
27238460Smckusick 		}
27338460Smckusick 
27451667Smckusick 		/*
27551667Smckusick 		 * Get the real pathname and make sure it is a directory
27651667Smckusick 		 * that exists.
27751667Smckusick 		 */
278*51898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
279*51898Smckusick 		    stat(dirpath, &stb) < 0 ||
280*51898Smckusick 		    (stb.st_mode & S_IFMT) != S_IFDIR ||
281*51898Smckusick 		    statfs(dirpath, &fsb) < 0) {
28251667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
28351667Smckusick 			if (debug)
284*51898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
28538460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
28638460Smckusick 				syslog(LOG_ERR, "Can't send reply");
28738460Smckusick 			return;
28838460Smckusick 		}
28938460Smckusick 
29038460Smckusick 		/* Check in the exports list */
29138460Smckusick 		omask = sigblock(sigmask(SIGHUP));
292*51898Smckusick 		ep = ex_search(&fsb.f_fsid);
293*51898Smckusick 		defset = 0;
294*51898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
295*51898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
296*51898Smckusick 		     chk_host(dp, saddr, &defset)) ||
297*51898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
298*51898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
29951667Smckusick 			/* Get the file handle */
30051667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
30151667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
30251667Smckusick 				bad = errno;
303*51898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
30451667Smckusick 				if (!svc_sendreply(transp, xdr_long,
30551667Smckusick 				    (caddr_t)&bad))
30651667Smckusick 					syslog(LOG_ERR, "Can't send reply");
30751667Smckusick 				sigsetmask(omask);
30851667Smckusick 				return;
30951667Smckusick 			}
31051667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
31138460Smckusick 				syslog(LOG_ERR, "Can't send reply");
31251667Smckusick 			if (hp == NULL)
31351667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
31451667Smckusick 				    sizeof(saddr), AF_INET);
31551667Smckusick 			if (hp)
31651667Smckusick 				add_mlist(hp->h_name, dirpath);
31751667Smckusick 			else
31851667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
31951667Smckusick 					dirpath);
32051667Smckusick 			if (debug)
32151667Smckusick 				fprintf(stderr,"Mount successfull.\n");
322*51898Smckusick 		} else {
323*51898Smckusick 			bad = EACCES;
324*51898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
325*51898Smckusick 				syslog(LOG_ERR, "Can't send reply");
32638460Smckusick 		}
32751667Smckusick 		sigsetmask(omask);
32838460Smckusick 		return;
32938460Smckusick 	case RPCMNT_DUMP:
33038460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
33138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
33238460Smckusick 		return;
33338460Smckusick 	case RPCMNT_UMOUNT:
33451667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
33539681Smckusick 			svcerr_weakauth(transp);
33639681Smckusick 			return;
33739681Smckusick 		}
33838460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
33938460Smckusick 			svcerr_decode(transp);
34038460Smckusick 			return;
34138460Smckusick 		}
34238460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
34338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
34444015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
34544015Smckusick 		if (hp)
34644015Smckusick 			del_mlist(hp->h_name, dirpath);
34751667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
34838460Smckusick 		return;
34938460Smckusick 	case RPCMNT_UMNTALL:
35051667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
35139681Smckusick 			svcerr_weakauth(transp);
35239681Smckusick 			return;
35339681Smckusick 		}
35438460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
35538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
35644015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
35744015Smckusick 		if (hp)
35844015Smckusick 			del_mlist(hp->h_name, (char *)0);
35951667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
36038460Smckusick 		return;
36138460Smckusick 	case RPCMNT_EXPORT:
36238460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
36338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36438460Smckusick 		return;
36538460Smckusick 	default:
36638460Smckusick 		svcerr_noproc(transp);
36738460Smckusick 		return;
36838460Smckusick 	}
36938460Smckusick }
37038460Smckusick 
37138460Smckusick /*
37238460Smckusick  * Xdr conversion for a dirpath string
37338460Smckusick  */
37438460Smckusick xdr_dir(xdrsp, dirp)
37538460Smckusick 	XDR *xdrsp;
37638460Smckusick 	char *dirp;
37738460Smckusick {
37838460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
37938460Smckusick }
38038460Smckusick 
38138460Smckusick /*
38238460Smckusick  * Xdr routine to generate fhstatus
38338460Smckusick  */
38438460Smckusick xdr_fhs(xdrsp, nfh)
38538460Smckusick 	XDR *xdrsp;
38638460Smckusick 	nfsv2fh_t *nfh;
38738460Smckusick {
38838460Smckusick 	int ok = 0;
38938460Smckusick 
39038460Smckusick 	if (!xdr_long(xdrsp, &ok))
39138460Smckusick 		return (0);
39238460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
39338460Smckusick }
39438460Smckusick 
39538460Smckusick xdr_mlist(xdrsp, cp)
39638460Smckusick 	XDR *xdrsp;
39738460Smckusick 	caddr_t cp;
39838460Smckusick {
39944015Smckusick 	register struct mountlist *mlp;
40038460Smckusick 	int true = 1;
40138460Smckusick 	int false = 0;
40238460Smckusick 	char *strp;
40338460Smckusick 
40444015Smckusick 	mlp = mlhead;
40544015Smckusick 	while (mlp) {
40644015Smckusick 		if (!xdr_bool(xdrsp, &true))
40744015Smckusick 			return (0);
40844015Smckusick 		strp = &mlp->ml_host[0];
40944015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
41044015Smckusick 			return (0);
41144015Smckusick 		strp = &mlp->ml_dirp[0];
41244015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
41344015Smckusick 			return (0);
41444015Smckusick 		mlp = mlp->ml_next;
41538460Smckusick 	}
41638460Smckusick 	if (!xdr_bool(xdrsp, &false))
41738460Smckusick 		return (0);
41838460Smckusick 	return (1);
41938460Smckusick }
42038460Smckusick 
42138460Smckusick /*
42238460Smckusick  * Xdr conversion for export list
42338460Smckusick  */
42438460Smckusick xdr_explist(xdrsp, cp)
42538460Smckusick 	XDR *xdrsp;
42638460Smckusick 	caddr_t cp;
42738460Smckusick {
42838460Smckusick 	register struct exportlist *ep;
42938460Smckusick 	int false = 0;
43038460Smckusick 	int omask;
43138460Smckusick 
43238460Smckusick 	omask = sigblock(sigmask(SIGHUP));
433*51898Smckusick 	ep = exphead;
434*51898Smckusick 	while (ep) {
435*51898Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir))
43638460Smckusick 			goto errout;
43738460Smckusick 		ep = ep->ex_next;
43838460Smckusick 	}
43938460Smckusick 	sigsetmask(omask);
44038460Smckusick 	if (!xdr_bool(xdrsp, &false))
44138460Smckusick 		return (0);
44238460Smckusick 	return (1);
44338460Smckusick errout:
44438460Smckusick 	sigsetmask(omask);
44538460Smckusick 	return (0);
44638460Smckusick }
44738460Smckusick 
448*51898Smckusick /*
449*51898Smckusick  * Called from xdr_explist() to traverse the tree and export the
450*51898Smckusick  * directory paths.
451*51898Smckusick  */
452*51898Smckusick put_exlist(dp, xdrsp, adp)
453*51898Smckusick 	register struct dirlist *dp;
454*51898Smckusick 	XDR *xdrsp;
455*51898Smckusick 	struct dirlist *adp;
456*51898Smckusick {
457*51898Smckusick 	register struct grouplist *grp;
458*51898Smckusick 	register struct hostlist *hp;
459*51898Smckusick 	struct in_addr inaddr;
460*51898Smckusick 	int true = 1;
461*51898Smckusick 	int false = 0;
462*51898Smckusick 	int gotalldir = 0;
463*51898Smckusick 	char *strp;
464*51898Smckusick 
465*51898Smckusick 	if (dp) {
466*51898Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp))
467*51898Smckusick 			return (1);
468*51898Smckusick 		if (!xdr_bool(xdrsp, &true))
469*51898Smckusick 			return (1);
470*51898Smckusick 		strp = dp->dp_dirp;
471*51898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
472*51898Smckusick 			return (1);
473*51898Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp))
474*51898Smckusick 			gotalldir = 1;
475*51898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
476*51898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
477*51898Smckusick 			hp = dp->dp_hosts;
478*51898Smckusick 			while (hp) {
479*51898Smckusick 				grp = hp->ht_grp;
480*51898Smckusick 				if (grp->gr_type == GT_HOST) {
481*51898Smckusick 					if (!xdr_bool(xdrsp, &true))
482*51898Smckusick 						return (1);
483*51898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
484*51898Smckusick 					if (!xdr_string(xdrsp, &strp,
485*51898Smckusick 					    RPCMNT_NAMELEN))
486*51898Smckusick 						return (1);
487*51898Smckusick 				} else if (grp->gr_type == GT_NET) {
488*51898Smckusick 					if (!xdr_bool(xdrsp, &true))
489*51898Smckusick 						return (1);
490*51898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
491*51898Smckusick 					if (!xdr_string(xdrsp, &strp,
492*51898Smckusick 					    RPCMNT_NAMELEN))
493*51898Smckusick 						return (1);
494*51898Smckusick 				}
495*51898Smckusick 				hp = hp->ht_next;
496*51898Smckusick 				if (gotalldir && hp == (struct hostlist *)0) {
497*51898Smckusick 					hp = adp->dp_hosts;
498*51898Smckusick 					gotalldir = 0;
499*51898Smckusick 				}
500*51898Smckusick 			}
501*51898Smckusick 		}
502*51898Smckusick 		if (!xdr_bool(xdrsp, &false))
503*51898Smckusick 			return (1);
504*51898Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp))
505*51898Smckusick 			return (1);
506*51898Smckusick 	}
507*51898Smckusick 	return (0);
508*51898Smckusick }
509*51898Smckusick 
51038460Smckusick #define LINESIZ	10240
51138460Smckusick char line[LINESIZ];
512*51898Smckusick FILE *exp_file;
51338460Smckusick 
51438460Smckusick /*
51538460Smckusick  * Get the export list
51638460Smckusick  */
51746709Sbostic void
51838460Smckusick get_exportlist()
51938460Smckusick {
52038460Smckusick 	register struct exportlist *ep, *ep2;
521*51898Smckusick 	register struct grouplist *grp, *tgrp;
522*51898Smckusick 	struct exportlist **epp;
523*51898Smckusick 	struct dirlist *dirhead;
524*51898Smckusick 	struct stat sb;
525*51898Smckusick 	struct statfs fsb;
526*51898Smckusick 	struct hostent *hpe;
527*51898Smckusick 	struct ucred anon;
528*51898Smckusick 	char *cp, *endcp, *dirp;
52939681Smckusick 	char savedc;
530*51898Smckusick 	int len, has_host, exflags, got_nondir, dirplen;
53138460Smckusick 
53238460Smckusick 	/*
53338460Smckusick 	 * First, get rid of the old list
53438460Smckusick 	 */
535*51898Smckusick 	ep = exphead;
536*51898Smckusick 	while (ep) {
53738460Smckusick 		ep2 = ep;
53838460Smckusick 		ep = ep->ex_next;
53944015Smckusick 		free_exp(ep2);
54038460Smckusick 	}
541*51898Smckusick 	exphead = (struct exportlist *)0;
54238460Smckusick 
543*51898Smckusick 	grp = grphead;
544*51898Smckusick 	while (grp) {
545*51898Smckusick 		tgrp = grp;
546*51898Smckusick 		grp = grp->gr_next;
547*51898Smckusick 		free_grp(tgrp);
54851667Smckusick 	}
549*51898Smckusick 	grphead = (struct grouplist *)0;
55051667Smckusick 
55138460Smckusick 	/*
55238460Smckusick 	 * Read in the exports file and build the list, calling
55351667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
55438460Smckusick 	 */
555*51898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
55638460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
55738460Smckusick 		exit(2);
55838460Smckusick 	}
559*51898Smckusick 	dirhead = (struct dirlist *)0;
560*51898Smckusick 	while (get_line()) {
56151667Smckusick 		if (debug)
56251667Smckusick 			fprintf(stderr,"Got line %s\n",line);
56338460Smckusick 		cp = line;
56438460Smckusick 		nextfield(&cp, &endcp);
56551667Smckusick 		if (*cp == '#')
56651667Smckusick 			goto nextline;
567*51898Smckusick 
568*51898Smckusick 		/*
569*51898Smckusick 		 * Set defaults.
570*51898Smckusick 		 */
571*51898Smckusick 		has_host = FALSE;
572*51898Smckusick 		anon = def_anon;
57351667Smckusick 		exflags = MNT_EXPORTED;
574*51898Smckusick 		got_nondir = 0;
575*51898Smckusick 		opt_flags = 0;
576*51898Smckusick 		ep = (struct exportlist *)0;
57744015Smckusick 
57844015Smckusick 		/*
57944015Smckusick 		 * Create new exports list entry
58044015Smckusick 		 */
58138460Smckusick 		len = endcp-cp;
582*51898Smckusick 		grp = get_grp();
583*51898Smckusick 		while (len > 0) {
584*51898Smckusick 			if (len > RPCMNT_NAMELEN) {
585*51898Smckusick 			    getexp_err(ep, grp);
586*51898Smckusick 			    goto nextline;
58751667Smckusick 			}
58845271Smckusick 			if (*cp == '-') {
589*51898Smckusick 			    if (ep == (struct exportlist *)0) {
590*51898Smckusick 				getexp_err(ep, grp);
591*51898Smckusick 				goto nextline;
592*51898Smckusick 			    }
593*51898Smckusick 			    if (debug)
594*51898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
595*51898Smckusick 			    got_nondir = 1;
596*51898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
597*51898Smckusick 				&exflags, &anon)) {
598*51898Smckusick 				getexp_err(ep, grp);
599*51898Smckusick 				goto nextline;
600*51898Smckusick 			    }
601*51898Smckusick 			} else if (*cp == '/') {
602*51898Smckusick 			    savedc = *endcp;
603*51898Smckusick 			    *endcp = '\0';
604*51898Smckusick 			    if (stat(cp, &sb) >= 0 &&
605*51898Smckusick 				(sb.st_mode & S_IFMT) == S_IFDIR &&
606*51898Smckusick 				statfs(cp, &fsb) >= 0) {
607*51898Smckusick 				if (got_nondir) {
608*51898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
609*51898Smckusick 				    getexp_err(ep, grp);
610*51898Smckusick 				    goto nextline;
611*51898Smckusick 				}
612*51898Smckusick 				if (ep) {
613*51898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
614*51898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
615*51898Smckusick 					getexp_err(ep, grp);
616*51898Smckusick 					goto nextline;
617*51898Smckusick 				    }
61851667Smckusick 				} else {
619*51898Smckusick 				    /*
620*51898Smckusick 				     * See if this directory is already
621*51898Smckusick 				     * in the list.
622*51898Smckusick 				     */
623*51898Smckusick 				    ep = ex_search(&fsb.f_fsid);
624*51898Smckusick 				    if (ep == (struct exportlist *)0) {
625*51898Smckusick 					ep = get_exp();
626*51898Smckusick 					ep->ex_fs = fsb.f_fsid;
627*51898Smckusick 					ep->ex_fsdir = (char *)
628*51898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
629*51898Smckusick 					if (ep->ex_fsdir)
630*51898Smckusick 					    strcpy(ep->ex_fsdir,
631*51898Smckusick 						fsb.f_mntonname);
632*51898Smckusick 					else
633*51898Smckusick 					    out_of_mem();
634*51898Smckusick 					if (debug)
635*51898Smckusick 					  fprintf(stderr,
636*51898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
637*51898Smckusick 					      fsb.f_fsid.val[0],
638*51898Smckusick 					      fsb.f_fsid.val[1]);
639*51898Smckusick 				    } else if (debug)
640*51898Smckusick 					fprintf(stderr,
641*51898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
642*51898Smckusick 					    fsb.f_fsid.val[0],
643*51898Smckusick 					    fsb.f_fsid.val[1]);
64438460Smckusick 				}
645*51898Smckusick 
646*51898Smckusick 				/*
647*51898Smckusick 				 * Add dirpath to export mount point.
648*51898Smckusick 				 */
649*51898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
650*51898Smckusick 				dirplen = len;
651*51898Smckusick 			    } else {
652*51898Smckusick 				getexp_err(ep, grp);
653*51898Smckusick 				goto nextline;
654*51898Smckusick 			    }
655*51898Smckusick 			    *endcp = savedc;
656*51898Smckusick 			} else {
657*51898Smckusick 			    savedc = *endcp;
658*51898Smckusick 			    *endcp = '\0';
659*51898Smckusick 			    got_nondir = 1;
660*51898Smckusick 			    if (ep == (struct exportlist *)0 || has_host) {
661*51898Smckusick 				getexp_err(ep, grp);
662*51898Smckusick 				goto nextline;
663*51898Smckusick 			    }
664*51898Smckusick 			    if (get_host(cp, grp)) {
665*51898Smckusick 				getexp_err(ep, grp);
666*51898Smckusick 				goto nextline;
667*51898Smckusick 			    }
668*51898Smckusick 			    has_host = TRUE;
669*51898Smckusick 			    *endcp = savedc;
67038460Smckusick 			}
67138460Smckusick 			cp = endcp;
67238460Smckusick 			nextfield(&cp, &endcp);
67345271Smckusick 			len = endcp - cp;
67438460Smckusick 		}
675*51898Smckusick 		if (check_options(dirhead)) {
676*51898Smckusick 			getexp_err(ep, grp);
677*51898Smckusick 			goto nextline;
678*51898Smckusick 		}
679*51898Smckusick 		if (!has_host) {
680*51898Smckusick 			grp->gr_type = GT_HOST;
68151667Smckusick 			if (debug)
68251667Smckusick 				fprintf(stderr,"Adding a default entry\n");
68351667Smckusick 			/* add a default group and make the grp list NULL */
68451667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
685*51898Smckusick 			if (hpe == (struct hostent *)0)
686*51898Smckusick 				out_of_mem();
687*51898Smckusick 			hpe->h_name = "Default";
68851667Smckusick 			hpe->h_addrtype = AF_INET;
68951667Smckusick 			hpe->h_length = sizeof (u_long);
69051712Smckusick 			hpe->h_addr_list = (char **)0;
691*51898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
69251667Smckusick 		}
693*51898Smckusick 		if (do_mount(ep, grp, exflags, &anon, dirp,
694*51898Smckusick 			dirplen, &fsb)) {
695*51898Smckusick 			getexp_err(ep, grp);
696*51898Smckusick 			goto nextline;
697*51898Smckusick 		}
698*51898Smckusick 
699*51898Smckusick 		/*
700*51898Smckusick 		 * Success. Update the data structures.
701*51898Smckusick 		 */
702*51898Smckusick 		if (has_host) {
703*51898Smckusick 			grp->gr_next = grphead;
704*51898Smckusick 			grphead = grp;
705*51898Smckusick 			hang_dirp(dirhead, grp, ep, (opt_flags & OP_ALLDIRS));
706*51898Smckusick 		} else {
707*51898Smckusick 			hang_dirp(dirhead, (struct grouplist *)0, ep,
708*51898Smckusick 				(opt_flags & OP_ALLDIRS));
709*51898Smckusick 			free_grp(grp);
710*51898Smckusick 		}
711*51898Smckusick 		dirhead = (struct dirlist *)0;
712*51898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
713*51898Smckusick 			ep2 = exphead;
714*51898Smckusick 			epp = &exphead;
715*51898Smckusick 
716*51898Smckusick 			/*
717*51898Smckusick 			 * Insert in the list in alphabetical order.
718*51898Smckusick 			 */
719*51898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
720*51898Smckusick 				epp = &ep2->ex_next;
721*51898Smckusick 				ep2 = ep2->ex_next;
722*51898Smckusick 			}
723*51898Smckusick 			if (ep2)
724*51898Smckusick 				ep->ex_next = ep2;
725*51898Smckusick 			*epp = ep;
726*51898Smckusick 			ep->ex_flag |= EX_LINKED;
727*51898Smckusick 		}
728*51898Smckusick nextline:
729*51898Smckusick 		if (dirhead) {
730*51898Smckusick 			free_dir(dirhead);
731*51898Smckusick 			dirhead = (struct dirlist *)0;
732*51898Smckusick 		}
733*51898Smckusick 	}
734*51898Smckusick 	fclose(exp_file);
735*51898Smckusick }
736*51898Smckusick 
737*51898Smckusick /*
738*51898Smckusick  * Allocate an export list element
739*51898Smckusick  */
740*51898Smckusick struct exportlist *
741*51898Smckusick get_exp()
742*51898Smckusick {
743*51898Smckusick 	register struct exportlist *ep;
744*51898Smckusick 
745*51898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
746*51898Smckusick 	if (ep == (struct exportlist *)0)
747*51898Smckusick 		out_of_mem();
748*51898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
749*51898Smckusick 	return (ep);
750*51898Smckusick }
751*51898Smckusick 
752*51898Smckusick /*
753*51898Smckusick  * Allocate a group list element
754*51898Smckusick  */
755*51898Smckusick struct grouplist *
756*51898Smckusick get_grp()
757*51898Smckusick {
758*51898Smckusick 	register struct grouplist *gp;
759*51898Smckusick 
760*51898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
761*51898Smckusick 	if (gp == (struct grouplist *)0)
762*51898Smckusick 		out_of_mem();
763*51898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
764*51898Smckusick 	return (gp);
765*51898Smckusick }
766*51898Smckusick 
767*51898Smckusick /*
768*51898Smckusick  * Clean up upon an error in get_exportlist().
769*51898Smckusick  */
770*51898Smckusick void
771*51898Smckusick getexp_err(ep, grp)
772*51898Smckusick 	struct exportlist *ep;
773*51898Smckusick 	struct grouplist *grp;
774*51898Smckusick {
775*51898Smckusick 
776*51898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
777*51898Smckusick 	if (ep && ep->ex_next == (struct exportlist *)0)
778*51898Smckusick 		free_exp(ep);
779*51898Smckusick 	if (grp && grp->gr_next == (struct grouplist *)0)
780*51898Smckusick 		free_grp(grp);
781*51898Smckusick }
782*51898Smckusick 
783*51898Smckusick /*
784*51898Smckusick  * Search the export list for a matching fs.
785*51898Smckusick  */
786*51898Smckusick struct exportlist *
787*51898Smckusick ex_search(fsid)
788*51898Smckusick 	quad *fsid;
789*51898Smckusick {
790*51898Smckusick 	register struct exportlist *ep;
791*51898Smckusick 
792*51898Smckusick 	ep = exphead;
793*51898Smckusick 	while (ep) {
794*51898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
795*51898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
796*51898Smckusick 			return (ep);
797*51898Smckusick 		ep = ep->ex_next;
798*51898Smckusick 	}
799*51898Smckusick 	return (ep);
800*51898Smckusick }
801*51898Smckusick 
802*51898Smckusick /*
803*51898Smckusick  * Add a directory path to the list.
804*51898Smckusick  */
805*51898Smckusick char *
806*51898Smckusick add_expdir(dpp, cp, len)
807*51898Smckusick 	struct dirlist **dpp;
808*51898Smckusick 	char *cp;
809*51898Smckusick 	int len;
810*51898Smckusick {
811*51898Smckusick 	register struct dirlist *dp;
812*51898Smckusick 
813*51898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
814*51898Smckusick 	dp->dp_left = *dpp;
815*51898Smckusick 	dp->dp_right = (struct dirlist *)0;
816*51898Smckusick 	dp->dp_flag = 0;
817*51898Smckusick 	dp->dp_hosts = (struct hostlist *)0;
818*51898Smckusick 	strcpy(dp->dp_dirp, cp);
819*51898Smckusick 	*dpp = dp;
820*51898Smckusick 	return (dp->dp_dirp);
821*51898Smckusick }
822*51898Smckusick 
823*51898Smckusick /*
824*51898Smckusick  * Hang the dir list element off the dirpath binary tree as required
825*51898Smckusick  * and update the entry for host.
826*51898Smckusick  */
827*51898Smckusick void
828*51898Smckusick hang_dirp(dp, grp, ep, alldirs)
829*51898Smckusick 	register struct dirlist *dp;
830*51898Smckusick 	struct grouplist *grp;
831*51898Smckusick 	struct exportlist *ep;
832*51898Smckusick 	int alldirs;
833*51898Smckusick {
834*51898Smckusick 	register struct hostlist *hp;
835*51898Smckusick 	struct dirlist *dp2;
836*51898Smckusick 
837*51898Smckusick 	if (alldirs) {
838*51898Smckusick 		if (ep->ex_defdir)
839*51898Smckusick 			free((caddr_t)dp);
840*51898Smckusick 		else
841*51898Smckusick 			ep->ex_defdir = dp;
842*51898Smckusick 		if (grp) {
843*51898Smckusick 			hp = get_ht();
844*51898Smckusick 			hp->ht_grp = grp;
845*51898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
846*51898Smckusick 			ep->ex_defdir->dp_hosts = hp;
847*51898Smckusick 		} else
848*51898Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
849*51898Smckusick 	} else {
850*51898Smckusick 		while (dp) {
851*51898Smckusick 			if (grp) {
852*51898Smckusick 				hp = get_ht();
853*51898Smckusick 				hp->ht_grp = grp;
854*51898Smckusick 			} else
855*51898Smckusick 				hp = (struct hostlist *)0;
856*51898Smckusick 			dp2 = dp->dp_left;
857*51898Smckusick 			add_dlist(&ep->ex_dirl, dp, hp);
858*51898Smckusick 			dp = dp2;
859*51898Smckusick 		}
860*51898Smckusick 	}
861*51898Smckusick }
862*51898Smckusick 
863*51898Smckusick /*
864*51898Smckusick  * Traverse the binary tree either updating a node that is already there
865*51898Smckusick  * for the new directory or adding the new node.
866*51898Smckusick  */
867*51898Smckusick void
868*51898Smckusick add_dlist(dpp, newdp, hp)
869*51898Smckusick 	struct dirlist **dpp;
870*51898Smckusick 	struct dirlist *newdp;
871*51898Smckusick 	struct hostlist *hp;
872*51898Smckusick {
873*51898Smckusick 	register struct dirlist *dp;
874*51898Smckusick 	int cmp;
875*51898Smckusick 
876*51898Smckusick 	dp = *dpp;
877*51898Smckusick 	if (dp) {
878*51898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
879*51898Smckusick 		if (cmp > 0) {
880*51898Smckusick 			add_dlist(&dp->dp_left, newdp, hp);
881*51898Smckusick 			return;
882*51898Smckusick 		} else if (cmp < 0) {
883*51898Smckusick 			add_dlist(&dp->dp_right, newdp, hp);
884*51898Smckusick 			return;
885*51898Smckusick 		} else
886*51898Smckusick 			free((caddr_t)newdp);
887*51898Smckusick 	} else {
888*51898Smckusick 		dp = newdp;
889*51898Smckusick 		dp->dp_left = (struct dirlist *)0;
890*51898Smckusick 		*dpp = dp;
891*51898Smckusick 	}
892*51898Smckusick 	if (hp) {
893*51898Smckusick 		hp->ht_next = dp->dp_hosts;
894*51898Smckusick 		dp->dp_hosts = hp;
895*51898Smckusick 	} else
896*51898Smckusick 		dp->dp_flag |= DP_DEFSET;
897*51898Smckusick }
898*51898Smckusick 
899*51898Smckusick /*
900*51898Smckusick  * Search for a dirpath on the export point.
901*51898Smckusick  */
902*51898Smckusick struct dirlist *
903*51898Smckusick dirp_search(dp, dirpath)
904*51898Smckusick 	register struct dirlist *dp;
905*51898Smckusick 	char *dirpath;
906*51898Smckusick {
907*51898Smckusick 	register int cmp;
908*51898Smckusick 
909*51898Smckusick 	if (dp) {
910*51898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
911*51898Smckusick 		if (cmp > 0)
912*51898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
913*51898Smckusick 		else if (cmp < 0)
914*51898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
915*51898Smckusick 		else
916*51898Smckusick 			return (dp);
917*51898Smckusick 	}
918*51898Smckusick 	return (dp);
919*51898Smckusick }
920*51898Smckusick 
921*51898Smckusick /*
922*51898Smckusick  * Scan for a host match in a directory tree.
923*51898Smckusick  */
924*51898Smckusick chk_host(dp, saddr, defsetp)
925*51898Smckusick 	struct dirlist *dp;
926*51898Smckusick 	u_long saddr;
927*51898Smckusick 	int *defsetp;
928*51898Smckusick {
929*51898Smckusick 	register struct hostlist *hp;
930*51898Smckusick 	register struct grouplist *grp;
931*51898Smckusick 	register u_long **addrp;
932*51898Smckusick 
933*51898Smckusick 	if (dp) {
934*51898Smckusick 		if (dp->dp_flag & DP_DEFSET)
935*51898Smckusick 			*defsetp = 1;
936*51898Smckusick 		hp = dp->dp_hosts;
937*51898Smckusick 		while (hp) {
938*51898Smckusick 			grp = hp->ht_grp;
939*51898Smckusick 			switch (grp->gr_type) {
940*51898Smckusick 			case GT_HOST:
941*51898Smckusick 			    addrp = (u_long **)
942*51898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
943*51898Smckusick 			    while (*addrp) {
944*51898Smckusick 				if (**addrp == saddr)
945*51898Smckusick 				    return (1);
946*51898Smckusick 				addrp++;
947*51898Smckusick 			    }
948*51898Smckusick 			    break;
949*51898Smckusick 			case GT_NET:
950*51898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
951*51898Smckusick 				grp->gr_ptr.gt_net.nt_net)
952*51898Smckusick 				return (1);
953*51898Smckusick 			    break;
954*51898Smckusick 			};
955*51898Smckusick 			hp = hp->ht_next;
956*51898Smckusick 		}
957*51898Smckusick 	}
958*51898Smckusick 	return (0);
959*51898Smckusick }
960*51898Smckusick 
961*51898Smckusick /*
962*51898Smckusick  * Scan tree for a host that matches the address.
963*51898Smckusick  */
964*51898Smckusick scan_tree(dp, saddr)
965*51898Smckusick 	register struct dirlist *dp;
966*51898Smckusick 	u_long saddr;
967*51898Smckusick {
968*51898Smckusick 	int defset;
969*51898Smckusick 
970*51898Smckusick 	if (dp) {
971*51898Smckusick 		if (scan_tree(dp->dp_left, saddr))
972*51898Smckusick 			return (1);
973*51898Smckusick 		if (chk_host(dp, saddr, &defset))
974*51898Smckusick 			return (1);
975*51898Smckusick 		if (scan_tree(dp->dp_right, saddr))
976*51898Smckusick 			return (1);
977*51898Smckusick 	}
978*51898Smckusick 	return (0);
979*51898Smckusick }
980*51898Smckusick 
981*51898Smckusick /*
982*51898Smckusick  * Traverse the dirlist tree and free it up.
983*51898Smckusick  */
984*51898Smckusick void
985*51898Smckusick free_dir(dp)
986*51898Smckusick 	register struct dirlist *dp;
987*51898Smckusick {
988*51898Smckusick 
989*51898Smckusick 	if (dp) {
990*51898Smckusick 		free_dir(dp->dp_left);
991*51898Smckusick 		free_dir(dp->dp_right);
992*51898Smckusick 		free_host(dp->dp_hosts);
993*51898Smckusick 		free((caddr_t)dp);
994*51898Smckusick 	}
995*51898Smckusick }
996*51898Smckusick 
997*51898Smckusick /*
998*51898Smckusick  * Parse the option string and update fields.
999*51898Smckusick  * Option arguments may either be -<option>=<value> or
1000*51898Smckusick  * -<option> <value>
1001*51898Smckusick  */
1002*51898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1003*51898Smckusick 	char **cpp, **endcpp;
1004*51898Smckusick 	struct exportlist *ep;
1005*51898Smckusick 	struct grouplist *grp;
1006*51898Smckusick 	int *has_hostp;
1007*51898Smckusick 	int *exflagsp;
1008*51898Smckusick 	struct ucred *cr;
1009*51898Smckusick {
1010*51898Smckusick 	register char *cpoptarg, *cpoptend;
1011*51898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
1012*51898Smckusick 	int allflag, usedarg;
1013*51898Smckusick 
1014*51898Smckusick 	cpopt = *cpp;
1015*51898Smckusick 	cpopt++;
1016*51898Smckusick 	cp = *endcpp;
1017*51898Smckusick 	savedc = *cp;
1018*51898Smckusick 	*cp = '\0';
1019*51898Smckusick 	while (cpopt && *cpopt) {
1020*51898Smckusick 		allflag = 1;
1021*51898Smckusick 		usedarg = -2;
1022*51898Smckusick 		if (cpoptend = index(cpopt, ',')) {
1023*51898Smckusick 			*cpoptend++ = '\0';
1024*51898Smckusick 			if (cpoptarg = index(cpopt, '='))
1025*51898Smckusick 				*cpoptarg++ = '\0';
1026*51898Smckusick 		} else {
1027*51898Smckusick 			if (cpoptarg = index(cpopt, '='))
1028*51898Smckusick 				*cpoptarg++ = '\0';
1029*51898Smckusick 			else {
1030*51898Smckusick 				*cp = savedc;
1031*51898Smckusick 				nextfield(&cp, &endcp);
1032*51898Smckusick 				**endcpp = '\0';
1033*51898Smckusick 				if (endcp > cp && *cp != '-') {
1034*51898Smckusick 					cpoptarg = cp;
1035*51898Smckusick 					savedc2 = *endcp;
1036*51898Smckusick 					*endcp = '\0';
1037*51898Smckusick 					usedarg = 0;
103851667Smckusick 				}
103951667Smckusick 			}
104051667Smckusick 		}
1041*51898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1042*51898Smckusick 			*exflagsp |= MNT_EXRDONLY;
1043*51898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1044*51898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
1045*51898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1046*51898Smckusick 			usedarg++;
1047*51898Smckusick 			parsecred(cpoptarg, cr);
1048*51898Smckusick 			if (allflag == 0) {
1049*51898Smckusick 				*exflagsp |= MNT_EXPORTANON;
1050*51898Smckusick 				opt_flags |= OP_MAPALL;
1051*51898Smckusick 			} else
1052*51898Smckusick 				opt_flags |= OP_MAPROOT;
1053*51898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1054*51898Smckusick 			*exflagsp |= MNT_EXKERB;
1055*51898Smckusick 			opt_flags |= OP_KERB;
1056*51898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "mask")) {
1057*51898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1058*51898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1059*51898Smckusick 				return (1);
1060*51898Smckusick 			}
1061*51898Smckusick 			usedarg++;
1062*51898Smckusick 			opt_flags |= OP_MASK;
1063*51898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "network")) {
1064*51898Smckusick 			if (grp->gr_type != GT_NULL) {
1065*51898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
1066*51898Smckusick 				return (1);
1067*51898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1068*51898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1069*51898Smckusick 				return (1);
1070*51898Smckusick 			}
1071*51898Smckusick 			grp->gr_type = GT_NET;
1072*51898Smckusick 			*has_hostp = 1;
1073*51898Smckusick 			usedarg++;
1074*51898Smckusick 			opt_flags |= OP_NET;
1075*51898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
1076*51898Smckusick 			opt_flags |= OP_ALLDIRS;
1077*51898Smckusick #ifdef ISO
1078*51898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1079*51898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
1080*51898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1081*51898Smckusick 				return (1);
1082*51898Smckusick 			}
1083*51898Smckusick 			*has_hostp = 1;
1084*51898Smckusick 			usedarg++;
1085*51898Smckusick 			opt_flags |= OP_ISO;
1086*51898Smckusick #endif /* ISO */
1087*51898Smckusick 		} else {
1088*51898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
1089*51898Smckusick 			return (1);
109051667Smckusick 		}
1091*51898Smckusick 		if (usedarg >= 0) {
1092*51898Smckusick 			*endcp = savedc2;
1093*51898Smckusick 			**endcpp = savedc;
1094*51898Smckusick 			if (usedarg > 0) {
1095*51898Smckusick 				*cpp = cp;
1096*51898Smckusick 				*endcpp = endcp;
1097*51898Smckusick 			}
1098*51898Smckusick 			return (0);
1099*51898Smckusick 		}
1100*51898Smckusick 		cpopt = cpoptend;
110151667Smckusick 	}
1102*51898Smckusick 	**endcpp = savedc;
1103*51898Smckusick 	return (0);
1104*51898Smckusick }
1105*51898Smckusick 
1106*51898Smckusick /*
1107*51898Smckusick  * Translate a character string to the corresponding list of network
1108*51898Smckusick  * addresses for a hostname.
1109*51898Smckusick  */
1110*51898Smckusick get_host(cp, grp)
1111*51898Smckusick 	char *cp;
1112*51898Smckusick 	register struct grouplist *grp;
1113*51898Smckusick {
1114*51898Smckusick 	register struct hostent *hp, *nhp;
1115*51898Smckusick 	register char **addrp, **naddrp;
1116*51898Smckusick 	struct hostent t_host;
1117*51898Smckusick 	int i;
1118*51898Smckusick 	u_long saddr;
1119*51898Smckusick 	char *aptr[2];
1120*51898Smckusick 
1121*51898Smckusick 	if (grp->gr_type != GT_NULL)
1122*51898Smckusick 		return (1);
1123*51898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
1124*51898Smckusick 		if (isdigit(*cp)) {
1125*51898Smckusick 			saddr = inet_addr(cp);
1126*51898Smckusick 			if (saddr == -1) {
1127*51898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
1128*51898Smckusick 				return (1);
1129*51898Smckusick 			}
1130*51898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1131*51898Smckusick 				AF_INET)) == NULL) {
1132*51898Smckusick 				hp = &t_host;
1133*51898Smckusick 				hp->h_name = cp;
1134*51898Smckusick 				hp->h_addrtype = AF_INET;
1135*51898Smckusick 				hp->h_length = sizeof (u_long);
1136*51898Smckusick 				hp->h_addr_list = aptr;
1137*51898Smckusick 				aptr[0] = (char *)&saddr;
1138*51898Smckusick 				aptr[1] = (char *)0;
1139*51898Smckusick 			}
1140*51898Smckusick 		} else {
1141*51898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
1142*51898Smckusick 			return (1);
1143*51898Smckusick 		}
1144*51898Smckusick 	}
1145*51898Smckusick 	grp->gr_type = GT_HOST;
1146*51898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1147*51898Smckusick 		malloc(sizeof(struct hostent));
1148*51898Smckusick 	if (nhp == (struct hostent *)0)
1149*51898Smckusick 		out_of_mem();
1150*51898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
1151*51898Smckusick 		sizeof(struct hostent));
1152*51898Smckusick 	i = strlen(hp->h_name)+1;
1153*51898Smckusick 	nhp->h_name = (char *)malloc(i);
1154*51898Smckusick 	if (nhp->h_name == (char *)0)
1155*51898Smckusick 		out_of_mem();
1156*51898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
1157*51898Smckusick 	addrp = hp->h_addr_list;
1158*51898Smckusick 	i = 1;
1159*51898Smckusick 	while (*addrp++)
1160*51898Smckusick 		i++;
1161*51898Smckusick 	naddrp = nhp->h_addr_list = (char **)
1162*51898Smckusick 		malloc(i*sizeof(char *));
1163*51898Smckusick 	if (naddrp == (char **)0)
1164*51898Smckusick 		out_of_mem();
1165*51898Smckusick 	addrp = hp->h_addr_list;
1166*51898Smckusick 	while (*addrp) {
1167*51898Smckusick 		*naddrp = (char *)
1168*51898Smckusick 		    malloc(hp->h_length);
1169*51898Smckusick 		if (*naddrp == (char *)0)
1170*51898Smckusick 		    out_of_mem();
1171*51898Smckusick 		bcopy(*addrp, *naddrp,
1172*51898Smckusick 			hp->h_length);
1173*51898Smckusick 		addrp++;
1174*51898Smckusick 		naddrp++;
1175*51898Smckusick 	}
1176*51898Smckusick 	*naddrp = (char *)0;
1177*51898Smckusick 	return (0);
1178*51898Smckusick }
1179*51898Smckusick 
1180*51898Smckusick /*
1181*51898Smckusick  * Free up an exports list component
1182*51898Smckusick  */
1183*51898Smckusick void
1184*51898Smckusick free_exp(ep)
1185*51898Smckusick 	register struct exportlist *ep;
1186*51898Smckusick {
1187*51898Smckusick 
1188*51898Smckusick 	if (ep->ex_defdir) {
1189*51898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
1190*51898Smckusick 		free((caddr_t)ep->ex_defdir);
1191*51898Smckusick 	}
1192*51898Smckusick 	if (ep->ex_fsdir)
1193*51898Smckusick 		free(ep->ex_fsdir);
1194*51898Smckusick 	free_dir(ep->ex_dirl);
1195*51898Smckusick 	free((caddr_t)ep);
1196*51898Smckusick }
1197*51898Smckusick 
1198*51898Smckusick /*
1199*51898Smckusick  * Free hosts.
1200*51898Smckusick  */
1201*51898Smckusick void
1202*51898Smckusick free_host(hp)
1203*51898Smckusick 	register struct hostlist *hp;
1204*51898Smckusick {
1205*51898Smckusick 	register struct hostlist *hp2;
1206*51898Smckusick 
1207*51898Smckusick 	while (hp) {
1208*51898Smckusick 		hp2 = hp;
1209*51898Smckusick 		hp = hp->ht_next;
1210*51898Smckusick 		free((caddr_t)hp2);
1211*51898Smckusick 	}
1212*51898Smckusick }
1213*51898Smckusick 
1214*51898Smckusick struct hostlist *
1215*51898Smckusick get_ht()
1216*51898Smckusick {
1217*51898Smckusick 	register struct hostlist *hp;
1218*51898Smckusick 
1219*51898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1220*51898Smckusick 	if (hp == (struct hostlist *)0)
1221*51898Smckusick 		out_of_mem();
1222*51898Smckusick 	hp->ht_next = (struct hostlist *)0;
1223*51898Smckusick 	return (hp);
1224*51898Smckusick }
1225*51898Smckusick 
1226*51898Smckusick #ifdef ISO
1227*51898Smckusick /*
1228*51898Smckusick  * Translate an iso address.
1229*51898Smckusick  */
1230*51898Smckusick get_isoaddr(cp, grp)
1231*51898Smckusick 	char *cp;
1232*51898Smckusick 	struct grouplist *grp;
1233*51898Smckusick {
1234*51898Smckusick 	struct iso_addr *isop;
1235*51898Smckusick 	struct sockaddr_iso *isoaddr;
1236*51898Smckusick 
1237*51898Smckusick 	if (grp->gr_type != GT_NULL)
1238*51898Smckusick 		return (1);
1239*51898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
1240*51898Smckusick 		syslog(LOG_ERR,
1241*51898Smckusick 		    "iso_addr failed, ignored");
1242*51898Smckusick 		return (1);
1243*51898Smckusick 	}
1244*51898Smckusick 	isoaddr = (struct sockaddr_iso *)
1245*51898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
1246*51898Smckusick 	if (isoaddr == (struct sockaddr_iso *)0)
1247*51898Smckusick 		out_of_mem();
1248*51898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1249*51898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1250*51898Smckusick 		sizeof (struct iso_addr));
1251*51898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
1252*51898Smckusick 	isoaddr->siso_family = AF_ISO;
1253*51898Smckusick 	grp->gr_type = GT_ISO;
1254*51898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
1255*51898Smckusick 	return (0);
1256*51898Smckusick }
1257*51898Smckusick #endif	/* ISO */
1258*51898Smckusick 
1259*51898Smckusick /*
1260*51898Smckusick  * Out of memory, fatal
1261*51898Smckusick  */
1262*51898Smckusick void
1263*51898Smckusick out_of_mem()
1264*51898Smckusick {
1265*51898Smckusick 
1266*51898Smckusick 	syslog(LOG_ERR, "Out of memory");
126751667Smckusick 	exit(2);
126851667Smckusick }
126951667Smckusick 
1270*51898Smckusick /*
1271*51898Smckusick  * Do the mount syscall with the update flag to push the export info into
1272*51898Smckusick  * the kernel.
1273*51898Smckusick  */
1274*51898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
127551667Smckusick 	struct exportlist *ep;
127651667Smckusick 	struct grouplist *grp;
1277*51898Smckusick 	int exflags;
127851667Smckusick 	struct ucred *anoncrp;
1279*51898Smckusick 	char *dirp;
1280*51898Smckusick 	int dirplen;
1281*51898Smckusick 	struct statfs *fsb;
128251667Smckusick {
1283*51898Smckusick 	register char *cp = (char *)0;
128451667Smckusick 	register u_long **addrp;
1285*51898Smckusick 	int done;
1286*51898Smckusick 	char savedc;
1287*51898Smckusick 	struct sockaddr_in sin, imask;
128851667Smckusick 	struct ufs_args args, targs;
1289*51898Smckusick 	u_long net;
129051667Smckusick 
129151667Smckusick 	args.fspec = 0;
129251667Smckusick 	args.exflags = exflags;
129351667Smckusick 	args.anon = *anoncrp;
129451667Smckusick 	sin.sin_family = AF_INET;
129551667Smckusick 	sin.sin_port = 0;
129651667Smckusick 	sin.sin_len = sizeof(sin);
1297*51898Smckusick 	imask.sin_family = AF_INET;
1298*51898Smckusick 	imask.sin_port = 0;
1299*51898Smckusick 	imask.sin_len = sizeof(sin);
1300*51898Smckusick 	if (grp->gr_type == GT_HOST)
130151667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1302*51898Smckusick 	else
1303*51898Smckusick 		addrp = (u_long **)0;
130451667Smckusick 	done = FALSE;
1305*51898Smckusick 	while (!done) {
1306*51898Smckusick 		switch (grp->gr_type) {
1307*51898Smckusick 		case GT_HOST:
1308*51898Smckusick 			if (addrp)
130951712Smckusick 				sin.sin_addr.s_addr = **addrp;
131051712Smckusick 			else
131151667Smckusick 				sin.sin_addr.s_addr = INADDR_ANY;
131251667Smckusick 			args.saddr = (struct sockaddr *)&sin;
131351667Smckusick 			args.slen = sizeof(sin);
1314*51898Smckusick 			args.msklen = 0;
1315*51898Smckusick 			break;
1316*51898Smckusick 		case GT_NET:
1317*51898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
1318*51898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1319*51898Smckusick 			else {
1320*51898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1321*51898Smckusick 			    if (IN_CLASSA(net))
1322*51898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1323*51898Smckusick 			    else if (IN_CLASSB(net))
1324*51898Smckusick 				imask.sin_addr.s_addr =
1325*51898Smckusick 				    inet_addr("255.255.0.0");
1326*51898Smckusick 			    else
1327*51898Smckusick 				imask.sin_addr.s_addr =
1328*51898Smckusick 				    inet_addr("255.255.255.0");
1329*51898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1330*51898Smckusick 			}
1331*51898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1332*51898Smckusick 			args.saddr = (struct sockaddr *)&sin;
1333*51898Smckusick 			args.slen = sizeof (sin);
1334*51898Smckusick 			args.smask = (struct sockaddr *)&imask;
1335*51898Smckusick 			args.msklen = sizeof (imask);
1336*51898Smckusick 			break;
133751667Smckusick #ifdef ISO
1338*51898Smckusick 		case GT_ISO:
133951667Smckusick 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
134051667Smckusick 			args.slen = sizeof (struct sockaddr_iso);
1341*51898Smckusick 			args.msklen = 0;
1342*51898Smckusick 			break;
134351667Smckusick #endif	/* ISO */
1344*51898Smckusick 		default:
134551667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
1346*51898Smckusick 			if (cp)
1347*51898Smckusick 				*cp = savedc;
1348*51898Smckusick 			return (1);
1349*51898Smckusick 		};
1350*51898Smckusick 		if ((ep->ex_flag & EX_DONEDEL) == 0) {
1351*51898Smckusick 			/*
1352*51898Smckusick 			 * first time for fs, so must send a MNT_DELEXPORT
135351667Smckusick 			 * to clear the old export list held in the kernel
135451667Smckusick 			 * for this fs.
135551667Smckusick 			 */
135651667Smckusick 			targs.fspec = 0;
135751667Smckusick 			targs.exflags = MNT_DELEXPORT;
1358*51898Smckusick 			while (mount(MOUNT_UFS, dirp,
1359*51898Smckusick 			       fsb->f_flags | MNT_UPDATE, &targs) < 0) {
1360*51898Smckusick 				if (debug)
136151667Smckusick 					fprintf(stderr,
136251667Smckusick 					    "tried [%s][%d]\n",
1363*51898Smckusick 					    dirp,errno);
1364*51898Smckusick 				if (cp)
1365*51898Smckusick 					*cp-- = savedc;
1366*51898Smckusick 				else
1367*51898Smckusick 					cp = dirp + dirplen - 1;
1368*51898Smckusick 				if (opt_flags & OP_ALLDIRS) {
1369*51898Smckusick 					syslog(LOG_ERR, "Not root dir");
1370*51898Smckusick 					return (1);
137151667Smckusick 				}
137244015Smckusick 				/* back up over the last component */
1373*51898Smckusick 				while (*cp == '/' && cp > dirp)
137444015Smckusick 					cp--;
1375*51898Smckusick 				while (*(cp - 1) != '/' && cp > dirp)
137644015Smckusick 					cp--;
1377*51898Smckusick 				if (cp == dirp) {
1378*51898Smckusick 					if (debug)
137951667Smckusick 						fprintf(stderr,"mnt unsucc\n");
138051667Smckusick 					syslog(LOG_ERR,
1381*51898Smckusick 					    "Can't export %s", dirp);
1382*51898Smckusick 					return (1);
138344015Smckusick 				}
138444015Smckusick 				savedc = *cp;
138544015Smckusick 				*cp = '\0';
138644015Smckusick 			}
1387*51898Smckusick 			ep->ex_flag |= EX_DONEDEL;
138838460Smckusick 		}
1389*51898Smckusick 		while (mount(MOUNT_UFS, dirp,
1390*51898Smckusick 		       fsb->f_flags | MNT_UPDATE, &args) < 0) {
1391*51898Smckusick 			if (cp)
1392*51898Smckusick 				*cp-- = savedc;
1393*51898Smckusick 			else
1394*51898Smckusick 				cp = dirp + dirplen - 1;
139551667Smckusick 			if (errno == EPERM) {
139651667Smckusick 				syslog(LOG_ERR,
1397*51898Smckusick 				   "Can't change attributes for %s.\n", dirp);
1398*51898Smckusick 				return (1);
139951667Smckusick 			}
1400*51898Smckusick 			if (opt_flags & OP_ALLDIRS) {
1401*51898Smckusick 				syslog(LOG_ERR, "Not root dir");
1402*51898Smckusick 				return (1);
1403*51898Smckusick 			}
140451667Smckusick 			/* back up over the last component */
1405*51898Smckusick 			while (*cp == '/' && cp > dirp)
140651667Smckusick 				cp--;
1407*51898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
140851667Smckusick 				cp--;
1409*51898Smckusick 			if (cp == dirp) {
1410*51898Smckusick 				if (debug)
141151667Smckusick 					fprintf(stderr,"mnt unsucc\n");
1412*51898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
1413*51898Smckusick 				return (1);
141451667Smckusick 			}
141551667Smckusick 			savedc = *cp;
141651667Smckusick 			*cp = '\0';
141751667Smckusick 		}
1418*51898Smckusick 		if (addrp) {
141951667Smckusick 			++addrp;
1420*51898Smckusick 			if (*addrp == (u_long *)0)
142151667Smckusick 				done = TRUE;
1422*51898Smckusick 		} else
1423*51898Smckusick 			done = TRUE;
1424*51898Smckusick 	}
1425*51898Smckusick 	if (cp)
1426*51898Smckusick 		*cp = savedc;
1427*51898Smckusick 	return (0);
1428*51898Smckusick }
1429*51898Smckusick 
1430*51898Smckusick /*
1431*51898Smckusick  * Translate a net address.
1432*51898Smckusick  */
1433*51898Smckusick get_net(cp, net, maskflg)
1434*51898Smckusick 	char *cp;
1435*51898Smckusick 	struct netmsk *net;
1436*51898Smckusick 	int maskflg;
1437*51898Smckusick {
1438*51898Smckusick 	register struct netent *np;
1439*51898Smckusick 	register long netaddr;
1440*51898Smckusick 	struct in_addr inetaddr, inetaddr2;
1441*51898Smckusick 	char *name;
1442*51898Smckusick 
1443*51898Smckusick 	if (np = getnetbyname(cp))
1444*51898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
1445*51898Smckusick 	else if (isdigit(*cp)) {
1446*51898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
1447*51898Smckusick 			return (1);
1448*51898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
1449*51898Smckusick 		/*
1450*51898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
1451*51898Smckusick 		 * bits to shift the address to make it into a network,
1452*51898Smckusick 		 * however you do know how to make a network address into
1453*51898Smckusick 		 * a host with host == 0 and then compare them.
1454*51898Smckusick 		 * (What a pest)
1455*51898Smckusick 		 */
1456*51898Smckusick 		if (!maskflg) {
1457*51898Smckusick 			setnetent(0);
1458*51898Smckusick 			while (np = getnetent()) {
1459*51898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
1460*51898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
1461*51898Smckusick 					break;
1462*51898Smckusick 			}
1463*51898Smckusick 			endnetent();
146451667Smckusick 		}
1465*51898Smckusick 	} else
1466*51898Smckusick 		return (1);
1467*51898Smckusick 	if (maskflg)
1468*51898Smckusick 		net->nt_mask = inetaddr.s_addr;
1469*51898Smckusick 	else {
1470*51898Smckusick 		if (np)
1471*51898Smckusick 			name = np->n_name;
1472*51898Smckusick 		else
1473*51898Smckusick 			name = inet_ntoa(inetaddr);
1474*51898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
1475*51898Smckusick 		if (net->nt_name == (char *)0)
1476*51898Smckusick 			out_of_mem();
1477*51898Smckusick 		strcpy(net->nt_name, name);
1478*51898Smckusick 		net->nt_net = inetaddr.s_addr;
147938460Smckusick 	}
1480*51898Smckusick 	return (0);
148138460Smckusick }
148238460Smckusick 
148338460Smckusick /*
148438460Smckusick  * Parse out the next white space separated field
148538460Smckusick  */
148651667Smckusick void
148738460Smckusick nextfield(cp, endcp)
148838460Smckusick 	char **cp;
148938460Smckusick 	char **endcp;
149038460Smckusick {
149138460Smckusick 	register char *p;
149238460Smckusick 
149338460Smckusick 	p = *cp;
149438460Smckusick 	while (*p == ' ' || *p == '\t')
149538460Smckusick 		p++;
1496*51898Smckusick 	if (*p == '\n' || *p == '\0')
149738460Smckusick 		*cp = *endcp = p;
1498*51898Smckusick 	else {
1499*51898Smckusick 		*cp = p++;
1500*51898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1501*51898Smckusick 			p++;
1502*51898Smckusick 		*endcp = p;
150338460Smckusick 	}
150438460Smckusick }
150539681Smckusick 
150639681Smckusick /*
1507*51898Smckusick  * Get an exports file line. Skip over blank lines and handle line
1508*51898Smckusick  * continuations.
150939681Smckusick  */
1510*51898Smckusick get_line()
151139681Smckusick {
1512*51898Smckusick 	register char *p, *cp;
1513*51898Smckusick 	register int len;
1514*51898Smckusick 	int totlen, cont_line;
151539681Smckusick 
1516*51898Smckusick 	/*
1517*51898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
1518*51898Smckusick 	 */
1519*51898Smckusick 	p = line;
1520*51898Smckusick 	totlen = 0;
1521*51898Smckusick 	do {
1522*51898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1523*51898Smckusick 			return (0);
1524*51898Smckusick 		len = strlen(p);
1525*51898Smckusick 		cp = p + len - 1;
1526*51898Smckusick 		cont_line = 0;
1527*51898Smckusick 		while (cp >= p &&
1528*51898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1529*51898Smckusick 			if (*cp == '\\')
1530*51898Smckusick 				cont_line = 1;
1531*51898Smckusick 			cp--;
1532*51898Smckusick 			len--;
1533*51898Smckusick 		}
1534*51898Smckusick 		*++cp = '\0';
1535*51898Smckusick 		if (len > 0) {
1536*51898Smckusick 			totlen += len;
1537*51898Smckusick 			if (totlen >= LINESIZ) {
1538*51898Smckusick 				syslog(LOG_ERR, "Exports line too long");
1539*51898Smckusick 				exit(2);
1540*51898Smckusick 			}
1541*51898Smckusick 			p = cp;
1542*51898Smckusick 		}
1543*51898Smckusick 	} while (totlen == 0 || cont_line);
1544*51898Smckusick 	return (1);
154544015Smckusick }
154644015Smckusick 
154751667Smckusick /*
154851667Smckusick  * Parse a description of a credential.
154951667Smckusick  */
155051667Smckusick parsecred(namelist, cr)
155151667Smckusick 	char *namelist;
155251667Smckusick 	register struct ucred *cr;
155351667Smckusick {
155451667Smckusick 	register char *name;
155551667Smckusick 	register int cnt;
155651667Smckusick 	char *names;
155751667Smckusick 	struct passwd *pw;
155851667Smckusick 	struct group *gr;
155951667Smckusick 	int ngroups, groups[NGROUPS + 1];
156051667Smckusick 
156151667Smckusick 	/*
156251667Smckusick 	 * Set up the unpriviledged user.
156351667Smckusick 	 */
156451667Smckusick 	cr->cr_ref = 1;
156551667Smckusick 	cr->cr_uid = -2;
156651667Smckusick 	cr->cr_groups[0] = -2;
156751667Smckusick 	cr->cr_ngroups = 1;
156851667Smckusick 	/*
156951667Smckusick 	 * Get the user's password table entry.
157051667Smckusick 	 */
157151667Smckusick 	names = strsep(&namelist, " \t\n");
157251667Smckusick 	name = strsep(&names, ":");
157351667Smckusick 	if (isdigit(*name) || *name == '-')
157451667Smckusick 		pw = getpwuid(atoi(name));
157551667Smckusick 	else
157651667Smckusick 		pw = getpwnam(name);
157751667Smckusick 	/*
157851667Smckusick 	 * Credentials specified as those of a user.
157951667Smckusick 	 */
158051667Smckusick 	if (names == NULL) {
158151667Smckusick 		if (pw == NULL) {
158251667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
158351667Smckusick 			return;
158451667Smckusick 		}
158551667Smckusick 		cr->cr_uid = pw->pw_uid;
158651667Smckusick 		ngroups = NGROUPS + 1;
158751667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
158851667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
158951667Smckusick 		/*
159051667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
159151667Smckusick 		 */
159251667Smckusick 		cr->cr_ngroups = ngroups - 1;
159351667Smckusick 		cr->cr_groups[0] = groups[0];
159451667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
159551667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
159651667Smckusick 		return;
159751667Smckusick 	}
159851667Smckusick 	/*
159951667Smckusick 	 * Explicit credential specified as a colon separated list:
160051667Smckusick 	 *	uid:gid:gid:...
160151667Smckusick 	 */
160251667Smckusick 	if (pw != NULL)
160351667Smckusick 		cr->cr_uid = pw->pw_uid;
160451667Smckusick 	else if (isdigit(*name) || *name == '-')
160551667Smckusick 		cr->cr_uid = atoi(name);
160651667Smckusick 	else {
160751667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
160851667Smckusick 		return;
160951667Smckusick 	}
161051667Smckusick 	cr->cr_ngroups = 0;
161151667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
161251667Smckusick 		name = strsep(&names, ":");
161351667Smckusick 		if (isdigit(*name) || *name == '-') {
161451667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
161551667Smckusick 		} else {
161651667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
161751667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
161851667Smckusick 				continue;
161951667Smckusick 			}
162051667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
162151667Smckusick 		}
162251667Smckusick 	}
162351667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
162451667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
162551667Smckusick }
162651667Smckusick 
162744015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
162844015Smckusick /*
162944015Smckusick  * Routines that maintain the remote mounttab
163044015Smckusick  */
163151667Smckusick void
163251667Smckusick get_mountlist()
163344015Smckusick {
163444015Smckusick 	register struct mountlist *mlp, **mlpp;
163544015Smckusick 	register char *eos, *dirp;
163644015Smckusick 	int len;
163744015Smckusick 	char str[STRSIZ];
163844015Smckusick 	FILE *mlfile;
163944015Smckusick 
164051712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
164151667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
164244015Smckusick 		return;
164344015Smckusick 	}
164444015Smckusick 	mlpp = &mlhead;
164544015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
164644015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
164744015Smckusick 		    (dirp = index(str, ' ')) == NULL)
164844015Smckusick 			continue;
164944015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
165044015Smckusick 		len = dirp-str;
165144015Smckusick 		if (len > RPCMNT_NAMELEN)
165244015Smckusick 			len = RPCMNT_NAMELEN;
165344015Smckusick 		bcopy(str, mlp->ml_host, len);
165444015Smckusick 		mlp->ml_host[len] = '\0';
165544015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
165644015Smckusick 			dirp++;
165744015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
165844015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
165944015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
166044015Smckusick 			len = strlen(dirp);
166144015Smckusick 		else
166244015Smckusick 			len = eos-dirp;
166344015Smckusick 		if (len > RPCMNT_PATHLEN)
166444015Smckusick 			len = RPCMNT_PATHLEN;
166544015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
166644015Smckusick 		mlp->ml_dirp[len] = '\0';
166744015Smckusick 		mlp->ml_next = (struct mountlist *)0;
166844015Smckusick 		*mlpp = mlp;
166944015Smckusick 		mlpp = &mlp->ml_next;
167044015Smckusick 	}
167144015Smckusick 	fclose(mlfile);
167244015Smckusick }
167344015Smckusick 
167451667Smckusick void
167551667Smckusick del_mlist(hostp, dirp)
167644015Smckusick 	register char *hostp, *dirp;
167744015Smckusick {
167844015Smckusick 	register struct mountlist *mlp, **mlpp;
167951712Smckusick 	struct mountlist *mlp2;
168044015Smckusick 	FILE *mlfile;
168144015Smckusick 	int fnd = 0;
168244015Smckusick 
168344015Smckusick 	mlpp = &mlhead;
168444015Smckusick 	mlp = mlhead;
168544015Smckusick 	while (mlp) {
168644015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
168744015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
168844015Smckusick 			fnd = 1;
168951712Smckusick 			mlp2 = mlp;
169051712Smckusick 			*mlpp = mlp = mlp->ml_next;
169151712Smckusick 			free((caddr_t)mlp2);
169251712Smckusick 		} else {
169351712Smckusick 			mlpp = &mlp->ml_next;
169451712Smckusick 			mlp = mlp->ml_next;
169539681Smckusick 		}
169639681Smckusick 	}
169744015Smckusick 	if (fnd) {
169844015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1699*51898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
170044015Smckusick 			return;
170144015Smckusick 		}
170244015Smckusick 		mlp = mlhead;
170344015Smckusick 		while (mlp) {
170444015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
170544015Smckusick 			mlp = mlp->ml_next;
170644015Smckusick 		}
170744015Smckusick 		fclose(mlfile);
170844015Smckusick 	}
170939681Smckusick }
171044015Smckusick 
171151667Smckusick void
171251667Smckusick add_mlist(hostp, dirp)
171344015Smckusick 	register char *hostp, *dirp;
171444015Smckusick {
171544015Smckusick 	register struct mountlist *mlp, **mlpp;
171644015Smckusick 	FILE *mlfile;
171744015Smckusick 
171844015Smckusick 	mlpp = &mlhead;
171944015Smckusick 	mlp = mlhead;
172044015Smckusick 	while (mlp) {
172144015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
172244015Smckusick 			return;
172344015Smckusick 		mlpp = &mlp->ml_next;
172444015Smckusick 		mlp = mlp->ml_next;
172544015Smckusick 	}
172644015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
172744015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
172844015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
172944015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
173044015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
173144015Smckusick 	mlp->ml_next = (struct mountlist *)0;
173244015Smckusick 	*mlpp = mlp;
173344015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1734*51898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
173544015Smckusick 		return;
173644015Smckusick 	}
173744015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
173844015Smckusick 	fclose(mlfile);
173944015Smckusick }
174044015Smckusick 
174144015Smckusick /*
174244015Smckusick  * This function is called via. SIGTERM when the system is going down.
174344015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
174444015Smckusick  */
174546709Sbostic void
174644015Smckusick send_umntall()
174744015Smckusick {
174844015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
174944015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
175051667Smckusick 	exit(0);
175144015Smckusick }
175244015Smckusick 
175344015Smckusick umntall_each(resultsp, raddr)
175444015Smckusick 	caddr_t resultsp;
175544015Smckusick 	struct sockaddr_in *raddr;
175644015Smckusick {
175744015Smckusick 	return (1);
175844015Smckusick }
175944015Smckusick 
176044015Smckusick /*
176151667Smckusick  * Free up a group list.
176251667Smckusick  */
176351667Smckusick void
176451667Smckusick free_grp(grp)
176551667Smckusick 	register struct grouplist *grp;
176651667Smckusick {
176751667Smckusick 	register char **addrp;
176851667Smckusick 
1769*51898Smckusick 	if (grp->gr_type == GT_HOST) {
177051712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
177151712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
177251712Smckusick 			while (addrp && *addrp)
177351712Smckusick 				free(*addrp++);
177451712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
177551712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
177651712Smckusick 		}
177751667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
1778*51898Smckusick 	} else if (grp->gr_type == GT_NET) {
1779*51898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
1780*51898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
178151667Smckusick 	}
178251667Smckusick #ifdef ISO
1783*51898Smckusick 	else if (grp->gr_type == GT_ISO)
178451667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
178551667Smckusick #endif
178651667Smckusick 	free((caddr_t)grp);
178751667Smckusick }
178851667Smckusick 
178951667Smckusick /*
179051667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
179151667Smckusick  *
179251667Smckusick  * find the real name of path, by removing all ".", ".."
179351667Smckusick  * and symlink components.
179451667Smckusick  *
179551667Smckusick  * Jan-Simon Pendry, September 1991.
179651667Smckusick  */
179751667Smckusick char *
179851667Smckusick realpath(path, resolved)
179951667Smckusick 	char *path;
180051667Smckusick 	char resolved[MAXPATHLEN];
180151667Smckusick {
180251667Smckusick 	int d = open(".", O_RDONLY);
180351667Smckusick 	int rootd = 0;
180451667Smckusick 	char *p, *q;
180551667Smckusick 	struct stat stb;
180651667Smckusick 	char wbuf[MAXPATHLEN];
180751667Smckusick 
180851667Smckusick 	strcpy(resolved, path);
180951667Smckusick 
181051667Smckusick 	if (d < 0)
181151667Smckusick 		return 0;
181251667Smckusick 
181351667Smckusick loop:;
181451667Smckusick 	q = strrchr(resolved, '/');
181551667Smckusick 	if (q) {
181651667Smckusick 		p = q + 1;
181751667Smckusick 		if (q == resolved)
181851667Smckusick 			q = "/";
181951667Smckusick 		else {
182051667Smckusick 			do
182151667Smckusick 				--q;
182251667Smckusick 			while (q > resolved && *q == '/');
182351667Smckusick 			q[1] = '\0';
182451667Smckusick 			q = resolved;
182551667Smckusick 		}
182651667Smckusick 		if (chdir(q) < 0)
182751667Smckusick 			goto out;
182851667Smckusick 	} else
182951667Smckusick 		p = resolved;
183051667Smckusick 
183151667Smckusick 	if (lstat(p, &stb) == 0) {
183251667Smckusick 		if (S_ISLNK(stb.st_mode)) {
183351667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
183451667Smckusick 			if (n < 0)
183551667Smckusick 				goto out;
183651667Smckusick 			resolved[n] = '\0';
183751667Smckusick 			goto loop;
183851667Smckusick 		}
183951667Smckusick 		if (S_ISDIR(stb.st_mode)) {
184051667Smckusick 			if (chdir(p) < 0)
184151667Smckusick 				goto out;
184251667Smckusick 			p = "";
184351667Smckusick 		}
184451667Smckusick 	}
184551667Smckusick 
184651667Smckusick 	strcpy(wbuf, p);
184751667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
184851667Smckusick 		goto out;
184951667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
185051667Smckusick 		rootd = 1;
185151667Smckusick 
185251667Smckusick 	if (*wbuf) {
185351667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
185451667Smckusick 			errno = ENAMETOOLONG;
185551667Smckusick 			goto out;
185651667Smckusick 		}
185751667Smckusick 		if (rootd == 0)
185851667Smckusick 			strcat(resolved, "/");
185951667Smckusick 		strcat(resolved, wbuf);
186051667Smckusick 	}
186151667Smckusick 
186251667Smckusick 	if (fchdir(d) < 0)
186351667Smckusick 		goto out;
186451667Smckusick 	(void) close(d);
186551667Smckusick 
186651667Smckusick 	return resolved;
186751667Smckusick 
186851667Smckusick out:;
186951667Smckusick 	(void) close(d);
187051667Smckusick 	return 0;
187151667Smckusick }
187251711Smckusick 
187351711Smckusick #ifdef DEBUG
187451711Smckusick void
187551711Smckusick SYSLOG(int pri, const char *fmt, ...)
187651711Smckusick {
187751711Smckusick 	va_list ap;
187851711Smckusick 
187951711Smckusick 	va_start(ap, fmt);
188051711Smckusick 	vfprintf(stderr, fmt, ap);
188151711Smckusick 	va_end(ap);
188251711Smckusick }
188351711Smckusick #endif /* DEBUG */
1884*51898Smckusick 
1885*51898Smckusick /*
1886*51898Smckusick  * Check options for consistency.
1887*51898Smckusick  */
1888*51898Smckusick check_options(dp)
1889*51898Smckusick 	struct dirlist *dp;
1890*51898Smckusick {
1891*51898Smckusick 
1892*51898Smckusick 	if (dp == (struct dirlist *)0)
1893*51898Smckusick 	    return (1);
1894*51898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1895*51898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1896*51898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1897*51898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
1898*51898Smckusick 	    return (1);
1899*51898Smckusick 	}
1900*51898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
1901*51898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
1902*51898Smckusick 	    return (1);
1903*51898Smckusick 	}
1904*51898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
1905*51898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
1906*51898Smckusick 	    return (1);
1907*51898Smckusick 	}
1908*51898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
1909*51898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
1910*51898Smckusick 	    return (1);
1911*51898Smckusick 	}
1912*51898Smckusick 	return (0);
1913*51898Smckusick }
1914