xref: /csrg-svn/sbin/mountd/mountd.c (revision 65940)
138460Smckusick /*
261519Sbostic  * Copyright (c) 1989, 1993
361519Sbostic  *	The Regents of the University of California.  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
1261519Sbostic static char copyright[] =
1361519Sbostic "@(#) Copyright (c) 1989, 1993\n\
1461519Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*65940Sbostic static char sccsid[] = "@(#)mountd.c	8.6 (Berkeley) 01/28/94";
1938460Smckusick #endif not lint
2038460Smckusick 
2138460Smckusick #include <sys/param.h>
2265863Sbostic #include <sys/file.h>
2338460Smckusick #include <sys/ioctl.h>
2438460Smckusick #include <sys/mount.h>
2538460Smckusick #include <sys/socket.h>
2665863Sbostic #include <sys/stat.h>
2752109Smckusick #include <sys/syslog.h>
2865863Sbostic #include <sys/ucred.h>
2965863Sbostic 
3038460Smckusick #include <rpc/rpc.h>
3138460Smckusick #include <rpc/pmap_clnt.h>
3238460Smckusick #include <rpc/pmap_prot.h>
3351667Smckusick #ifdef ISO
3451667Smckusick #include <netiso/iso.h>
3551667Smckusick #endif
3638460Smckusick #include <nfs/rpcv2.h>
3738460Smckusick #include <nfs/nfsv2.h>
3865863Sbostic 
3965863Sbostic #include <errno.h>
4065863Sbostic #include <grp.h>
4165863Sbostic #include <netdb.h>
4265863Sbostic #include <pwd.h>
4365863Sbostic #include <signal.h>
4453150Smckusick #ifdef DEBUG
4553150Smckusick #include <stdarg.h>
4653150Smckusick #endif
4765863Sbostic #include <stdio.h>
4865863Sbostic #include <stdlib.h>
4965863Sbostic #include <string.h>
5065863Sbostic #include <unistd.h>
5165863Sbostic #include "pathnames.h"
5238460Smckusick 
5338460Smckusick /*
5438460Smckusick  * Structures for keeping the mount list and export list
5538460Smckusick  */
5638460Smckusick struct mountlist {
5744015Smckusick 	struct mountlist *ml_next;
5838460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
5938460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
6038460Smckusick };
6138460Smckusick 
6251898Smckusick struct dirlist {
6351898Smckusick 	struct dirlist	*dp_left;
6451898Smckusick 	struct dirlist	*dp_right;
6551898Smckusick 	int		dp_flag;
6651898Smckusick 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
6751898Smckusick 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
6851898Smckusick };
6951898Smckusick /* dp_flag bits */
7051898Smckusick #define	DP_DEFSET	0x1
7151898Smckusick 
7238460Smckusick struct exportlist {
7338460Smckusick 	struct exportlist *ex_next;
7451898Smckusick 	struct dirlist	*ex_dirl;
7551898Smckusick 	struct dirlist	*ex_defdir;
7651898Smckusick 	int		ex_flag;
7751898Smckusick 	fsid_t		ex_fs;
7851898Smckusick 	char		*ex_fsdir;
7938460Smckusick };
8051898Smckusick /* ex_flag bits */
8152109Smckusick #define	EX_LINKED	0x1
8238460Smckusick 
8351898Smckusick struct netmsk {
8451898Smckusick 	u_long	nt_net;
8551898Smckusick 	u_long	nt_mask;
8651898Smckusick 	char *nt_name;
8751898Smckusick };
8851898Smckusick 
8951667Smckusick union grouptypes {
9051667Smckusick 	struct hostent *gt_hostent;
9151898Smckusick 	struct netmsk	gt_net;
9251667Smckusick #ifdef ISO
9351667Smckusick 	struct sockaddr_iso *gt_isoaddr;
9451667Smckusick #endif
9551667Smckusick };
9651667Smckusick 
9738460Smckusick struct grouplist {
9851898Smckusick 	int gr_type;
9951667Smckusick 	union grouptypes gr_ptr;
10038460Smckusick 	struct grouplist *gr_next;
10138460Smckusick };
10251898Smckusick /* Group types */
10351898Smckusick #define	GT_NULL		0x0
10451898Smckusick #define	GT_HOST		0x1
10551898Smckusick #define	GT_NET		0x2
10651898Smckusick #define	GT_ISO		0x4
10738460Smckusick 
10851898Smckusick struct hostlist {
10951898Smckusick 	struct grouplist *ht_grp;
11051898Smckusick 	struct hostlist	 *ht_next;
11151667Smckusick };
11251667Smckusick 
11338460Smckusick /* Global defs */
11446709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
115*65940Sbostic int check_dirpath();
11651898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem();
11751667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
11851898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host();
11953150Smckusick void setnetgrent(), endnetgrent();
12051898Smckusick struct exportlist *ex_search(), *get_exp();
12151898Smckusick struct grouplist *get_grp();
12251898Smckusick char *realpath(), *add_expdir();
12351898Smckusick struct in_addr inet_makeaddr();
12451898Smckusick char *inet_ntoa();
12551898Smckusick struct dirlist *dirp_search();
12651898Smckusick struct hostlist *get_ht();
12751667Smckusick #ifdef ISO
12851667Smckusick struct iso_addr *iso_addr();
12951667Smckusick #endif
13051898Smckusick struct exportlist *exphead;
13144015Smckusick struct mountlist *mlhead;
13251898Smckusick struct grouplist *grphead;
13338460Smckusick char exname[MAXPATHLEN];
13451667Smckusick struct ucred def_anon = {
13551667Smckusick 	(u_short) 1,
13651667Smckusick 	(uid_t) -2,
13751667Smckusick 	1,
13851667Smckusick 	(gid_t) -2,
13951667Smckusick };
14044015Smckusick int root_only = 1;
14151898Smckusick int opt_flags;
14251898Smckusick /* Bits for above */
14351898Smckusick #define	OP_MAPROOT	0x01
14451898Smckusick #define	OP_MAPALL	0x02
14551898Smckusick #define	OP_KERB		0x04
14651898Smckusick #define	OP_MASK		0x08
14751898Smckusick #define	OP_NET		0x10
14851898Smckusick #define	OP_ISO		0x20
14951898Smckusick #define	OP_ALLDIRS	0x40
15051898Smckusick 
15138460Smckusick extern int errno;
15238460Smckusick #ifdef DEBUG
15338460Smckusick int debug = 1;
15451711Smckusick void	SYSLOG __P((int, const char *, ...));
15551711Smckusick #define syslog SYSLOG
15638460Smckusick #else
15738460Smckusick int debug = 0;
15838460Smckusick #endif
15938460Smckusick 
16038460Smckusick /*
16138460Smckusick  * Mountd server for NFS mount protocol as described in:
16239681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
16344015Smckusick  * The optional arguments are the exports file name
16439681Smckusick  * default: _PATH_EXPORTS
16544015Smckusick  * and "-n" to allow nonroot mount.
16638460Smckusick  */
16738460Smckusick main(argc, argv)
16838460Smckusick 	int argc;
16944015Smckusick 	char **argv;
17038460Smckusick {
17138460Smckusick 	SVCXPRT *transp;
17244015Smckusick 	int c;
17344015Smckusick 	extern int optind;
17444015Smckusick 	extern char *optarg;
17538460Smckusick 
17644015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
17744015Smckusick 		switch (c) {
17844015Smckusick 		case 'n':
17944015Smckusick 			root_only = 0;
18044015Smckusick 			break;
18144015Smckusick 		default:
18244015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
18344015Smckusick 			exit(1);
18444015Smckusick 		};
18544015Smckusick 	argc -= optind;
18644015Smckusick 	argv += optind;
18751898Smckusick 	grphead = (struct grouplist *)0;
18851898Smckusick 	exphead = (struct exportlist *)0;
18944015Smckusick 	mlhead = (struct mountlist *)0;
19044015Smckusick 	if (argc == 1) {
19144015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
19244015Smckusick 		exname[MAXPATHLEN-1] = '\0';
19344015Smckusick 	} else
19444015Smckusick 		strcpy(exname, _PATH_EXPORTS);
19544338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
19651667Smckusick 	if (debug)
19751667Smckusick 		fprintf(stderr,"Getting export list.\n");
19844015Smckusick 	get_exportlist();
19951667Smckusick 	if (debug)
20051667Smckusick 		fprintf(stderr,"Getting mount list.\n");
20144015Smckusick 	get_mountlist();
20251667Smckusick 	if (debug)
20351667Smckusick 		fprintf(stderr,"Here we go.\n");
20438460Smckusick 	if (debug == 0) {
20544690Skarels 		daemon(0, 0);
20638460Smckusick 		signal(SIGINT, SIG_IGN);
20738460Smckusick 		signal(SIGQUIT, SIG_IGN);
20838460Smckusick 	}
20938460Smckusick 	signal(SIGHUP, get_exportlist);
21044015Smckusick 	signal(SIGTERM, send_umntall);
21140494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
21240494Smckusick 	  if (pidfile != NULL) {
21340494Smckusick 		fprintf(pidfile, "%d\n", getpid());
21440494Smckusick 		fclose(pidfile);
21540494Smckusick 	  }
21640494Smckusick 	}
21738460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
21838460Smckusick 		syslog(LOG_ERR, "Can't create socket");
21938460Smckusick 		exit(1);
22038460Smckusick 	}
22138460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
22251667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
22351667Smckusick 	    IPPROTO_UDP)) {
22438460Smckusick 		syslog(LOG_ERR, "Can't register mount");
22538460Smckusick 		exit(1);
22638460Smckusick 	}
22738460Smckusick 	svc_run();
22838460Smckusick 	syslog(LOG_ERR, "Mountd died");
22944690Skarels 	exit(1);
23038460Smckusick }
23138460Smckusick 
23238460Smckusick /*
23338460Smckusick  * The mount rpc service
23438460Smckusick  */
23538460Smckusick mntsrv(rqstp, transp)
23638460Smckusick 	register struct svc_req *rqstp;
23738460Smckusick 	register SVCXPRT *transp;
23838460Smckusick {
23938460Smckusick 	register struct exportlist *ep;
24051898Smckusick 	register struct dirlist *dp;
24138460Smckusick 	nfsv2fh_t nfh;
24238460Smckusick 	struct authunix_parms *ucr;
24338460Smckusick 	struct stat stb;
24451898Smckusick 	struct statfs fsb;
24538460Smckusick 	struct hostent *hp;
24639681Smckusick 	u_long saddr;
24751667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
24851898Smckusick 	int bad = ENOENT, omask, defset;
24939681Smckusick 	uid_t uid = -2;
25038460Smckusick 
25138460Smckusick 	/* Get authorization */
25238460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
25338460Smckusick 	case AUTH_UNIX:
25438460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
25539681Smckusick 		uid = ucr->aup_uid;
25639681Smckusick 		break;
25738460Smckusick 	case AUTH_NULL:
25838460Smckusick 	default:
25939681Smckusick 		break;
26038460Smckusick 	}
26138460Smckusick 
26239681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
26339681Smckusick 	hp = (struct hostent *)0;
26438460Smckusick 	switch (rqstp->rq_proc) {
26539681Smckusick 	case NULLPROC:
26639681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
26739681Smckusick 			syslog(LOG_ERR, "Can't send reply");
26839681Smckusick 		return;
26938460Smckusick 	case RPCMNT_MOUNT:
27051667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
27139681Smckusick 			svcerr_weakauth(transp);
27239681Smckusick 			return;
27339681Smckusick 		}
27451667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
27538460Smckusick 			svcerr_decode(transp);
27638460Smckusick 			return;
27738460Smckusick 		}
27838460Smckusick 
27951667Smckusick 		/*
28051667Smckusick 		 * Get the real pathname and make sure it is a directory
28151667Smckusick 		 * that exists.
28251667Smckusick 		 */
28351898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
28451898Smckusick 		    stat(dirpath, &stb) < 0 ||
28551898Smckusick 		    (stb.st_mode & S_IFMT) != S_IFDIR ||
28651898Smckusick 		    statfs(dirpath, &fsb) < 0) {
28751667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
28851667Smckusick 			if (debug)
28951898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
29038460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
29138460Smckusick 				syslog(LOG_ERR, "Can't send reply");
29238460Smckusick 			return;
29338460Smckusick 		}
29438460Smckusick 
29538460Smckusick 		/* Check in the exports list */
29638460Smckusick 		omask = sigblock(sigmask(SIGHUP));
29751898Smckusick 		ep = ex_search(&fsb.f_fsid);
29851898Smckusick 		defset = 0;
29951898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
30051898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
30151898Smckusick 		     chk_host(dp, saddr, &defset)) ||
30251898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
30351898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
30451667Smckusick 			/* Get the file handle */
30551667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
30651667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
30751667Smckusick 				bad = errno;
30851898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
30951667Smckusick 				if (!svc_sendreply(transp, xdr_long,
31051667Smckusick 				    (caddr_t)&bad))
31151667Smckusick 					syslog(LOG_ERR, "Can't send reply");
31251667Smckusick 				sigsetmask(omask);
31351667Smckusick 				return;
31451667Smckusick 			}
31551667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
31638460Smckusick 				syslog(LOG_ERR, "Can't send reply");
31751667Smckusick 			if (hp == NULL)
31851667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
31951667Smckusick 				    sizeof(saddr), AF_INET);
32051667Smckusick 			if (hp)
32151667Smckusick 				add_mlist(hp->h_name, dirpath);
32251667Smckusick 			else
32351667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
32451667Smckusick 					dirpath);
32551667Smckusick 			if (debug)
32651667Smckusick 				fprintf(stderr,"Mount successfull.\n");
32751898Smckusick 		} else {
32851898Smckusick 			bad = EACCES;
32951898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
33051898Smckusick 				syslog(LOG_ERR, "Can't send reply");
33138460Smckusick 		}
33251667Smckusick 		sigsetmask(omask);
33338460Smckusick 		return;
33438460Smckusick 	case RPCMNT_DUMP:
33538460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
33638460Smckusick 			syslog(LOG_ERR, "Can't send reply");
33738460Smckusick 		return;
33838460Smckusick 	case RPCMNT_UMOUNT:
33951667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
34039681Smckusick 			svcerr_weakauth(transp);
34139681Smckusick 			return;
34239681Smckusick 		}
34338460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
34438460Smckusick 			svcerr_decode(transp);
34538460Smckusick 			return;
34638460Smckusick 		}
34738460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
34838460Smckusick 			syslog(LOG_ERR, "Can't send reply");
34944015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
35044015Smckusick 		if (hp)
35144015Smckusick 			del_mlist(hp->h_name, dirpath);
35251667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
35338460Smckusick 		return;
35438460Smckusick 	case RPCMNT_UMNTALL:
35551667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
35639681Smckusick 			svcerr_weakauth(transp);
35739681Smckusick 			return;
35839681Smckusick 		}
35938460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
36038460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36144015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
36244015Smckusick 		if (hp)
36344015Smckusick 			del_mlist(hp->h_name, (char *)0);
36451667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
36538460Smckusick 		return;
36638460Smckusick 	case RPCMNT_EXPORT:
36738460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
36838460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36938460Smckusick 		return;
37038460Smckusick 	default:
37138460Smckusick 		svcerr_noproc(transp);
37238460Smckusick 		return;
37338460Smckusick 	}
37438460Smckusick }
37538460Smckusick 
37638460Smckusick /*
37738460Smckusick  * Xdr conversion for a dirpath string
37838460Smckusick  */
37938460Smckusick xdr_dir(xdrsp, dirp)
38038460Smckusick 	XDR *xdrsp;
38138460Smckusick 	char *dirp;
38238460Smckusick {
38338460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
38438460Smckusick }
38538460Smckusick 
38638460Smckusick /*
38738460Smckusick  * Xdr routine to generate fhstatus
38838460Smckusick  */
38938460Smckusick xdr_fhs(xdrsp, nfh)
39038460Smckusick 	XDR *xdrsp;
39138460Smckusick 	nfsv2fh_t *nfh;
39238460Smckusick {
39338460Smckusick 	int ok = 0;
39438460Smckusick 
39538460Smckusick 	if (!xdr_long(xdrsp, &ok))
39638460Smckusick 		return (0);
39738460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
39838460Smckusick }
39938460Smckusick 
40038460Smckusick xdr_mlist(xdrsp, cp)
40138460Smckusick 	XDR *xdrsp;
40238460Smckusick 	caddr_t cp;
40338460Smckusick {
40444015Smckusick 	register struct mountlist *mlp;
40538460Smckusick 	int true = 1;
40638460Smckusick 	int false = 0;
40738460Smckusick 	char *strp;
40838460Smckusick 
40944015Smckusick 	mlp = mlhead;
41044015Smckusick 	while (mlp) {
41144015Smckusick 		if (!xdr_bool(xdrsp, &true))
41244015Smckusick 			return (0);
41344015Smckusick 		strp = &mlp->ml_host[0];
41444015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
41544015Smckusick 			return (0);
41644015Smckusick 		strp = &mlp->ml_dirp[0];
41744015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
41844015Smckusick 			return (0);
41944015Smckusick 		mlp = mlp->ml_next;
42038460Smckusick 	}
42138460Smckusick 	if (!xdr_bool(xdrsp, &false))
42238460Smckusick 		return (0);
42338460Smckusick 	return (1);
42438460Smckusick }
42538460Smckusick 
42638460Smckusick /*
42738460Smckusick  * Xdr conversion for export list
42838460Smckusick  */
42938460Smckusick xdr_explist(xdrsp, cp)
43038460Smckusick 	XDR *xdrsp;
43138460Smckusick 	caddr_t cp;
43238460Smckusick {
43338460Smckusick 	register struct exportlist *ep;
43438460Smckusick 	int false = 0;
43564903Smckusick 	int omask, putdef;
43638460Smckusick 
43738460Smckusick 	omask = sigblock(sigmask(SIGHUP));
43851898Smckusick 	ep = exphead;
43951898Smckusick 	while (ep) {
44064903Smckusick 		putdef = 0;
44164903Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
44238460Smckusick 			goto errout;
44364903Smckusick 		if (ep->ex_defdir && putdef == 0 &&
44464903Smckusick 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)0,
44564903Smckusick 			&putdef))
44664903Smckusick 			goto errout;
44738460Smckusick 		ep = ep->ex_next;
44838460Smckusick 	}
44938460Smckusick 	sigsetmask(omask);
45038460Smckusick 	if (!xdr_bool(xdrsp, &false))
45138460Smckusick 		return (0);
45238460Smckusick 	return (1);
45338460Smckusick errout:
45438460Smckusick 	sigsetmask(omask);
45538460Smckusick 	return (0);
45638460Smckusick }
45738460Smckusick 
45851898Smckusick /*
45951898Smckusick  * Called from xdr_explist() to traverse the tree and export the
46051898Smckusick  * directory paths.
46151898Smckusick  */
46264903Smckusick put_exlist(dp, xdrsp, adp, putdefp)
46351898Smckusick 	register struct dirlist *dp;
46451898Smckusick 	XDR *xdrsp;
46551898Smckusick 	struct dirlist *adp;
46664903Smckusick 	int *putdefp;
46751898Smckusick {
46851898Smckusick 	register struct grouplist *grp;
46951898Smckusick 	register struct hostlist *hp;
47051898Smckusick 	struct in_addr inaddr;
47151898Smckusick 	int true = 1;
47251898Smckusick 	int false = 0;
47351898Smckusick 	int gotalldir = 0;
47451898Smckusick 	char *strp;
47551898Smckusick 
47651898Smckusick 	if (dp) {
47764903Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
47851898Smckusick 			return (1);
47951898Smckusick 		if (!xdr_bool(xdrsp, &true))
48051898Smckusick 			return (1);
48151898Smckusick 		strp = dp->dp_dirp;
48251898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
48351898Smckusick 			return (1);
48464903Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
48551898Smckusick 			gotalldir = 1;
48664903Smckusick 			*putdefp = 1;
48764903Smckusick 		}
48851898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
48951898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
49051898Smckusick 			hp = dp->dp_hosts;
49151898Smckusick 			while (hp) {
49251898Smckusick 				grp = hp->ht_grp;
49351898Smckusick 				if (grp->gr_type == GT_HOST) {
49451898Smckusick 					if (!xdr_bool(xdrsp, &true))
49551898Smckusick 						return (1);
49651898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
49751898Smckusick 					if (!xdr_string(xdrsp, &strp,
49851898Smckusick 					    RPCMNT_NAMELEN))
49951898Smckusick 						return (1);
50051898Smckusick 				} else if (grp->gr_type == GT_NET) {
50151898Smckusick 					if (!xdr_bool(xdrsp, &true))
50251898Smckusick 						return (1);
50351898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
50451898Smckusick 					if (!xdr_string(xdrsp, &strp,
50551898Smckusick 					    RPCMNT_NAMELEN))
50651898Smckusick 						return (1);
50751898Smckusick 				}
50851898Smckusick 				hp = hp->ht_next;
50951898Smckusick 				if (gotalldir && hp == (struct hostlist *)0) {
51051898Smckusick 					hp = adp->dp_hosts;
51151898Smckusick 					gotalldir = 0;
51251898Smckusick 				}
51351898Smckusick 			}
51451898Smckusick 		}
51551898Smckusick 		if (!xdr_bool(xdrsp, &false))
51651898Smckusick 			return (1);
51764903Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
51851898Smckusick 			return (1);
51951898Smckusick 	}
52051898Smckusick 	return (0);
52151898Smckusick }
52251898Smckusick 
52338460Smckusick #define LINESIZ	10240
52438460Smckusick char line[LINESIZ];
52551898Smckusick FILE *exp_file;
52638460Smckusick 
52738460Smckusick /*
52838460Smckusick  * Get the export list
52938460Smckusick  */
53046709Sbostic void
53138460Smckusick get_exportlist()
53238460Smckusick {
53338460Smckusick 	register struct exportlist *ep, *ep2;
53451898Smckusick 	register struct grouplist *grp, *tgrp;
53551898Smckusick 	struct exportlist **epp;
53651898Smckusick 	struct dirlist *dirhead;
53752109Smckusick 	struct statfs fsb, *fsp;
53851898Smckusick 	struct hostent *hpe;
53951898Smckusick 	struct ucred anon;
54053150Smckusick 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
54153150Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
54238460Smckusick 
54338460Smckusick 	/*
54438460Smckusick 	 * First, get rid of the old list
54538460Smckusick 	 */
54651898Smckusick 	ep = exphead;
54751898Smckusick 	while (ep) {
54838460Smckusick 		ep2 = ep;
54938460Smckusick 		ep = ep->ex_next;
55044015Smckusick 		free_exp(ep2);
55138460Smckusick 	}
55251898Smckusick 	exphead = (struct exportlist *)0;
55338460Smckusick 
55451898Smckusick 	grp = grphead;
55551898Smckusick 	while (grp) {
55651898Smckusick 		tgrp = grp;
55751898Smckusick 		grp = grp->gr_next;
55851898Smckusick 		free_grp(tgrp);
55951667Smckusick 	}
56051898Smckusick 	grphead = (struct grouplist *)0;
56151667Smckusick 
56238460Smckusick 	/*
56352109Smckusick 	 * And delete exports that are in the kernel for all local
56452109Smckusick 	 * file systems.
56552109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
56652109Smckusick 	 *      instead of just MOUNT_UFS.
56752109Smckusick 	 */
56853214Smckusick 	num = getmntinfo(&fsp, MNT_NOWAIT);
56952109Smckusick 	for (i = 0; i < num; i++) {
57065713Shibler 		union {
57165713Shibler 			struct ufs_args ua;
57265713Shibler 			struct iso_args ia;
57365713Shibler 			struct mfs_args ma;
57465713Shibler 		} targs;
57565713Shibler 
57665713Shibler 		switch (fsp->f_type) {
57765863Sbostic 		case MOUNT_MFS:
57865713Shibler 		case MOUNT_UFS:
57965863Sbostic 		case MOUNT_CD9660:
58065863Sbostic 			targs.ua.fspec = NULL;
58165713Shibler 			targs.ua.export.ex_flags = MNT_DELEXPORT;
58252109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
58365713Shibler 				  fsp->f_flags | MNT_UPDATE,
58465713Shibler 				  (caddr_t)&targs) < 0)
58565713Shibler 				syslog(LOG_ERR, "Can't delete exports for %s",
58652109Smckusick 				       fsp->f_mntonname);
58752109Smckusick 		}
58852109Smckusick 		fsp++;
58952109Smckusick 	}
59052109Smckusick 
59152109Smckusick 	/*
59238460Smckusick 	 * Read in the exports file and build the list, calling
59351667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
59438460Smckusick 	 */
59551898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
59638460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
59738460Smckusick 		exit(2);
59838460Smckusick 	}
59951898Smckusick 	dirhead = (struct dirlist *)0;
60051898Smckusick 	while (get_line()) {
60151667Smckusick 		if (debug)
60251667Smckusick 			fprintf(stderr,"Got line %s\n",line);
60338460Smckusick 		cp = line;
60438460Smckusick 		nextfield(&cp, &endcp);
60551667Smckusick 		if (*cp == '#')
60651667Smckusick 			goto nextline;
60751898Smckusick 
60851898Smckusick 		/*
60951898Smckusick 		 * Set defaults.
61051898Smckusick 		 */
61151898Smckusick 		has_host = FALSE;
61251898Smckusick 		anon = def_anon;
61351667Smckusick 		exflags = MNT_EXPORTED;
61451898Smckusick 		got_nondir = 0;
61551898Smckusick 		opt_flags = 0;
61651898Smckusick 		ep = (struct exportlist *)0;
61744015Smckusick 
61844015Smckusick 		/*
61944015Smckusick 		 * Create new exports list entry
62044015Smckusick 		 */
62138460Smckusick 		len = endcp-cp;
62253150Smckusick 		tgrp = grp = get_grp();
62351898Smckusick 		while (len > 0) {
62451898Smckusick 			if (len > RPCMNT_NAMELEN) {
62553150Smckusick 			    getexp_err(ep, tgrp);
62651898Smckusick 			    goto nextline;
62751667Smckusick 			}
62845271Smckusick 			if (*cp == '-') {
62951898Smckusick 			    if (ep == (struct exportlist *)0) {
63053150Smckusick 				getexp_err(ep, tgrp);
63151898Smckusick 				goto nextline;
63251898Smckusick 			    }
63351898Smckusick 			    if (debug)
63451898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
63551898Smckusick 			    got_nondir = 1;
63651898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
63751898Smckusick 				&exflags, &anon)) {
63853150Smckusick 				getexp_err(ep, tgrp);
63951898Smckusick 				goto nextline;
64051898Smckusick 			    }
64151898Smckusick 			} else if (*cp == '/') {
64251898Smckusick 			    savedc = *endcp;
64351898Smckusick 			    *endcp = '\0';
644*65940Sbostic 			    if (check_dirpath(cp) &&
64551898Smckusick 				statfs(cp, &fsb) >= 0) {
64651898Smckusick 				if (got_nondir) {
64751898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
64853150Smckusick 				    getexp_err(ep, tgrp);
64951898Smckusick 				    goto nextline;
65051898Smckusick 				}
65151898Smckusick 				if (ep) {
65251898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
65351898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
65453150Smckusick 					getexp_err(ep, tgrp);
65551898Smckusick 					goto nextline;
65651898Smckusick 				    }
65751667Smckusick 				} else {
65851898Smckusick 				    /*
65951898Smckusick 				     * See if this directory is already
66051898Smckusick 				     * in the list.
66151898Smckusick 				     */
66251898Smckusick 				    ep = ex_search(&fsb.f_fsid);
66351898Smckusick 				    if (ep == (struct exportlist *)0) {
66451898Smckusick 					ep = get_exp();
66551898Smckusick 					ep->ex_fs = fsb.f_fsid;
66651898Smckusick 					ep->ex_fsdir = (char *)
66751898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
66851898Smckusick 					if (ep->ex_fsdir)
66951898Smckusick 					    strcpy(ep->ex_fsdir,
67051898Smckusick 						fsb.f_mntonname);
67151898Smckusick 					else
67251898Smckusick 					    out_of_mem();
67351898Smckusick 					if (debug)
67451898Smckusick 					  fprintf(stderr,
67551898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
67651898Smckusick 					      fsb.f_fsid.val[0],
67751898Smckusick 					      fsb.f_fsid.val[1]);
67851898Smckusick 				    } else if (debug)
67951898Smckusick 					fprintf(stderr,
68051898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
68151898Smckusick 					    fsb.f_fsid.val[0],
68251898Smckusick 					    fsb.f_fsid.val[1]);
68338460Smckusick 				}
68451898Smckusick 
68551898Smckusick 				/*
68651898Smckusick 				 * Add dirpath to export mount point.
68751898Smckusick 				 */
68851898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
68951898Smckusick 				dirplen = len;
69051898Smckusick 			    } else {
69153150Smckusick 				getexp_err(ep, tgrp);
69251898Smckusick 				goto nextline;
69351898Smckusick 			    }
69451898Smckusick 			    *endcp = savedc;
69551898Smckusick 			} else {
69651898Smckusick 			    savedc = *endcp;
69751898Smckusick 			    *endcp = '\0';
69851898Smckusick 			    got_nondir = 1;
69953150Smckusick 			    if (ep == (struct exportlist *)0) {
70053150Smckusick 				getexp_err(ep, tgrp);
70151898Smckusick 				goto nextline;
70251898Smckusick 			    }
70353150Smckusick 
70453150Smckusick 			    /*
70553150Smckusick 			     * Get the host or netgroup.
70653150Smckusick 			     */
70753150Smckusick 			    setnetgrent(cp);
70853150Smckusick 			    netgrp = getnetgrent(&hst, &usr, &dom);
70953150Smckusick 			    do {
71053150Smckusick 				if (has_host) {
71153150Smckusick 				    grp->gr_next = get_grp();
71253150Smckusick 				    grp = grp->gr_next;
71353150Smckusick 				}
71453150Smckusick 				if (netgrp) {
71553150Smckusick 				    if (get_host(hst, grp)) {
71653150Smckusick 					syslog(LOG_ERR, "Bad netgroup %s", cp);
71753150Smckusick 					getexp_err(ep, tgrp);
71853150Smckusick 					goto nextline;
71953150Smckusick 				    }
72053150Smckusick 				} else if (get_host(cp, grp)) {
72153150Smckusick 				    getexp_err(ep, tgrp);
72253150Smckusick 				    goto nextline;
72353150Smckusick 				}
72453150Smckusick 				has_host = TRUE;
72553150Smckusick 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
72653150Smckusick 			    endnetgrent();
72751898Smckusick 			    *endcp = savedc;
72838460Smckusick 			}
72938460Smckusick 			cp = endcp;
73038460Smckusick 			nextfield(&cp, &endcp);
73145271Smckusick 			len = endcp - cp;
73238460Smckusick 		}
73351898Smckusick 		if (check_options(dirhead)) {
73453150Smckusick 			getexp_err(ep, tgrp);
73551898Smckusick 			goto nextline;
73651898Smckusick 		}
73751898Smckusick 		if (!has_host) {
73851898Smckusick 			grp->gr_type = GT_HOST;
73951667Smckusick 			if (debug)
74051667Smckusick 				fprintf(stderr,"Adding a default entry\n");
74151667Smckusick 			/* add a default group and make the grp list NULL */
74251667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
74351898Smckusick 			if (hpe == (struct hostent *)0)
74451898Smckusick 				out_of_mem();
74551898Smckusick 			hpe->h_name = "Default";
74651667Smckusick 			hpe->h_addrtype = AF_INET;
74751667Smckusick 			hpe->h_length = sizeof (u_long);
74851712Smckusick 			hpe->h_addr_list = (char **)0;
74951898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
75053150Smckusick 
75153150Smckusick 		/*
75253150Smckusick 		 * Don't allow a network export coincide with a list of
75353150Smckusick 		 * host(s) on the same line.
75453150Smckusick 		 */
75553150Smckusick 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
75653150Smckusick 			getexp_err(ep, tgrp);
75753150Smckusick 			goto nextline;
75851667Smckusick 		}
75953150Smckusick 
76053150Smckusick 		/*
76153150Smckusick 		 * Loop through hosts, pushing the exports into the kernel.
76253150Smckusick 		 * After loop, tgrp points to the start of the list and
76353150Smckusick 		 * grp points to the last entry in the list.
76453150Smckusick 		 */
76553150Smckusick 		grp = tgrp;
76653150Smckusick 		do {
76753150Smckusick 		    if (do_mount(ep, grp, exflags, &anon, dirp,
76851898Smckusick 			dirplen, &fsb)) {
76953150Smckusick 			getexp_err(ep, tgrp);
77051898Smckusick 			goto nextline;
77153150Smckusick 		    }
77253150Smckusick 		} while (grp->gr_next && (grp = grp->gr_next));
77351898Smckusick 
77451898Smckusick 		/*
77551898Smckusick 		 * Success. Update the data structures.
77651898Smckusick 		 */
77751898Smckusick 		if (has_host) {
77853150Smckusick 			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
77951898Smckusick 			grp->gr_next = grphead;
78053150Smckusick 			grphead = tgrp;
78151898Smckusick 		} else {
78251898Smckusick 			hang_dirp(dirhead, (struct grouplist *)0, ep,
78353150Smckusick 			(opt_flags & OP_ALLDIRS));
78451898Smckusick 			free_grp(grp);
78551898Smckusick 		}
78651898Smckusick 		dirhead = (struct dirlist *)0;
78751898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
78851898Smckusick 			ep2 = exphead;
78951898Smckusick 			epp = &exphead;
79051898Smckusick 
79151898Smckusick 			/*
79251898Smckusick 			 * Insert in the list in alphabetical order.
79351898Smckusick 			 */
79451898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
79551898Smckusick 				epp = &ep2->ex_next;
79651898Smckusick 				ep2 = ep2->ex_next;
79751898Smckusick 			}
79851898Smckusick 			if (ep2)
79951898Smckusick 				ep->ex_next = ep2;
80051898Smckusick 			*epp = ep;
80151898Smckusick 			ep->ex_flag |= EX_LINKED;
80251898Smckusick 		}
80351898Smckusick nextline:
80451898Smckusick 		if (dirhead) {
80551898Smckusick 			free_dir(dirhead);
80651898Smckusick 			dirhead = (struct dirlist *)0;
80751898Smckusick 		}
80851898Smckusick 	}
80951898Smckusick 	fclose(exp_file);
81051898Smckusick }
81151898Smckusick 
81251898Smckusick /*
81351898Smckusick  * Allocate an export list element
81451898Smckusick  */
81551898Smckusick struct exportlist *
81651898Smckusick get_exp()
81751898Smckusick {
81851898Smckusick 	register struct exportlist *ep;
81951898Smckusick 
82051898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
82151898Smckusick 	if (ep == (struct exportlist *)0)
82251898Smckusick 		out_of_mem();
82351898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
82451898Smckusick 	return (ep);
82551898Smckusick }
82651898Smckusick 
82751898Smckusick /*
82851898Smckusick  * Allocate a group list element
82951898Smckusick  */
83051898Smckusick struct grouplist *
83151898Smckusick get_grp()
83251898Smckusick {
83351898Smckusick 	register struct grouplist *gp;
83451898Smckusick 
83551898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
83651898Smckusick 	if (gp == (struct grouplist *)0)
83751898Smckusick 		out_of_mem();
83851898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
83951898Smckusick 	return (gp);
84051898Smckusick }
84151898Smckusick 
84251898Smckusick /*
84351898Smckusick  * Clean up upon an error in get_exportlist().
84451898Smckusick  */
84551898Smckusick void
84651898Smckusick getexp_err(ep, grp)
84751898Smckusick 	struct exportlist *ep;
84851898Smckusick 	struct grouplist *grp;
84951898Smckusick {
85053150Smckusick 	struct grouplist *tgrp;
85151898Smckusick 
85251898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
85359017Smckusick 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
85451898Smckusick 		free_exp(ep);
85553150Smckusick 	while (grp) {
85653150Smckusick 		tgrp = grp;
85753150Smckusick 		grp = grp->gr_next;
85853150Smckusick 		free_grp(tgrp);
85953150Smckusick 	}
86051898Smckusick }
86151898Smckusick 
86251898Smckusick /*
86351898Smckusick  * Search the export list for a matching fs.
86451898Smckusick  */
86551898Smckusick struct exportlist *
86651898Smckusick ex_search(fsid)
86752109Smckusick 	fsid_t *fsid;
86851898Smckusick {
86951898Smckusick 	register struct exportlist *ep;
87051898Smckusick 
87151898Smckusick 	ep = exphead;
87251898Smckusick 	while (ep) {
87351898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
87451898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
87551898Smckusick 			return (ep);
87651898Smckusick 		ep = ep->ex_next;
87751898Smckusick 	}
87851898Smckusick 	return (ep);
87951898Smckusick }
88051898Smckusick 
88151898Smckusick /*
88251898Smckusick  * Add a directory path to the list.
88351898Smckusick  */
88451898Smckusick char *
88551898Smckusick add_expdir(dpp, cp, len)
88651898Smckusick 	struct dirlist **dpp;
88751898Smckusick 	char *cp;
88851898Smckusick 	int len;
88951898Smckusick {
89051898Smckusick 	register struct dirlist *dp;
89151898Smckusick 
89251898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
89351898Smckusick 	dp->dp_left = *dpp;
89451898Smckusick 	dp->dp_right = (struct dirlist *)0;
89551898Smckusick 	dp->dp_flag = 0;
89651898Smckusick 	dp->dp_hosts = (struct hostlist *)0;
89751898Smckusick 	strcpy(dp->dp_dirp, cp);
89851898Smckusick 	*dpp = dp;
89951898Smckusick 	return (dp->dp_dirp);
90051898Smckusick }
90151898Smckusick 
90251898Smckusick /*
90351898Smckusick  * Hang the dir list element off the dirpath binary tree as required
90451898Smckusick  * and update the entry for host.
90551898Smckusick  */
90651898Smckusick void
90751898Smckusick hang_dirp(dp, grp, ep, alldirs)
90851898Smckusick 	register struct dirlist *dp;
90951898Smckusick 	struct grouplist *grp;
91051898Smckusick 	struct exportlist *ep;
91151898Smckusick 	int alldirs;
91251898Smckusick {
91351898Smckusick 	register struct hostlist *hp;
91451898Smckusick 	struct dirlist *dp2;
91551898Smckusick 
91651898Smckusick 	if (alldirs) {
91751898Smckusick 		if (ep->ex_defdir)
91851898Smckusick 			free((caddr_t)dp);
91951898Smckusick 		else
92051898Smckusick 			ep->ex_defdir = dp;
92155292Smckusick 		if (grp == (struct grouplist *)0)
92255292Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
92355292Smckusick 		else while (grp) {
92451898Smckusick 			hp = get_ht();
92551898Smckusick 			hp->ht_grp = grp;
92651898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
92751898Smckusick 			ep->ex_defdir->dp_hosts = hp;
92855292Smckusick 			grp = grp->gr_next;
92955292Smckusick 		}
93051898Smckusick 	} else {
93153150Smckusick 
93253150Smckusick 		/*
93353150Smckusick 		 * Loop throught the directories adding them to the tree.
93453150Smckusick 		 */
93551898Smckusick 		while (dp) {
93651898Smckusick 			dp2 = dp->dp_left;
93753150Smckusick 			add_dlist(&ep->ex_dirl, dp, grp);
93851898Smckusick 			dp = dp2;
93951898Smckusick 		}
94051898Smckusick 	}
94151898Smckusick }
94251898Smckusick 
94351898Smckusick /*
94451898Smckusick  * Traverse the binary tree either updating a node that is already there
94551898Smckusick  * for the new directory or adding the new node.
94651898Smckusick  */
94751898Smckusick void
94853150Smckusick add_dlist(dpp, newdp, grp)
94951898Smckusick 	struct dirlist **dpp;
95051898Smckusick 	struct dirlist *newdp;
95153150Smckusick 	register struct grouplist *grp;
95251898Smckusick {
95351898Smckusick 	register struct dirlist *dp;
95453150Smckusick 	register struct hostlist *hp;
95551898Smckusick 	int cmp;
95651898Smckusick 
95751898Smckusick 	dp = *dpp;
95851898Smckusick 	if (dp) {
95951898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
96051898Smckusick 		if (cmp > 0) {
96153150Smckusick 			add_dlist(&dp->dp_left, newdp, grp);
96251898Smckusick 			return;
96351898Smckusick 		} else if (cmp < 0) {
96453150Smckusick 			add_dlist(&dp->dp_right, newdp, grp);
96551898Smckusick 			return;
96651898Smckusick 		} else
96751898Smckusick 			free((caddr_t)newdp);
96851898Smckusick 	} else {
96951898Smckusick 		dp = newdp;
97051898Smckusick 		dp->dp_left = (struct dirlist *)0;
97151898Smckusick 		*dpp = dp;
97251898Smckusick 	}
97353150Smckusick 	if (grp) {
97453150Smckusick 
97553150Smckusick 		/*
97653150Smckusick 		 * Hang all of the host(s) off of the directory point.
97753150Smckusick 		 */
97853150Smckusick 		do {
97953150Smckusick 			hp = get_ht();
98053150Smckusick 			hp->ht_grp = grp;
98153150Smckusick 			hp->ht_next = dp->dp_hosts;
98253150Smckusick 			dp->dp_hosts = hp;
98353150Smckusick 			grp = grp->gr_next;
98453150Smckusick 		} while (grp);
98551898Smckusick 	} else
98651898Smckusick 		dp->dp_flag |= DP_DEFSET;
98751898Smckusick }
98851898Smckusick 
98951898Smckusick /*
99051898Smckusick  * Search for a dirpath on the export point.
99151898Smckusick  */
99251898Smckusick struct dirlist *
99351898Smckusick dirp_search(dp, dirpath)
99451898Smckusick 	register struct dirlist *dp;
99551898Smckusick 	char *dirpath;
99651898Smckusick {
99751898Smckusick 	register int cmp;
99851898Smckusick 
99951898Smckusick 	if (dp) {
100051898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
100151898Smckusick 		if (cmp > 0)
100251898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
100351898Smckusick 		else if (cmp < 0)
100451898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
100551898Smckusick 		else
100651898Smckusick 			return (dp);
100751898Smckusick 	}
100851898Smckusick 	return (dp);
100951898Smckusick }
101051898Smckusick 
101151898Smckusick /*
101251898Smckusick  * Scan for a host match in a directory tree.
101351898Smckusick  */
101451898Smckusick chk_host(dp, saddr, defsetp)
101551898Smckusick 	struct dirlist *dp;
101651898Smckusick 	u_long saddr;
101751898Smckusick 	int *defsetp;
101851898Smckusick {
101951898Smckusick 	register struct hostlist *hp;
102051898Smckusick 	register struct grouplist *grp;
102151898Smckusick 	register u_long **addrp;
102251898Smckusick 
102351898Smckusick 	if (dp) {
102451898Smckusick 		if (dp->dp_flag & DP_DEFSET)
102551898Smckusick 			*defsetp = 1;
102651898Smckusick 		hp = dp->dp_hosts;
102751898Smckusick 		while (hp) {
102851898Smckusick 			grp = hp->ht_grp;
102951898Smckusick 			switch (grp->gr_type) {
103051898Smckusick 			case GT_HOST:
103151898Smckusick 			    addrp = (u_long **)
103251898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
103351898Smckusick 			    while (*addrp) {
103451898Smckusick 				if (**addrp == saddr)
103551898Smckusick 				    return (1);
103651898Smckusick 				addrp++;
103751898Smckusick 			    }
103851898Smckusick 			    break;
103951898Smckusick 			case GT_NET:
104051898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
104151898Smckusick 				grp->gr_ptr.gt_net.nt_net)
104251898Smckusick 				return (1);
104351898Smckusick 			    break;
104451898Smckusick 			};
104551898Smckusick 			hp = hp->ht_next;
104651898Smckusick 		}
104751898Smckusick 	}
104851898Smckusick 	return (0);
104951898Smckusick }
105051898Smckusick 
105151898Smckusick /*
105251898Smckusick  * Scan tree for a host that matches the address.
105351898Smckusick  */
105451898Smckusick scan_tree(dp, saddr)
105551898Smckusick 	register struct dirlist *dp;
105651898Smckusick 	u_long saddr;
105751898Smckusick {
105851898Smckusick 	int defset;
105951898Smckusick 
106051898Smckusick 	if (dp) {
106151898Smckusick 		if (scan_tree(dp->dp_left, saddr))
106251898Smckusick 			return (1);
106351898Smckusick 		if (chk_host(dp, saddr, &defset))
106451898Smckusick 			return (1);
106551898Smckusick 		if (scan_tree(dp->dp_right, saddr))
106651898Smckusick 			return (1);
106751898Smckusick 	}
106851898Smckusick 	return (0);
106951898Smckusick }
107051898Smckusick 
107151898Smckusick /*
107251898Smckusick  * Traverse the dirlist tree and free it up.
107351898Smckusick  */
107451898Smckusick void
107551898Smckusick free_dir(dp)
107651898Smckusick 	register struct dirlist *dp;
107751898Smckusick {
107851898Smckusick 
107951898Smckusick 	if (dp) {
108051898Smckusick 		free_dir(dp->dp_left);
108151898Smckusick 		free_dir(dp->dp_right);
108251898Smckusick 		free_host(dp->dp_hosts);
108351898Smckusick 		free((caddr_t)dp);
108451898Smckusick 	}
108551898Smckusick }
108651898Smckusick 
108751898Smckusick /*
108851898Smckusick  * Parse the option string and update fields.
108951898Smckusick  * Option arguments may either be -<option>=<value> or
109051898Smckusick  * -<option> <value>
109151898Smckusick  */
109251898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
109351898Smckusick 	char **cpp, **endcpp;
109451898Smckusick 	struct exportlist *ep;
109551898Smckusick 	struct grouplist *grp;
109651898Smckusick 	int *has_hostp;
109751898Smckusick 	int *exflagsp;
109851898Smckusick 	struct ucred *cr;
109951898Smckusick {
110051898Smckusick 	register char *cpoptarg, *cpoptend;
110151898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
110251898Smckusick 	int allflag, usedarg;
110351898Smckusick 
110451898Smckusick 	cpopt = *cpp;
110551898Smckusick 	cpopt++;
110651898Smckusick 	cp = *endcpp;
110751898Smckusick 	savedc = *cp;
110851898Smckusick 	*cp = '\0';
110951898Smckusick 	while (cpopt && *cpopt) {
111051898Smckusick 		allflag = 1;
111151898Smckusick 		usedarg = -2;
111251898Smckusick 		if (cpoptend = index(cpopt, ',')) {
111351898Smckusick 			*cpoptend++ = '\0';
111451898Smckusick 			if (cpoptarg = index(cpopt, '='))
111551898Smckusick 				*cpoptarg++ = '\0';
111651898Smckusick 		} else {
111751898Smckusick 			if (cpoptarg = index(cpopt, '='))
111851898Smckusick 				*cpoptarg++ = '\0';
111951898Smckusick 			else {
112051898Smckusick 				*cp = savedc;
112151898Smckusick 				nextfield(&cp, &endcp);
112251898Smckusick 				**endcpp = '\0';
112351898Smckusick 				if (endcp > cp && *cp != '-') {
112451898Smckusick 					cpoptarg = cp;
112551898Smckusick 					savedc2 = *endcp;
112651898Smckusick 					*endcp = '\0';
112751898Smckusick 					usedarg = 0;
112851667Smckusick 				}
112951667Smckusick 			}
113051667Smckusick 		}
113151898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
113251898Smckusick 			*exflagsp |= MNT_EXRDONLY;
113351898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
113451898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
113551898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
113651898Smckusick 			usedarg++;
113751898Smckusick 			parsecred(cpoptarg, cr);
113851898Smckusick 			if (allflag == 0) {
113951898Smckusick 				*exflagsp |= MNT_EXPORTANON;
114051898Smckusick 				opt_flags |= OP_MAPALL;
114151898Smckusick 			} else
114251898Smckusick 				opt_flags |= OP_MAPROOT;
114351898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
114451898Smckusick 			*exflagsp |= MNT_EXKERB;
114551898Smckusick 			opt_flags |= OP_KERB;
114653150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
114753150Smckusick 			!strcmp(cpopt, "m"))) {
114851898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
114951898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
115051898Smckusick 				return (1);
115151898Smckusick 			}
115251898Smckusick 			usedarg++;
115351898Smckusick 			opt_flags |= OP_MASK;
115453150Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
115553150Smckusick 			!strcmp(cpopt, "n"))) {
115651898Smckusick 			if (grp->gr_type != GT_NULL) {
115751898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
115851898Smckusick 				return (1);
115951898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
116051898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
116151898Smckusick 				return (1);
116251898Smckusick 			}
116351898Smckusick 			grp->gr_type = GT_NET;
116451898Smckusick 			*has_hostp = 1;
116551898Smckusick 			usedarg++;
116651898Smckusick 			opt_flags |= OP_NET;
116751898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
116851898Smckusick 			opt_flags |= OP_ALLDIRS;
116951898Smckusick #ifdef ISO
117051898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
117151898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
117251898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
117351898Smckusick 				return (1);
117451898Smckusick 			}
117551898Smckusick 			*has_hostp = 1;
117651898Smckusick 			usedarg++;
117751898Smckusick 			opt_flags |= OP_ISO;
117851898Smckusick #endif /* ISO */
117951898Smckusick 		} else {
118051898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
118151898Smckusick 			return (1);
118251667Smckusick 		}
118351898Smckusick 		if (usedarg >= 0) {
118451898Smckusick 			*endcp = savedc2;
118551898Smckusick 			**endcpp = savedc;
118651898Smckusick 			if (usedarg > 0) {
118751898Smckusick 				*cpp = cp;
118851898Smckusick 				*endcpp = endcp;
118951898Smckusick 			}
119051898Smckusick 			return (0);
119151898Smckusick 		}
119251898Smckusick 		cpopt = cpoptend;
119351667Smckusick 	}
119451898Smckusick 	**endcpp = savedc;
119551898Smckusick 	return (0);
119651898Smckusick }
119751898Smckusick 
119851898Smckusick /*
119951898Smckusick  * Translate a character string to the corresponding list of network
120051898Smckusick  * addresses for a hostname.
120151898Smckusick  */
120251898Smckusick get_host(cp, grp)
120351898Smckusick 	char *cp;
120451898Smckusick 	register struct grouplist *grp;
120551898Smckusick {
120651898Smckusick 	register struct hostent *hp, *nhp;
120751898Smckusick 	register char **addrp, **naddrp;
120851898Smckusick 	struct hostent t_host;
120951898Smckusick 	int i;
121051898Smckusick 	u_long saddr;
121151898Smckusick 	char *aptr[2];
121251898Smckusick 
121351898Smckusick 	if (grp->gr_type != GT_NULL)
121451898Smckusick 		return (1);
121551898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
121651898Smckusick 		if (isdigit(*cp)) {
121751898Smckusick 			saddr = inet_addr(cp);
121851898Smckusick 			if (saddr == -1) {
121951898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
122051898Smckusick 				return (1);
122151898Smckusick 			}
122251898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
122351898Smckusick 				AF_INET)) == NULL) {
122451898Smckusick 				hp = &t_host;
122551898Smckusick 				hp->h_name = cp;
122651898Smckusick 				hp->h_addrtype = AF_INET;
122751898Smckusick 				hp->h_length = sizeof (u_long);
122851898Smckusick 				hp->h_addr_list = aptr;
122951898Smckusick 				aptr[0] = (char *)&saddr;
123051898Smckusick 				aptr[1] = (char *)0;
123151898Smckusick 			}
123251898Smckusick 		} else {
123351898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
123451898Smckusick 			return (1);
123551898Smckusick 		}
123651898Smckusick 	}
123751898Smckusick 	grp->gr_type = GT_HOST;
123851898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
123951898Smckusick 		malloc(sizeof(struct hostent));
124051898Smckusick 	if (nhp == (struct hostent *)0)
124151898Smckusick 		out_of_mem();
124251898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
124351898Smckusick 		sizeof(struct hostent));
124451898Smckusick 	i = strlen(hp->h_name)+1;
124551898Smckusick 	nhp->h_name = (char *)malloc(i);
124651898Smckusick 	if (nhp->h_name == (char *)0)
124751898Smckusick 		out_of_mem();
124851898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
124951898Smckusick 	addrp = hp->h_addr_list;
125051898Smckusick 	i = 1;
125151898Smckusick 	while (*addrp++)
125251898Smckusick 		i++;
125351898Smckusick 	naddrp = nhp->h_addr_list = (char **)
125451898Smckusick 		malloc(i*sizeof(char *));
125551898Smckusick 	if (naddrp == (char **)0)
125651898Smckusick 		out_of_mem();
125751898Smckusick 	addrp = hp->h_addr_list;
125851898Smckusick 	while (*addrp) {
125951898Smckusick 		*naddrp = (char *)
126051898Smckusick 		    malloc(hp->h_length);
126151898Smckusick 		if (*naddrp == (char *)0)
126251898Smckusick 		    out_of_mem();
126351898Smckusick 		bcopy(*addrp, *naddrp,
126451898Smckusick 			hp->h_length);
126551898Smckusick 		addrp++;
126651898Smckusick 		naddrp++;
126751898Smckusick 	}
126851898Smckusick 	*naddrp = (char *)0;
126953150Smckusick 	if (debug)
127053150Smckusick 		fprintf(stderr, "got host %s\n", hp->h_name);
127151898Smckusick 	return (0);
127251898Smckusick }
127351898Smckusick 
127451898Smckusick /*
127551898Smckusick  * Free up an exports list component
127651898Smckusick  */
127751898Smckusick void
127851898Smckusick free_exp(ep)
127951898Smckusick 	register struct exportlist *ep;
128051898Smckusick {
128151898Smckusick 
128251898Smckusick 	if (ep->ex_defdir) {
128351898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
128451898Smckusick 		free((caddr_t)ep->ex_defdir);
128551898Smckusick 	}
128651898Smckusick 	if (ep->ex_fsdir)
128751898Smckusick 		free(ep->ex_fsdir);
128851898Smckusick 	free_dir(ep->ex_dirl);
128951898Smckusick 	free((caddr_t)ep);
129051898Smckusick }
129151898Smckusick 
129251898Smckusick /*
129351898Smckusick  * Free hosts.
129451898Smckusick  */
129551898Smckusick void
129651898Smckusick free_host(hp)
129751898Smckusick 	register struct hostlist *hp;
129851898Smckusick {
129951898Smckusick 	register struct hostlist *hp2;
130051898Smckusick 
130151898Smckusick 	while (hp) {
130251898Smckusick 		hp2 = hp;
130351898Smckusick 		hp = hp->ht_next;
130451898Smckusick 		free((caddr_t)hp2);
130551898Smckusick 	}
130651898Smckusick }
130751898Smckusick 
130851898Smckusick struct hostlist *
130951898Smckusick get_ht()
131051898Smckusick {
131151898Smckusick 	register struct hostlist *hp;
131251898Smckusick 
131351898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
131451898Smckusick 	if (hp == (struct hostlist *)0)
131551898Smckusick 		out_of_mem();
131651898Smckusick 	hp->ht_next = (struct hostlist *)0;
131751898Smckusick 	return (hp);
131851898Smckusick }
131951898Smckusick 
132051898Smckusick #ifdef ISO
132151898Smckusick /*
132251898Smckusick  * Translate an iso address.
132351898Smckusick  */
132451898Smckusick get_isoaddr(cp, grp)
132551898Smckusick 	char *cp;
132651898Smckusick 	struct grouplist *grp;
132751898Smckusick {
132851898Smckusick 	struct iso_addr *isop;
132951898Smckusick 	struct sockaddr_iso *isoaddr;
133051898Smckusick 
133151898Smckusick 	if (grp->gr_type != GT_NULL)
133251898Smckusick 		return (1);
133351898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
133451898Smckusick 		syslog(LOG_ERR,
133551898Smckusick 		    "iso_addr failed, ignored");
133651898Smckusick 		return (1);
133751898Smckusick 	}
133851898Smckusick 	isoaddr = (struct sockaddr_iso *)
133951898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
134051898Smckusick 	if (isoaddr == (struct sockaddr_iso *)0)
134151898Smckusick 		out_of_mem();
134251898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
134351898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
134451898Smckusick 		sizeof (struct iso_addr));
134551898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
134651898Smckusick 	isoaddr->siso_family = AF_ISO;
134751898Smckusick 	grp->gr_type = GT_ISO;
134851898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
134951898Smckusick 	return (0);
135051898Smckusick }
135151898Smckusick #endif	/* ISO */
135251898Smckusick 
135351898Smckusick /*
135451898Smckusick  * Out of memory, fatal
135551898Smckusick  */
135651898Smckusick void
135751898Smckusick out_of_mem()
135851898Smckusick {
135951898Smckusick 
136051898Smckusick 	syslog(LOG_ERR, "Out of memory");
136151667Smckusick 	exit(2);
136251667Smckusick }
136351667Smckusick 
136451898Smckusick /*
136551898Smckusick  * Do the mount syscall with the update flag to push the export info into
136651898Smckusick  * the kernel.
136751898Smckusick  */
136851898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
136951667Smckusick 	struct exportlist *ep;
137051667Smckusick 	struct grouplist *grp;
137151898Smckusick 	int exflags;
137251667Smckusick 	struct ucred *anoncrp;
137351898Smckusick 	char *dirp;
137451898Smckusick 	int dirplen;
137551898Smckusick 	struct statfs *fsb;
137651667Smckusick {
137751898Smckusick 	register char *cp = (char *)0;
137851667Smckusick 	register u_long **addrp;
137951898Smckusick 	int done;
138051898Smckusick 	char savedc;
138151898Smckusick 	struct sockaddr_in sin, imask;
138265713Shibler 	union {
138365713Shibler 		struct ufs_args ua;
138465713Shibler 		struct iso_args ia;
138565713Shibler 		struct mfs_args ma;
138665713Shibler 	} args;
138751898Smckusick 	u_long net;
138851667Smckusick 
138965713Shibler 	args.ua.fspec = 0;
139065713Shibler 	args.ua.export.ex_flags = exflags;
139165713Shibler 	args.ua.export.ex_anon = *anoncrp;
139255878Smckusick 	bzero((char *)&sin, sizeof(sin));
139355878Smckusick 	bzero((char *)&imask, sizeof(imask));
139451667Smckusick 	sin.sin_family = AF_INET;
139551667Smckusick 	sin.sin_len = sizeof(sin);
139651898Smckusick 	imask.sin_family = AF_INET;
139751898Smckusick 	imask.sin_len = sizeof(sin);
139851898Smckusick 	if (grp->gr_type == GT_HOST)
139951667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
140051898Smckusick 	else
140151898Smckusick 		addrp = (u_long **)0;
140251667Smckusick 	done = FALSE;
140351898Smckusick 	while (!done) {
140451898Smckusick 		switch (grp->gr_type) {
140551898Smckusick 		case GT_HOST:
140664903Smckusick 			if (addrp) {
140751712Smckusick 				sin.sin_addr.s_addr = **addrp;
140865713Shibler 				args.ua.export.ex_addrlen = sizeof(sin);
140964903Smckusick 			} else
141065713Shibler 				args.ua.export.ex_addrlen = 0;
141165713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
141265713Shibler 			args.ua.export.ex_masklen = 0;
141351898Smckusick 			break;
141451898Smckusick 		case GT_NET:
141551898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
141651898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
141751898Smckusick 			else {
141851898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
141951898Smckusick 			    if (IN_CLASSA(net))
142051898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
142151898Smckusick 			    else if (IN_CLASSB(net))
142251898Smckusick 				imask.sin_addr.s_addr =
142351898Smckusick 				    inet_addr("255.255.0.0");
142451898Smckusick 			    else
142551898Smckusick 				imask.sin_addr.s_addr =
142651898Smckusick 				    inet_addr("255.255.255.0");
142751898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
142851898Smckusick 			}
142951898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
143065713Shibler 			args.ua.export.ex_addr = (struct sockaddr *)&sin;
143165713Shibler 			args.ua.export.ex_addrlen = sizeof (sin);
143265713Shibler 			args.ua.export.ex_mask = (struct sockaddr *)&imask;
143365713Shibler 			args.ua.export.ex_masklen = sizeof (imask);
143451898Smckusick 			break;
143551667Smckusick #ifdef ISO
143651898Smckusick 		case GT_ISO:
143765713Shibler 			args.ua.export.ex_addr =
143865713Shibler 				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
143965713Shibler 			args.ua.export.ex_addrlen =
144065713Shibler 				sizeof(struct sockaddr_iso);
144165713Shibler 			args.ua.export.ex_masklen = 0;
144251898Smckusick 			break;
144351667Smckusick #endif	/* ISO */
144451898Smckusick 		default:
144551667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
144651898Smckusick 			if (cp)
144751898Smckusick 				*cp = savedc;
144851898Smckusick 			return (1);
144951898Smckusick 		};
145052109Smckusick 
145152109Smckusick 		/*
145252109Smckusick 		 * XXX:
145352109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
145452109Smckusick 		 * of looping back up the dirp to the mount point??
145552109Smckusick 		 * Also, needs to know how to export all types of local
145652109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
145752109Smckusick 		 */
145852109Smckusick 		while (mount(fsb->f_type, dirp,
145952109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
146051898Smckusick 			if (cp)
146151898Smckusick 				*cp-- = savedc;
146251898Smckusick 			else
146351898Smckusick 				cp = dirp + dirplen - 1;
146451667Smckusick 			if (errno == EPERM) {
146551667Smckusick 				syslog(LOG_ERR,
146651898Smckusick 				   "Can't change attributes for %s.\n", dirp);
146751898Smckusick 				return (1);
146851667Smckusick 			}
146951898Smckusick 			if (opt_flags & OP_ALLDIRS) {
147051898Smckusick 				syslog(LOG_ERR, "Not root dir");
147151898Smckusick 				return (1);
147251898Smckusick 			}
147351667Smckusick 			/* back up over the last component */
147451898Smckusick 			while (*cp == '/' && cp > dirp)
147551667Smckusick 				cp--;
147651898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
147751667Smckusick 				cp--;
147851898Smckusick 			if (cp == dirp) {
147951898Smckusick 				if (debug)
148051667Smckusick 					fprintf(stderr,"mnt unsucc\n");
148151898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
148251898Smckusick 				return (1);
148351667Smckusick 			}
148451667Smckusick 			savedc = *cp;
148551667Smckusick 			*cp = '\0';
148651667Smckusick 		}
148751898Smckusick 		if (addrp) {
148851667Smckusick 			++addrp;
148951898Smckusick 			if (*addrp == (u_long *)0)
149051667Smckusick 				done = TRUE;
149151898Smckusick 		} else
149251898Smckusick 			done = TRUE;
149351898Smckusick 	}
149451898Smckusick 	if (cp)
149551898Smckusick 		*cp = savedc;
149651898Smckusick 	return (0);
149751898Smckusick }
149851898Smckusick 
149951898Smckusick /*
150051898Smckusick  * Translate a net address.
150151898Smckusick  */
150251898Smckusick get_net(cp, net, maskflg)
150351898Smckusick 	char *cp;
150451898Smckusick 	struct netmsk *net;
150551898Smckusick 	int maskflg;
150651898Smckusick {
150751898Smckusick 	register struct netent *np;
150851898Smckusick 	register long netaddr;
150951898Smckusick 	struct in_addr inetaddr, inetaddr2;
151051898Smckusick 	char *name;
151151898Smckusick 
151251898Smckusick 	if (np = getnetbyname(cp))
151351898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
151451898Smckusick 	else if (isdigit(*cp)) {
151551898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
151651898Smckusick 			return (1);
151751898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
151851898Smckusick 		/*
151951898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
152051898Smckusick 		 * bits to shift the address to make it into a network,
152151898Smckusick 		 * however you do know how to make a network address into
152251898Smckusick 		 * a host with host == 0 and then compare them.
152351898Smckusick 		 * (What a pest)
152451898Smckusick 		 */
152551898Smckusick 		if (!maskflg) {
152651898Smckusick 			setnetent(0);
152751898Smckusick 			while (np = getnetent()) {
152851898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
152951898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
153051898Smckusick 					break;
153151898Smckusick 			}
153251898Smckusick 			endnetent();
153351667Smckusick 		}
153451898Smckusick 	} else
153551898Smckusick 		return (1);
153651898Smckusick 	if (maskflg)
153751898Smckusick 		net->nt_mask = inetaddr.s_addr;
153851898Smckusick 	else {
153951898Smckusick 		if (np)
154051898Smckusick 			name = np->n_name;
154151898Smckusick 		else
154251898Smckusick 			name = inet_ntoa(inetaddr);
154351898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
154451898Smckusick 		if (net->nt_name == (char *)0)
154551898Smckusick 			out_of_mem();
154651898Smckusick 		strcpy(net->nt_name, name);
154751898Smckusick 		net->nt_net = inetaddr.s_addr;
154838460Smckusick 	}
154951898Smckusick 	return (0);
155038460Smckusick }
155138460Smckusick 
155238460Smckusick /*
155338460Smckusick  * Parse out the next white space separated field
155438460Smckusick  */
155551667Smckusick void
155638460Smckusick nextfield(cp, endcp)
155738460Smckusick 	char **cp;
155838460Smckusick 	char **endcp;
155938460Smckusick {
156038460Smckusick 	register char *p;
156138460Smckusick 
156238460Smckusick 	p = *cp;
156338460Smckusick 	while (*p == ' ' || *p == '\t')
156438460Smckusick 		p++;
156551898Smckusick 	if (*p == '\n' || *p == '\0')
156638460Smckusick 		*cp = *endcp = p;
156751898Smckusick 	else {
156851898Smckusick 		*cp = p++;
156951898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
157051898Smckusick 			p++;
157151898Smckusick 		*endcp = p;
157238460Smckusick 	}
157338460Smckusick }
157439681Smckusick 
157539681Smckusick /*
157651898Smckusick  * Get an exports file line. Skip over blank lines and handle line
157751898Smckusick  * continuations.
157839681Smckusick  */
157951898Smckusick get_line()
158039681Smckusick {
158151898Smckusick 	register char *p, *cp;
158251898Smckusick 	register int len;
158351898Smckusick 	int totlen, cont_line;
158439681Smckusick 
158551898Smckusick 	/*
158651898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
158751898Smckusick 	 */
158851898Smckusick 	p = line;
158951898Smckusick 	totlen = 0;
159051898Smckusick 	do {
159151898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
159251898Smckusick 			return (0);
159351898Smckusick 		len = strlen(p);
159451898Smckusick 		cp = p + len - 1;
159551898Smckusick 		cont_line = 0;
159651898Smckusick 		while (cp >= p &&
159751898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
159851898Smckusick 			if (*cp == '\\')
159951898Smckusick 				cont_line = 1;
160051898Smckusick 			cp--;
160151898Smckusick 			len--;
160251898Smckusick 		}
160351898Smckusick 		*++cp = '\0';
160451898Smckusick 		if (len > 0) {
160551898Smckusick 			totlen += len;
160651898Smckusick 			if (totlen >= LINESIZ) {
160751898Smckusick 				syslog(LOG_ERR, "Exports line too long");
160851898Smckusick 				exit(2);
160951898Smckusick 			}
161051898Smckusick 			p = cp;
161151898Smckusick 		}
161251898Smckusick 	} while (totlen == 0 || cont_line);
161351898Smckusick 	return (1);
161444015Smckusick }
161544015Smckusick 
161651667Smckusick /*
161751667Smckusick  * Parse a description of a credential.
161851667Smckusick  */
161951667Smckusick parsecred(namelist, cr)
162051667Smckusick 	char *namelist;
162151667Smckusick 	register struct ucred *cr;
162251667Smckusick {
162351667Smckusick 	register char *name;
162451667Smckusick 	register int cnt;
162551667Smckusick 	char *names;
162651667Smckusick 	struct passwd *pw;
162751667Smckusick 	struct group *gr;
162851667Smckusick 	int ngroups, groups[NGROUPS + 1];
162951667Smckusick 
163051667Smckusick 	/*
163151667Smckusick 	 * Set up the unpriviledged user.
163251667Smckusick 	 */
163351667Smckusick 	cr->cr_ref = 1;
163451667Smckusick 	cr->cr_uid = -2;
163551667Smckusick 	cr->cr_groups[0] = -2;
163651667Smckusick 	cr->cr_ngroups = 1;
163751667Smckusick 	/*
163851667Smckusick 	 * Get the user's password table entry.
163951667Smckusick 	 */
164051667Smckusick 	names = strsep(&namelist, " \t\n");
164151667Smckusick 	name = strsep(&names, ":");
164251667Smckusick 	if (isdigit(*name) || *name == '-')
164351667Smckusick 		pw = getpwuid(atoi(name));
164451667Smckusick 	else
164551667Smckusick 		pw = getpwnam(name);
164651667Smckusick 	/*
164751667Smckusick 	 * Credentials specified as those of a user.
164851667Smckusick 	 */
164951667Smckusick 	if (names == NULL) {
165051667Smckusick 		if (pw == NULL) {
165151667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
165251667Smckusick 			return;
165351667Smckusick 		}
165451667Smckusick 		cr->cr_uid = pw->pw_uid;
165551667Smckusick 		ngroups = NGROUPS + 1;
165651667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
165751667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
165851667Smckusick 		/*
165951667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
166051667Smckusick 		 */
166151667Smckusick 		cr->cr_ngroups = ngroups - 1;
166251667Smckusick 		cr->cr_groups[0] = groups[0];
166351667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
166451667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
166551667Smckusick 		return;
166651667Smckusick 	}
166751667Smckusick 	/*
166851667Smckusick 	 * Explicit credential specified as a colon separated list:
166951667Smckusick 	 *	uid:gid:gid:...
167051667Smckusick 	 */
167151667Smckusick 	if (pw != NULL)
167251667Smckusick 		cr->cr_uid = pw->pw_uid;
167351667Smckusick 	else if (isdigit(*name) || *name == '-')
167451667Smckusick 		cr->cr_uid = atoi(name);
167551667Smckusick 	else {
167651667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
167751667Smckusick 		return;
167851667Smckusick 	}
167951667Smckusick 	cr->cr_ngroups = 0;
168051667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
168151667Smckusick 		name = strsep(&names, ":");
168251667Smckusick 		if (isdigit(*name) || *name == '-') {
168351667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
168451667Smckusick 		} else {
168551667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
168651667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
168751667Smckusick 				continue;
168851667Smckusick 			}
168951667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
169051667Smckusick 		}
169151667Smckusick 	}
169251667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
169351667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
169451667Smckusick }
169551667Smckusick 
169644015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
169744015Smckusick /*
169844015Smckusick  * Routines that maintain the remote mounttab
169944015Smckusick  */
170051667Smckusick void
170151667Smckusick get_mountlist()
170244015Smckusick {
170344015Smckusick 	register struct mountlist *mlp, **mlpp;
170444015Smckusick 	register char *eos, *dirp;
170544015Smckusick 	int len;
170644015Smckusick 	char str[STRSIZ];
170744015Smckusick 	FILE *mlfile;
170844015Smckusick 
170951712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
171051667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
171144015Smckusick 		return;
171244015Smckusick 	}
171344015Smckusick 	mlpp = &mlhead;
171444015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
171544015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
171644015Smckusick 		    (dirp = index(str, ' ')) == NULL)
171744015Smckusick 			continue;
171844015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
171944015Smckusick 		len = dirp-str;
172044015Smckusick 		if (len > RPCMNT_NAMELEN)
172144015Smckusick 			len = RPCMNT_NAMELEN;
172244015Smckusick 		bcopy(str, mlp->ml_host, len);
172344015Smckusick 		mlp->ml_host[len] = '\0';
172444015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
172544015Smckusick 			dirp++;
172644015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
172744015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
172844015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
172944015Smckusick 			len = strlen(dirp);
173044015Smckusick 		else
173144015Smckusick 			len = eos-dirp;
173244015Smckusick 		if (len > RPCMNT_PATHLEN)
173344015Smckusick 			len = RPCMNT_PATHLEN;
173444015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
173544015Smckusick 		mlp->ml_dirp[len] = '\0';
173644015Smckusick 		mlp->ml_next = (struct mountlist *)0;
173744015Smckusick 		*mlpp = mlp;
173844015Smckusick 		mlpp = &mlp->ml_next;
173944015Smckusick 	}
174044015Smckusick 	fclose(mlfile);
174144015Smckusick }
174244015Smckusick 
174351667Smckusick void
174451667Smckusick del_mlist(hostp, dirp)
174544015Smckusick 	register char *hostp, *dirp;
174644015Smckusick {
174744015Smckusick 	register struct mountlist *mlp, **mlpp;
174851712Smckusick 	struct mountlist *mlp2;
174944015Smckusick 	FILE *mlfile;
175044015Smckusick 	int fnd = 0;
175144015Smckusick 
175244015Smckusick 	mlpp = &mlhead;
175344015Smckusick 	mlp = mlhead;
175444015Smckusick 	while (mlp) {
175544015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
175644015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
175744015Smckusick 			fnd = 1;
175851712Smckusick 			mlp2 = mlp;
175951712Smckusick 			*mlpp = mlp = mlp->ml_next;
176051712Smckusick 			free((caddr_t)mlp2);
176151712Smckusick 		} else {
176251712Smckusick 			mlpp = &mlp->ml_next;
176351712Smckusick 			mlp = mlp->ml_next;
176439681Smckusick 		}
176539681Smckusick 	}
176644015Smckusick 	if (fnd) {
176744015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
176851898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
176944015Smckusick 			return;
177044015Smckusick 		}
177144015Smckusick 		mlp = mlhead;
177244015Smckusick 		while (mlp) {
177344015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
177444015Smckusick 			mlp = mlp->ml_next;
177544015Smckusick 		}
177644015Smckusick 		fclose(mlfile);
177744015Smckusick 	}
177839681Smckusick }
177944015Smckusick 
178051667Smckusick void
178151667Smckusick add_mlist(hostp, dirp)
178244015Smckusick 	register char *hostp, *dirp;
178344015Smckusick {
178444015Smckusick 	register struct mountlist *mlp, **mlpp;
178544015Smckusick 	FILE *mlfile;
178644015Smckusick 
178744015Smckusick 	mlpp = &mlhead;
178844015Smckusick 	mlp = mlhead;
178944015Smckusick 	while (mlp) {
179044015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
179144015Smckusick 			return;
179244015Smckusick 		mlpp = &mlp->ml_next;
179344015Smckusick 		mlp = mlp->ml_next;
179444015Smckusick 	}
179544015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
179644015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
179744015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
179844015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
179944015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
180044015Smckusick 	mlp->ml_next = (struct mountlist *)0;
180144015Smckusick 	*mlpp = mlp;
180244015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
180351898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
180444015Smckusick 		return;
180544015Smckusick 	}
180644015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
180744015Smckusick 	fclose(mlfile);
180844015Smckusick }
180944015Smckusick 
181044015Smckusick /*
181144015Smckusick  * This function is called via. SIGTERM when the system is going down.
181244015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
181344015Smckusick  */
181446709Sbostic void
181544015Smckusick send_umntall()
181644015Smckusick {
181744015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
181844015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
181951667Smckusick 	exit(0);
182044015Smckusick }
182144015Smckusick 
182244015Smckusick umntall_each(resultsp, raddr)
182344015Smckusick 	caddr_t resultsp;
182444015Smckusick 	struct sockaddr_in *raddr;
182544015Smckusick {
182644015Smckusick 	return (1);
182744015Smckusick }
182844015Smckusick 
182944015Smckusick /*
183051667Smckusick  * Free up a group list.
183151667Smckusick  */
183251667Smckusick void
183351667Smckusick free_grp(grp)
183451667Smckusick 	register struct grouplist *grp;
183551667Smckusick {
183651667Smckusick 	register char **addrp;
183751667Smckusick 
183851898Smckusick 	if (grp->gr_type == GT_HOST) {
183951712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
184051712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
184151712Smckusick 			while (addrp && *addrp)
184251712Smckusick 				free(*addrp++);
184351712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
184451712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
184551712Smckusick 		}
184651667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
184751898Smckusick 	} else if (grp->gr_type == GT_NET) {
184851898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
184951898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
185051667Smckusick 	}
185151667Smckusick #ifdef ISO
185251898Smckusick 	else if (grp->gr_type == GT_ISO)
185351667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
185451667Smckusick #endif
185551667Smckusick 	free((caddr_t)grp);
185651667Smckusick }
185751667Smckusick 
185851667Smckusick /*
185951667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
186051667Smckusick  *
186151667Smckusick  * find the real name of path, by removing all ".", ".."
186251667Smckusick  * and symlink components.
186351667Smckusick  *
186451667Smckusick  * Jan-Simon Pendry, September 1991.
186551667Smckusick  */
186651667Smckusick char *
186751667Smckusick realpath(path, resolved)
186851667Smckusick 	char *path;
186951667Smckusick 	char resolved[MAXPATHLEN];
187051667Smckusick {
187151667Smckusick 	int d = open(".", O_RDONLY);
187251667Smckusick 	int rootd = 0;
187351667Smckusick 	char *p, *q;
187451667Smckusick 	struct stat stb;
187551667Smckusick 	char wbuf[MAXPATHLEN];
187651667Smckusick 
187751667Smckusick 	strcpy(resolved, path);
187851667Smckusick 
187951667Smckusick 	if (d < 0)
188051667Smckusick 		return 0;
188151667Smckusick 
188251667Smckusick loop:;
188351667Smckusick 	q = strrchr(resolved, '/');
188451667Smckusick 	if (q) {
188551667Smckusick 		p = q + 1;
188651667Smckusick 		if (q == resolved)
188751667Smckusick 			q = "/";
188851667Smckusick 		else {
188951667Smckusick 			do
189051667Smckusick 				--q;
189151667Smckusick 			while (q > resolved && *q == '/');
189251667Smckusick 			q[1] = '\0';
189351667Smckusick 			q = resolved;
189451667Smckusick 		}
189551667Smckusick 		if (chdir(q) < 0)
189651667Smckusick 			goto out;
189751667Smckusick 	} else
189851667Smckusick 		p = resolved;
189951667Smckusick 
190051667Smckusick 	if (lstat(p, &stb) == 0) {
190151667Smckusick 		if (S_ISLNK(stb.st_mode)) {
190251667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
190351667Smckusick 			if (n < 0)
190451667Smckusick 				goto out;
190551667Smckusick 			resolved[n] = '\0';
190651667Smckusick 			goto loop;
190751667Smckusick 		}
190851667Smckusick 		if (S_ISDIR(stb.st_mode)) {
190951667Smckusick 			if (chdir(p) < 0)
191051667Smckusick 				goto out;
191151667Smckusick 			p = "";
191251667Smckusick 		}
191351667Smckusick 	}
191451667Smckusick 
191551667Smckusick 	strcpy(wbuf, p);
191651667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
191751667Smckusick 		goto out;
191851667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
191951667Smckusick 		rootd = 1;
192051667Smckusick 
192151667Smckusick 	if (*wbuf) {
192251667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
192351667Smckusick 			errno = ENAMETOOLONG;
192451667Smckusick 			goto out;
192551667Smckusick 		}
192651667Smckusick 		if (rootd == 0)
192751667Smckusick 			strcat(resolved, "/");
192851667Smckusick 		strcat(resolved, wbuf);
192951667Smckusick 	}
193051667Smckusick 
193151667Smckusick 	if (fchdir(d) < 0)
193251667Smckusick 		goto out;
193351667Smckusick 	(void) close(d);
193451667Smckusick 
193551667Smckusick 	return resolved;
193651667Smckusick 
193751667Smckusick out:;
193851667Smckusick 	(void) close(d);
193951667Smckusick 	return 0;
194051667Smckusick }
194151711Smckusick 
194251711Smckusick #ifdef DEBUG
194351711Smckusick void
194451711Smckusick SYSLOG(int pri, const char *fmt, ...)
194551711Smckusick {
194651711Smckusick 	va_list ap;
194751711Smckusick 
194851711Smckusick 	va_start(ap, fmt);
194951711Smckusick 	vfprintf(stderr, fmt, ap);
195051711Smckusick 	va_end(ap);
195151711Smckusick }
195251711Smckusick #endif /* DEBUG */
195351898Smckusick 
195451898Smckusick /*
195551898Smckusick  * Check options for consistency.
195651898Smckusick  */
195751898Smckusick check_options(dp)
195851898Smckusick 	struct dirlist *dp;
195951898Smckusick {
196051898Smckusick 
196151898Smckusick 	if (dp == (struct dirlist *)0)
196251898Smckusick 	    return (1);
196351898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
196451898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
196551898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
196651898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
196751898Smckusick 	    return (1);
196851898Smckusick 	}
196951898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
197051898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
197151898Smckusick 	    return (1);
197251898Smckusick 	}
197351898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
197451898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
197551898Smckusick 	    return (1);
197651898Smckusick 	}
197751898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
197851898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
197951898Smckusick 	    return (1);
198051898Smckusick 	}
198151898Smckusick 	return (0);
198251898Smckusick }
1983*65940Sbostic 
1984*65940Sbostic /*
1985*65940Sbostic  * Check an absolute directory path for any symbolic links. Return true
1986*65940Sbostic  * if no symbolic links are found.
1987*65940Sbostic  */
1988*65940Sbostic int
1989*65940Sbostic check_dirpath(dirp)
1990*65940Sbostic 	register char *dirp;
1991*65940Sbostic {
1992*65940Sbostic 	register char *cp;
1993*65940Sbostic 	int ret = 1;
1994*65940Sbostic 	struct stat sb;
1995*65940Sbostic 
1996*65940Sbostic 	cp = dirp + 1;
1997*65940Sbostic 	while (*cp && ret) {
1998*65940Sbostic 		if (*cp == '/') {
1999*65940Sbostic 			*cp = '\0';
2000*65940Sbostic 			if (lstat(dirp, &sb) < 0 ||
2001*65940Sbostic 				(sb.st_mode & S_IFMT) != S_IFDIR)
2002*65940Sbostic 				ret = 0;
2003*65940Sbostic 			*cp = '/';
2004*65940Sbostic 		}
2005*65940Sbostic 		cp++;
2006*65940Sbostic 	}
2007*65940Sbostic 	if (lstat(dirp, &sb) < 0 ||
2008*65940Sbostic 		(sb.st_mode & S_IFMT) != S_IFDIR)
2009*65940Sbostic 		ret = 0;
2010*65940Sbostic 	return (ret);
2011*65940Sbostic }
2012