xref: /csrg-svn/sbin/mountd/mountd.c (revision 52109)
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*52109Smckusick static char sccsid[] = "@(#)mountd.c	5.20 (Berkeley) 01/06/92";
1938460Smckusick #endif not lint
2038460Smckusick 
2151667Smckusick #include <pwd.h>
2251667Smckusick #include <grp.h>
2351667Smckusick #include <unistd.h>
2451667Smckusick #include <stdlib.h>
2538460Smckusick #include <sys/param.h>
2638460Smckusick #include <sys/ioctl.h>
2738460Smckusick #include <sys/stat.h>
2839681Smckusick #include <sys/file.h>
2951667Smckusick #include <sys/ucred.h>
3038460Smckusick #include <sys/mount.h>
3138460Smckusick #include <sys/socket.h>
3238460Smckusick #include <sys/errno.h>
3342038Sbostic #include <sys/signal.h>
3442038Sbostic #include <stdio.h>
3542038Sbostic #include <string.h>
36*52109Smckusick #include <sys/syslog.h>
3738460Smckusick #include <netdb.h>
3838460Smckusick #include <rpc/rpc.h>
3938460Smckusick #include <rpc/pmap_clnt.h>
4038460Smckusick #include <rpc/pmap_prot.h>
4151667Smckusick #ifdef ISO
4251667Smckusick #include <netiso/iso.h>
4351667Smckusick #endif
4438460Smckusick #include <nfs/rpcv2.h>
4538460Smckusick #include <nfs/nfsv2.h>
4639681Smckusick #include "pathnames.h"
4738460Smckusick 
4838460Smckusick /*
4938460Smckusick  * Structures for keeping the mount list and export list
5038460Smckusick  */
5138460Smckusick struct mountlist {
5244015Smckusick 	struct mountlist *ml_next;
5338460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
5438460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
5538460Smckusick };
5638460Smckusick 
5751898Smckusick struct dirlist {
5851898Smckusick 	struct dirlist	*dp_left;
5951898Smckusick 	struct dirlist	*dp_right;
6051898Smckusick 	int		dp_flag;
6151898Smckusick 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
6251898Smckusick 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
6351898Smckusick };
6451898Smckusick /* dp_flag bits */
6551898Smckusick #define	DP_DEFSET	0x1
6651898Smckusick 
6738460Smckusick struct exportlist {
6838460Smckusick 	struct exportlist *ex_next;
6951898Smckusick 	struct dirlist	*ex_dirl;
7051898Smckusick 	struct dirlist	*ex_defdir;
7151898Smckusick 	int		ex_flag;
7251898Smckusick 	fsid_t		ex_fs;
7351898Smckusick 	char		*ex_fsdir;
7438460Smckusick };
7551898Smckusick /* ex_flag bits */
76*52109Smckusick #define	EX_LINKED	0x1
7738460Smckusick 
7851898Smckusick struct netmsk {
7951898Smckusick 	u_long	nt_net;
8051898Smckusick 	u_long	nt_mask;
8151898Smckusick 	char *nt_name;
8251898Smckusick };
8351898Smckusick 
8451667Smckusick union grouptypes {
8551667Smckusick 	struct hostent *gt_hostent;
8651898Smckusick 	struct netmsk	gt_net;
8751667Smckusick #ifdef ISO
8851667Smckusick 	struct sockaddr_iso *gt_isoaddr;
8951667Smckusick #endif
9051667Smckusick };
9151667Smckusick 
9238460Smckusick struct grouplist {
9351898Smckusick 	int gr_type;
9451667Smckusick 	union grouptypes gr_ptr;
9538460Smckusick 	struct grouplist *gr_next;
9638460Smckusick };
9751898Smckusick /* Group types */
9851898Smckusick #define	GT_NULL		0x0
9951898Smckusick #define	GT_HOST		0x1
10051898Smckusick #define	GT_NET		0x2
10151898Smckusick #define	GT_ISO		0x4
10238460Smckusick 
10351898Smckusick struct hostlist {
10451898Smckusick 	struct grouplist *ht_grp;
10551898Smckusick 	struct hostlist	 *ht_next;
10651667Smckusick };
10751667Smckusick 
10838460Smckusick /* Global defs */
10946709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
11051898Smckusick void get_exportlist(), send_umntall(), nextfield(), out_of_mem();
11151667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
11251898Smckusick void getexp_err(), hang_dirp(), add_dlist(), free_dir(), free_host();
11351898Smckusick struct exportlist *ex_search(), *get_exp();
11451898Smckusick struct grouplist *get_grp();
11551898Smckusick char *realpath(), *add_expdir();
11651898Smckusick struct in_addr inet_makeaddr();
11751898Smckusick char *inet_ntoa();
11851898Smckusick struct dirlist *dirp_search();
11951898Smckusick struct hostlist *get_ht();
12051667Smckusick #ifdef ISO
12151667Smckusick struct iso_addr *iso_addr();
12251667Smckusick #endif
12351898Smckusick struct exportlist *exphead;
12444015Smckusick struct mountlist *mlhead;
12551898Smckusick struct grouplist *grphead;
12638460Smckusick char exname[MAXPATHLEN];
12751667Smckusick struct ucred def_anon = {
12851667Smckusick 	(u_short) 1,
12951667Smckusick 	(uid_t) -2,
13051667Smckusick 	1,
13151667Smckusick 	(gid_t) -2,
13251667Smckusick };
13344015Smckusick int root_only = 1;
13451898Smckusick int opt_flags;
13551898Smckusick /* Bits for above */
13651898Smckusick #define	OP_MAPROOT	0x01
13751898Smckusick #define	OP_MAPALL	0x02
13851898Smckusick #define	OP_KERB		0x04
13951898Smckusick #define	OP_MASK		0x08
14051898Smckusick #define	OP_NET		0x10
14151898Smckusick #define	OP_ISO		0x20
14251898Smckusick #define	OP_ALLDIRS	0x40
14351898Smckusick 
14438460Smckusick extern int errno;
14538460Smckusick #ifdef DEBUG
14638460Smckusick int debug = 1;
14751711Smckusick void	SYSLOG __P((int, const char *, ...));
14851711Smckusick #define syslog SYSLOG
14938460Smckusick #else
15038460Smckusick int debug = 0;
15138460Smckusick #endif
15238460Smckusick 
15338460Smckusick /*
15438460Smckusick  * Mountd server for NFS mount protocol as described in:
15539681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
15644015Smckusick  * The optional arguments are the exports file name
15739681Smckusick  * default: _PATH_EXPORTS
15844015Smckusick  * and "-n" to allow nonroot mount.
15938460Smckusick  */
16038460Smckusick main(argc, argv)
16138460Smckusick 	int argc;
16244015Smckusick 	char **argv;
16338460Smckusick {
16438460Smckusick 	SVCXPRT *transp;
16544015Smckusick 	int c;
16644015Smckusick 	extern int optind;
16744015Smckusick 	extern char *optarg;
16838460Smckusick 
16944015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
17044015Smckusick 		switch (c) {
17144015Smckusick 		case 'n':
17244015Smckusick 			root_only = 0;
17344015Smckusick 			break;
17444015Smckusick 		default:
17544015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
17644015Smckusick 			exit(1);
17744015Smckusick 		};
17844015Smckusick 	argc -= optind;
17944015Smckusick 	argv += optind;
18051898Smckusick 	grphead = (struct grouplist *)0;
18151898Smckusick 	exphead = (struct exportlist *)0;
18244015Smckusick 	mlhead = (struct mountlist *)0;
18344015Smckusick 	if (argc == 1) {
18444015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
18544015Smckusick 		exname[MAXPATHLEN-1] = '\0';
18644015Smckusick 	} else
18744015Smckusick 		strcpy(exname, _PATH_EXPORTS);
18844338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
18951667Smckusick 	if (debug)
19051667Smckusick 		fprintf(stderr,"Getting export list.\n");
19144015Smckusick 	get_exportlist();
19251667Smckusick 	if (debug)
19351667Smckusick 		fprintf(stderr,"Getting mount list.\n");
19444015Smckusick 	get_mountlist();
19551667Smckusick 	if (debug)
19651667Smckusick 		fprintf(stderr,"Here we go.\n");
19738460Smckusick 	if (debug == 0) {
19844690Skarels 		daemon(0, 0);
19938460Smckusick 		signal(SIGINT, SIG_IGN);
20038460Smckusick 		signal(SIGQUIT, SIG_IGN);
20138460Smckusick 	}
20238460Smckusick 	signal(SIGHUP, get_exportlist);
20344015Smckusick 	signal(SIGTERM, send_umntall);
20440494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
20540494Smckusick 	  if (pidfile != NULL) {
20640494Smckusick 		fprintf(pidfile, "%d\n", getpid());
20740494Smckusick 		fclose(pidfile);
20840494Smckusick 	  }
20940494Smckusick 	}
21038460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
21138460Smckusick 		syslog(LOG_ERR, "Can't create socket");
21238460Smckusick 		exit(1);
21338460Smckusick 	}
21438460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
21551667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
21651667Smckusick 	    IPPROTO_UDP)) {
21738460Smckusick 		syslog(LOG_ERR, "Can't register mount");
21838460Smckusick 		exit(1);
21938460Smckusick 	}
22038460Smckusick 	svc_run();
22138460Smckusick 	syslog(LOG_ERR, "Mountd died");
22244690Skarels 	exit(1);
22338460Smckusick }
22438460Smckusick 
22538460Smckusick /*
22638460Smckusick  * The mount rpc service
22738460Smckusick  */
22838460Smckusick mntsrv(rqstp, transp)
22938460Smckusick 	register struct svc_req *rqstp;
23038460Smckusick 	register SVCXPRT *transp;
23138460Smckusick {
23238460Smckusick 	register struct exportlist *ep;
23351898Smckusick 	register struct dirlist *dp;
23438460Smckusick 	nfsv2fh_t nfh;
23538460Smckusick 	struct authunix_parms *ucr;
23638460Smckusick 	struct stat stb;
23751898Smckusick 	struct statfs fsb;
23838460Smckusick 	struct hostent *hp;
23939681Smckusick 	u_long saddr;
24051667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
24151898Smckusick 	int bad = ENOENT, omask, defset;
24239681Smckusick 	uid_t uid = -2;
24338460Smckusick 
24438460Smckusick 	/* Get authorization */
24538460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
24638460Smckusick 	case AUTH_UNIX:
24738460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
24839681Smckusick 		uid = ucr->aup_uid;
24939681Smckusick 		break;
25038460Smckusick 	case AUTH_NULL:
25138460Smckusick 	default:
25239681Smckusick 		break;
25338460Smckusick 	}
25438460Smckusick 
25539681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
25639681Smckusick 	hp = (struct hostent *)0;
25738460Smckusick 	switch (rqstp->rq_proc) {
25839681Smckusick 	case NULLPROC:
25939681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
26039681Smckusick 			syslog(LOG_ERR, "Can't send reply");
26139681Smckusick 		return;
26238460Smckusick 	case RPCMNT_MOUNT:
26351667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
26439681Smckusick 			svcerr_weakauth(transp);
26539681Smckusick 			return;
26639681Smckusick 		}
26751667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
26838460Smckusick 			svcerr_decode(transp);
26938460Smckusick 			return;
27038460Smckusick 		}
27138460Smckusick 
27251667Smckusick 		/*
27351667Smckusick 		 * Get the real pathname and make sure it is a directory
27451667Smckusick 		 * that exists.
27551667Smckusick 		 */
27651898Smckusick 		if (realpath(rpcpath, dirpath) == 0 ||
27751898Smckusick 		    stat(dirpath, &stb) < 0 ||
27851898Smckusick 		    (stb.st_mode & S_IFMT) != S_IFDIR ||
27951898Smckusick 		    statfs(dirpath, &fsb) < 0) {
28051667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
28151667Smckusick 			if (debug)
28251898Smckusick 				fprintf(stderr, "stat failed on %s\n", dirpath);
28338460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
28438460Smckusick 				syslog(LOG_ERR, "Can't send reply");
28538460Smckusick 			return;
28638460Smckusick 		}
28738460Smckusick 
28838460Smckusick 		/* Check in the exports list */
28938460Smckusick 		omask = sigblock(sigmask(SIGHUP));
29051898Smckusick 		ep = ex_search(&fsb.f_fsid);
29151898Smckusick 		defset = 0;
29251898Smckusick 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
29351898Smckusick 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
29451898Smckusick 		     chk_host(dp, saddr, &defset)) ||
29551898Smckusick 		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
29651898Smckusick 		      scan_tree(ep->ex_dirl, saddr) == 0))) {
29751667Smckusick 			/* Get the file handle */
29851667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
29951667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
30051667Smckusick 				bad = errno;
30151898Smckusick 				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
30251667Smckusick 				if (!svc_sendreply(transp, xdr_long,
30351667Smckusick 				    (caddr_t)&bad))
30451667Smckusick 					syslog(LOG_ERR, "Can't send reply");
30551667Smckusick 				sigsetmask(omask);
30651667Smckusick 				return;
30751667Smckusick 			}
30851667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
30938460Smckusick 				syslog(LOG_ERR, "Can't send reply");
31051667Smckusick 			if (hp == NULL)
31151667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
31251667Smckusick 				    sizeof(saddr), AF_INET);
31351667Smckusick 			if (hp)
31451667Smckusick 				add_mlist(hp->h_name, dirpath);
31551667Smckusick 			else
31651667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
31751667Smckusick 					dirpath);
31851667Smckusick 			if (debug)
31951667Smckusick 				fprintf(stderr,"Mount successfull.\n");
32051898Smckusick 		} else {
32151898Smckusick 			bad = EACCES;
32251898Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
32351898Smckusick 				syslog(LOG_ERR, "Can't send reply");
32438460Smckusick 		}
32551667Smckusick 		sigsetmask(omask);
32638460Smckusick 		return;
32738460Smckusick 	case RPCMNT_DUMP:
32838460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
32938460Smckusick 			syslog(LOG_ERR, "Can't send reply");
33038460Smckusick 		return;
33138460Smckusick 	case RPCMNT_UMOUNT:
33251667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
33339681Smckusick 			svcerr_weakauth(transp);
33439681Smckusick 			return;
33539681Smckusick 		}
33638460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
33738460Smckusick 			svcerr_decode(transp);
33838460Smckusick 			return;
33938460Smckusick 		}
34038460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
34138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
34244015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
34344015Smckusick 		if (hp)
34444015Smckusick 			del_mlist(hp->h_name, dirpath);
34551667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
34638460Smckusick 		return;
34738460Smckusick 	case RPCMNT_UMNTALL:
34851667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
34939681Smckusick 			svcerr_weakauth(transp);
35039681Smckusick 			return;
35139681Smckusick 		}
35238460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
35338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
35444015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
35544015Smckusick 		if (hp)
35644015Smckusick 			del_mlist(hp->h_name, (char *)0);
35751667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
35838460Smckusick 		return;
35938460Smckusick 	case RPCMNT_EXPORT:
36038460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
36138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
36238460Smckusick 		return;
36338460Smckusick 	default:
36438460Smckusick 		svcerr_noproc(transp);
36538460Smckusick 		return;
36638460Smckusick 	}
36738460Smckusick }
36838460Smckusick 
36938460Smckusick /*
37038460Smckusick  * Xdr conversion for a dirpath string
37138460Smckusick  */
37238460Smckusick xdr_dir(xdrsp, dirp)
37338460Smckusick 	XDR *xdrsp;
37438460Smckusick 	char *dirp;
37538460Smckusick {
37638460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
37738460Smckusick }
37838460Smckusick 
37938460Smckusick /*
38038460Smckusick  * Xdr routine to generate fhstatus
38138460Smckusick  */
38238460Smckusick xdr_fhs(xdrsp, nfh)
38338460Smckusick 	XDR *xdrsp;
38438460Smckusick 	nfsv2fh_t *nfh;
38538460Smckusick {
38638460Smckusick 	int ok = 0;
38738460Smckusick 
38838460Smckusick 	if (!xdr_long(xdrsp, &ok))
38938460Smckusick 		return (0);
39038460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
39138460Smckusick }
39238460Smckusick 
39338460Smckusick xdr_mlist(xdrsp, cp)
39438460Smckusick 	XDR *xdrsp;
39538460Smckusick 	caddr_t cp;
39638460Smckusick {
39744015Smckusick 	register struct mountlist *mlp;
39838460Smckusick 	int true = 1;
39938460Smckusick 	int false = 0;
40038460Smckusick 	char *strp;
40138460Smckusick 
40244015Smckusick 	mlp = mlhead;
40344015Smckusick 	while (mlp) {
40444015Smckusick 		if (!xdr_bool(xdrsp, &true))
40544015Smckusick 			return (0);
40644015Smckusick 		strp = &mlp->ml_host[0];
40744015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
40844015Smckusick 			return (0);
40944015Smckusick 		strp = &mlp->ml_dirp[0];
41044015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
41144015Smckusick 			return (0);
41244015Smckusick 		mlp = mlp->ml_next;
41338460Smckusick 	}
41438460Smckusick 	if (!xdr_bool(xdrsp, &false))
41538460Smckusick 		return (0);
41638460Smckusick 	return (1);
41738460Smckusick }
41838460Smckusick 
41938460Smckusick /*
42038460Smckusick  * Xdr conversion for export list
42138460Smckusick  */
42238460Smckusick xdr_explist(xdrsp, cp)
42338460Smckusick 	XDR *xdrsp;
42438460Smckusick 	caddr_t cp;
42538460Smckusick {
42638460Smckusick 	register struct exportlist *ep;
42738460Smckusick 	int false = 0;
42838460Smckusick 	int omask;
42938460Smckusick 
43038460Smckusick 	omask = sigblock(sigmask(SIGHUP));
43151898Smckusick 	ep = exphead;
43251898Smckusick 	while (ep) {
43351898Smckusick 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir))
43438460Smckusick 			goto errout;
43538460Smckusick 		ep = ep->ex_next;
43638460Smckusick 	}
43738460Smckusick 	sigsetmask(omask);
43838460Smckusick 	if (!xdr_bool(xdrsp, &false))
43938460Smckusick 		return (0);
44038460Smckusick 	return (1);
44138460Smckusick errout:
44238460Smckusick 	sigsetmask(omask);
44338460Smckusick 	return (0);
44438460Smckusick }
44538460Smckusick 
44651898Smckusick /*
44751898Smckusick  * Called from xdr_explist() to traverse the tree and export the
44851898Smckusick  * directory paths.
44951898Smckusick  */
45051898Smckusick put_exlist(dp, xdrsp, adp)
45151898Smckusick 	register struct dirlist *dp;
45251898Smckusick 	XDR *xdrsp;
45351898Smckusick 	struct dirlist *adp;
45451898Smckusick {
45551898Smckusick 	register struct grouplist *grp;
45651898Smckusick 	register struct hostlist *hp;
45751898Smckusick 	struct in_addr inaddr;
45851898Smckusick 	int true = 1;
45951898Smckusick 	int false = 0;
46051898Smckusick 	int gotalldir = 0;
46151898Smckusick 	char *strp;
46251898Smckusick 
46351898Smckusick 	if (dp) {
46451898Smckusick 		if (put_exlist(dp->dp_left, xdrsp, adp))
46551898Smckusick 			return (1);
46651898Smckusick 		if (!xdr_bool(xdrsp, &true))
46751898Smckusick 			return (1);
46851898Smckusick 		strp = dp->dp_dirp;
46951898Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
47051898Smckusick 			return (1);
47151898Smckusick 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp))
47251898Smckusick 			gotalldir = 1;
47351898Smckusick 		if ((dp->dp_flag & DP_DEFSET) == 0 &&
47451898Smckusick 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
47551898Smckusick 			hp = dp->dp_hosts;
47651898Smckusick 			while (hp) {
47751898Smckusick 				grp = hp->ht_grp;
47851898Smckusick 				if (grp->gr_type == GT_HOST) {
47951898Smckusick 					if (!xdr_bool(xdrsp, &true))
48051898Smckusick 						return (1);
48151898Smckusick 					strp = grp->gr_ptr.gt_hostent->h_name;
48251898Smckusick 					if (!xdr_string(xdrsp, &strp,
48351898Smckusick 					    RPCMNT_NAMELEN))
48451898Smckusick 						return (1);
48551898Smckusick 				} else if (grp->gr_type == GT_NET) {
48651898Smckusick 					if (!xdr_bool(xdrsp, &true))
48751898Smckusick 						return (1);
48851898Smckusick 					strp = grp->gr_ptr.gt_net.nt_name;
48951898Smckusick 					if (!xdr_string(xdrsp, &strp,
49051898Smckusick 					    RPCMNT_NAMELEN))
49151898Smckusick 						return (1);
49251898Smckusick 				}
49351898Smckusick 				hp = hp->ht_next;
49451898Smckusick 				if (gotalldir && hp == (struct hostlist *)0) {
49551898Smckusick 					hp = adp->dp_hosts;
49651898Smckusick 					gotalldir = 0;
49751898Smckusick 				}
49851898Smckusick 			}
49951898Smckusick 		}
50051898Smckusick 		if (!xdr_bool(xdrsp, &false))
50151898Smckusick 			return (1);
50251898Smckusick 		if (put_exlist(dp->dp_right, xdrsp, adp))
50351898Smckusick 			return (1);
50451898Smckusick 	}
50551898Smckusick 	return (0);
50651898Smckusick }
50751898Smckusick 
50838460Smckusick #define LINESIZ	10240
50938460Smckusick char line[LINESIZ];
51051898Smckusick FILE *exp_file;
51138460Smckusick 
51238460Smckusick /*
51338460Smckusick  * Get the export list
51438460Smckusick  */
51546709Sbostic void
51638460Smckusick get_exportlist()
51738460Smckusick {
51838460Smckusick 	register struct exportlist *ep, *ep2;
51951898Smckusick 	register struct grouplist *grp, *tgrp;
52051898Smckusick 	struct exportlist **epp;
52151898Smckusick 	struct dirlist *dirhead;
52251898Smckusick 	struct stat sb;
523*52109Smckusick 	struct statfs fsb, *fsp;
52451898Smckusick 	struct hostent *hpe;
52551898Smckusick 	struct ucred anon;
526*52109Smckusick 	struct ufs_args targs;
52751898Smckusick 	char *cp, *endcp, *dirp;
52839681Smckusick 	char savedc;
529*52109Smckusick 	int len, has_host, exflags, got_nondir, dirplen, num, i;
53038460Smckusick 
53138460Smckusick 	/*
53238460Smckusick 	 * First, get rid of the old list
53338460Smckusick 	 */
53451898Smckusick 	ep = exphead;
53551898Smckusick 	while (ep) {
53638460Smckusick 		ep2 = ep;
53738460Smckusick 		ep = ep->ex_next;
53844015Smckusick 		free_exp(ep2);
53938460Smckusick 	}
54051898Smckusick 	exphead = (struct exportlist *)0;
54138460Smckusick 
54251898Smckusick 	grp = grphead;
54351898Smckusick 	while (grp) {
54451898Smckusick 		tgrp = grp;
54551898Smckusick 		grp = grp->gr_next;
54651898Smckusick 		free_grp(tgrp);
54751667Smckusick 	}
54851898Smckusick 	grphead = (struct grouplist *)0;
54951667Smckusick 
55038460Smckusick 	/*
551*52109Smckusick 	 * And delete exports that are in the kernel for all local
552*52109Smckusick 	 * file systems.
553*52109Smckusick 	 * XXX: Should know how to handle all local exportable file systems
554*52109Smckusick 	 *      instead of just MOUNT_UFS.
555*52109Smckusick 	 */
556*52109Smckusick 	num = getmntinfo(&fsp, MNT_WAIT);
557*52109Smckusick 	for (i = 0; i < num; i++) {
558*52109Smckusick 		if (fsp->f_type == MOUNT_UFS) {
559*52109Smckusick 			targs.fspec = (char *)0;
560*52109Smckusick 			targs.exflags = MNT_DELEXPORT;
561*52109Smckusick 			if (mount(fsp->f_type, fsp->f_mntonname,
562*52109Smckusick 			    fsp->f_flags | MNT_UPDATE, (caddr_t)&targs) < 0)
563*52109Smckusick 				syslog(LOG_ERR, "Can't del exports %s",
564*52109Smckusick 				       fsp->f_mntonname);
565*52109Smckusick 		}
566*52109Smckusick 		fsp++;
567*52109Smckusick 	}
568*52109Smckusick 
569*52109Smckusick 	/*
57038460Smckusick 	 * Read in the exports file and build the list, calling
57151667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
57238460Smckusick 	 */
57351898Smckusick 	if ((exp_file = fopen(exname, "r")) == NULL) {
57438460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
57538460Smckusick 		exit(2);
57638460Smckusick 	}
57751898Smckusick 	dirhead = (struct dirlist *)0;
57851898Smckusick 	while (get_line()) {
57951667Smckusick 		if (debug)
58051667Smckusick 			fprintf(stderr,"Got line %s\n",line);
58138460Smckusick 		cp = line;
58238460Smckusick 		nextfield(&cp, &endcp);
58351667Smckusick 		if (*cp == '#')
58451667Smckusick 			goto nextline;
58551898Smckusick 
58651898Smckusick 		/*
58751898Smckusick 		 * Set defaults.
58851898Smckusick 		 */
58951898Smckusick 		has_host = FALSE;
59051898Smckusick 		anon = def_anon;
59151667Smckusick 		exflags = MNT_EXPORTED;
59251898Smckusick 		got_nondir = 0;
59351898Smckusick 		opt_flags = 0;
59451898Smckusick 		ep = (struct exportlist *)0;
59544015Smckusick 
59644015Smckusick 		/*
59744015Smckusick 		 * Create new exports list entry
59844015Smckusick 		 */
59938460Smckusick 		len = endcp-cp;
60051898Smckusick 		grp = get_grp();
60151898Smckusick 		while (len > 0) {
60251898Smckusick 			if (len > RPCMNT_NAMELEN) {
60351898Smckusick 			    getexp_err(ep, grp);
60451898Smckusick 			    goto nextline;
60551667Smckusick 			}
60645271Smckusick 			if (*cp == '-') {
60751898Smckusick 			    if (ep == (struct exportlist *)0) {
60851898Smckusick 				getexp_err(ep, grp);
60951898Smckusick 				goto nextline;
61051898Smckusick 			    }
61151898Smckusick 			    if (debug)
61251898Smckusick 				fprintf(stderr, "doing opt %s\n", cp);
61351898Smckusick 			    got_nondir = 1;
61451898Smckusick 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
61551898Smckusick 				&exflags, &anon)) {
61651898Smckusick 				getexp_err(ep, grp);
61751898Smckusick 				goto nextline;
61851898Smckusick 			    }
61951898Smckusick 			} else if (*cp == '/') {
62051898Smckusick 			    savedc = *endcp;
62151898Smckusick 			    *endcp = '\0';
62251898Smckusick 			    if (stat(cp, &sb) >= 0 &&
62351898Smckusick 				(sb.st_mode & S_IFMT) == S_IFDIR &&
62451898Smckusick 				statfs(cp, &fsb) >= 0) {
62551898Smckusick 				if (got_nondir) {
62651898Smckusick 				    syslog(LOG_ERR, "Dirs must be first");
62751898Smckusick 				    getexp_err(ep, grp);
62851898Smckusick 				    goto nextline;
62951898Smckusick 				}
63051898Smckusick 				if (ep) {
63151898Smckusick 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
63251898Smckusick 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
63351898Smckusick 					getexp_err(ep, grp);
63451898Smckusick 					goto nextline;
63551898Smckusick 				    }
63651667Smckusick 				} else {
63751898Smckusick 				    /*
63851898Smckusick 				     * See if this directory is already
63951898Smckusick 				     * in the list.
64051898Smckusick 				     */
64151898Smckusick 				    ep = ex_search(&fsb.f_fsid);
64251898Smckusick 				    if (ep == (struct exportlist *)0) {
64351898Smckusick 					ep = get_exp();
64451898Smckusick 					ep->ex_fs = fsb.f_fsid;
64551898Smckusick 					ep->ex_fsdir = (char *)
64651898Smckusick 					    malloc(strlen(fsb.f_mntonname) + 1);
64751898Smckusick 					if (ep->ex_fsdir)
64851898Smckusick 					    strcpy(ep->ex_fsdir,
64951898Smckusick 						fsb.f_mntonname);
65051898Smckusick 					else
65151898Smckusick 					    out_of_mem();
65251898Smckusick 					if (debug)
65351898Smckusick 					  fprintf(stderr,
65451898Smckusick 					      "Making new ep fs=0x%x,0x%x\n",
65551898Smckusick 					      fsb.f_fsid.val[0],
65651898Smckusick 					      fsb.f_fsid.val[1]);
65751898Smckusick 				    } else if (debug)
65851898Smckusick 					fprintf(stderr,
65951898Smckusick 					    "Found ep fs=0x%x,0x%x\n",
66051898Smckusick 					    fsb.f_fsid.val[0],
66151898Smckusick 					    fsb.f_fsid.val[1]);
66238460Smckusick 				}
66351898Smckusick 
66451898Smckusick 				/*
66551898Smckusick 				 * Add dirpath to export mount point.
66651898Smckusick 				 */
66751898Smckusick 				dirp = add_expdir(&dirhead, cp, len);
66851898Smckusick 				dirplen = len;
66951898Smckusick 			    } else {
67051898Smckusick 				getexp_err(ep, grp);
67151898Smckusick 				goto nextline;
67251898Smckusick 			    }
67351898Smckusick 			    *endcp = savedc;
67451898Smckusick 			} else {
67551898Smckusick 			    savedc = *endcp;
67651898Smckusick 			    *endcp = '\0';
67751898Smckusick 			    got_nondir = 1;
67851898Smckusick 			    if (ep == (struct exportlist *)0 || has_host) {
67951898Smckusick 				getexp_err(ep, grp);
68051898Smckusick 				goto nextline;
68151898Smckusick 			    }
68251898Smckusick 			    if (get_host(cp, grp)) {
68351898Smckusick 				getexp_err(ep, grp);
68451898Smckusick 				goto nextline;
68551898Smckusick 			    }
68651898Smckusick 			    has_host = TRUE;
68751898Smckusick 			    *endcp = savedc;
68838460Smckusick 			}
68938460Smckusick 			cp = endcp;
69038460Smckusick 			nextfield(&cp, &endcp);
69145271Smckusick 			len = endcp - cp;
69238460Smckusick 		}
69351898Smckusick 		if (check_options(dirhead)) {
69451898Smckusick 			getexp_err(ep, grp);
69551898Smckusick 			goto nextline;
69651898Smckusick 		}
69751898Smckusick 		if (!has_host) {
69851898Smckusick 			grp->gr_type = GT_HOST;
69951667Smckusick 			if (debug)
70051667Smckusick 				fprintf(stderr,"Adding a default entry\n");
70151667Smckusick 			/* add a default group and make the grp list NULL */
70251667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
70351898Smckusick 			if (hpe == (struct hostent *)0)
70451898Smckusick 				out_of_mem();
70551898Smckusick 			hpe->h_name = "Default";
70651667Smckusick 			hpe->h_addrtype = AF_INET;
70751667Smckusick 			hpe->h_length = sizeof (u_long);
70851712Smckusick 			hpe->h_addr_list = (char **)0;
70951898Smckusick 			grp->gr_ptr.gt_hostent = hpe;
71051667Smckusick 		}
71151898Smckusick 		if (do_mount(ep, grp, exflags, &anon, dirp,
71251898Smckusick 			dirplen, &fsb)) {
71351898Smckusick 			getexp_err(ep, grp);
71451898Smckusick 			goto nextline;
71551898Smckusick 		}
71651898Smckusick 
71751898Smckusick 		/*
71851898Smckusick 		 * Success. Update the data structures.
71951898Smckusick 		 */
72051898Smckusick 		if (has_host) {
72151898Smckusick 			grp->gr_next = grphead;
72251898Smckusick 			grphead = grp;
72351898Smckusick 			hang_dirp(dirhead, grp, ep, (opt_flags & OP_ALLDIRS));
72451898Smckusick 		} else {
72551898Smckusick 			hang_dirp(dirhead, (struct grouplist *)0, ep,
72651898Smckusick 				(opt_flags & OP_ALLDIRS));
72751898Smckusick 			free_grp(grp);
72851898Smckusick 		}
72951898Smckusick 		dirhead = (struct dirlist *)0;
73051898Smckusick 		if ((ep->ex_flag & EX_LINKED) == 0) {
73151898Smckusick 			ep2 = exphead;
73251898Smckusick 			epp = &exphead;
73351898Smckusick 
73451898Smckusick 			/*
73551898Smckusick 			 * Insert in the list in alphabetical order.
73651898Smckusick 			 */
73751898Smckusick 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
73851898Smckusick 				epp = &ep2->ex_next;
73951898Smckusick 				ep2 = ep2->ex_next;
74051898Smckusick 			}
74151898Smckusick 			if (ep2)
74251898Smckusick 				ep->ex_next = ep2;
74351898Smckusick 			*epp = ep;
74451898Smckusick 			ep->ex_flag |= EX_LINKED;
74551898Smckusick 		}
74651898Smckusick nextline:
74751898Smckusick 		if (dirhead) {
74851898Smckusick 			free_dir(dirhead);
74951898Smckusick 			dirhead = (struct dirlist *)0;
75051898Smckusick 		}
75151898Smckusick 	}
75251898Smckusick 	fclose(exp_file);
75351898Smckusick }
75451898Smckusick 
75551898Smckusick /*
75651898Smckusick  * Allocate an export list element
75751898Smckusick  */
75851898Smckusick struct exportlist *
75951898Smckusick get_exp()
76051898Smckusick {
76151898Smckusick 	register struct exportlist *ep;
76251898Smckusick 
76351898Smckusick 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
76451898Smckusick 	if (ep == (struct exportlist *)0)
76551898Smckusick 		out_of_mem();
76651898Smckusick 	bzero((caddr_t)ep, sizeof (struct exportlist));
76751898Smckusick 	return (ep);
76851898Smckusick }
76951898Smckusick 
77051898Smckusick /*
77151898Smckusick  * Allocate a group list element
77251898Smckusick  */
77351898Smckusick struct grouplist *
77451898Smckusick get_grp()
77551898Smckusick {
77651898Smckusick 	register struct grouplist *gp;
77751898Smckusick 
77851898Smckusick 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
77951898Smckusick 	if (gp == (struct grouplist *)0)
78051898Smckusick 		out_of_mem();
78151898Smckusick 	bzero((caddr_t)gp, sizeof (struct grouplist));
78251898Smckusick 	return (gp);
78351898Smckusick }
78451898Smckusick 
78551898Smckusick /*
78651898Smckusick  * Clean up upon an error in get_exportlist().
78751898Smckusick  */
78851898Smckusick void
78951898Smckusick getexp_err(ep, grp)
79051898Smckusick 	struct exportlist *ep;
79151898Smckusick 	struct grouplist *grp;
79251898Smckusick {
79351898Smckusick 
79451898Smckusick 	syslog(LOG_ERR, "Bad exports list line %s", line);
79551898Smckusick 	if (ep && ep->ex_next == (struct exportlist *)0)
79651898Smckusick 		free_exp(ep);
79751898Smckusick 	if (grp && grp->gr_next == (struct grouplist *)0)
79851898Smckusick 		free_grp(grp);
79951898Smckusick }
80051898Smckusick 
80151898Smckusick /*
80251898Smckusick  * Search the export list for a matching fs.
80351898Smckusick  */
80451898Smckusick struct exportlist *
80551898Smckusick ex_search(fsid)
806*52109Smckusick 	fsid_t *fsid;
80751898Smckusick {
80851898Smckusick 	register struct exportlist *ep;
80951898Smckusick 
81051898Smckusick 	ep = exphead;
81151898Smckusick 	while (ep) {
81251898Smckusick 		if (ep->ex_fs.val[0] == fsid->val[0] &&
81351898Smckusick 		    ep->ex_fs.val[1] == fsid->val[1])
81451898Smckusick 			return (ep);
81551898Smckusick 		ep = ep->ex_next;
81651898Smckusick 	}
81751898Smckusick 	return (ep);
81851898Smckusick }
81951898Smckusick 
82051898Smckusick /*
82151898Smckusick  * Add a directory path to the list.
82251898Smckusick  */
82351898Smckusick char *
82451898Smckusick add_expdir(dpp, cp, len)
82551898Smckusick 	struct dirlist **dpp;
82651898Smckusick 	char *cp;
82751898Smckusick 	int len;
82851898Smckusick {
82951898Smckusick 	register struct dirlist *dp;
83051898Smckusick 
83151898Smckusick 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
83251898Smckusick 	dp->dp_left = *dpp;
83351898Smckusick 	dp->dp_right = (struct dirlist *)0;
83451898Smckusick 	dp->dp_flag = 0;
83551898Smckusick 	dp->dp_hosts = (struct hostlist *)0;
83651898Smckusick 	strcpy(dp->dp_dirp, cp);
83751898Smckusick 	*dpp = dp;
83851898Smckusick 	return (dp->dp_dirp);
83951898Smckusick }
84051898Smckusick 
84151898Smckusick /*
84251898Smckusick  * Hang the dir list element off the dirpath binary tree as required
84351898Smckusick  * and update the entry for host.
84451898Smckusick  */
84551898Smckusick void
84651898Smckusick hang_dirp(dp, grp, ep, alldirs)
84751898Smckusick 	register struct dirlist *dp;
84851898Smckusick 	struct grouplist *grp;
84951898Smckusick 	struct exportlist *ep;
85051898Smckusick 	int alldirs;
85151898Smckusick {
85251898Smckusick 	register struct hostlist *hp;
85351898Smckusick 	struct dirlist *dp2;
85451898Smckusick 
85551898Smckusick 	if (alldirs) {
85651898Smckusick 		if (ep->ex_defdir)
85751898Smckusick 			free((caddr_t)dp);
85851898Smckusick 		else
85951898Smckusick 			ep->ex_defdir = dp;
86051898Smckusick 		if (grp) {
86151898Smckusick 			hp = get_ht();
86251898Smckusick 			hp->ht_grp = grp;
86351898Smckusick 			hp->ht_next = ep->ex_defdir->dp_hosts;
86451898Smckusick 			ep->ex_defdir->dp_hosts = hp;
86551898Smckusick 		} else
86651898Smckusick 			ep->ex_defdir->dp_flag |= DP_DEFSET;
86751898Smckusick 	} else {
86851898Smckusick 		while (dp) {
86951898Smckusick 			if (grp) {
87051898Smckusick 				hp = get_ht();
87151898Smckusick 				hp->ht_grp = grp;
87251898Smckusick 			} else
87351898Smckusick 				hp = (struct hostlist *)0;
87451898Smckusick 			dp2 = dp->dp_left;
87551898Smckusick 			add_dlist(&ep->ex_dirl, dp, hp);
87651898Smckusick 			dp = dp2;
87751898Smckusick 		}
87851898Smckusick 	}
87951898Smckusick }
88051898Smckusick 
88151898Smckusick /*
88251898Smckusick  * Traverse the binary tree either updating a node that is already there
88351898Smckusick  * for the new directory or adding the new node.
88451898Smckusick  */
88551898Smckusick void
88651898Smckusick add_dlist(dpp, newdp, hp)
88751898Smckusick 	struct dirlist **dpp;
88851898Smckusick 	struct dirlist *newdp;
88951898Smckusick 	struct hostlist *hp;
89051898Smckusick {
89151898Smckusick 	register struct dirlist *dp;
89251898Smckusick 	int cmp;
89351898Smckusick 
89451898Smckusick 	dp = *dpp;
89551898Smckusick 	if (dp) {
89651898Smckusick 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
89751898Smckusick 		if (cmp > 0) {
89851898Smckusick 			add_dlist(&dp->dp_left, newdp, hp);
89951898Smckusick 			return;
90051898Smckusick 		} else if (cmp < 0) {
90151898Smckusick 			add_dlist(&dp->dp_right, newdp, hp);
90251898Smckusick 			return;
90351898Smckusick 		} else
90451898Smckusick 			free((caddr_t)newdp);
90551898Smckusick 	} else {
90651898Smckusick 		dp = newdp;
90751898Smckusick 		dp->dp_left = (struct dirlist *)0;
90851898Smckusick 		*dpp = dp;
90951898Smckusick 	}
91051898Smckusick 	if (hp) {
91151898Smckusick 		hp->ht_next = dp->dp_hosts;
91251898Smckusick 		dp->dp_hosts = hp;
91351898Smckusick 	} else
91451898Smckusick 		dp->dp_flag |= DP_DEFSET;
91551898Smckusick }
91651898Smckusick 
91751898Smckusick /*
91851898Smckusick  * Search for a dirpath on the export point.
91951898Smckusick  */
92051898Smckusick struct dirlist *
92151898Smckusick dirp_search(dp, dirpath)
92251898Smckusick 	register struct dirlist *dp;
92351898Smckusick 	char *dirpath;
92451898Smckusick {
92551898Smckusick 	register int cmp;
92651898Smckusick 
92751898Smckusick 	if (dp) {
92851898Smckusick 		cmp = strcmp(dp->dp_dirp, dirpath);
92951898Smckusick 		if (cmp > 0)
93051898Smckusick 			return (dirp_search(dp->dp_left, dirpath));
93151898Smckusick 		else if (cmp < 0)
93251898Smckusick 			return (dirp_search(dp->dp_right, dirpath));
93351898Smckusick 		else
93451898Smckusick 			return (dp);
93551898Smckusick 	}
93651898Smckusick 	return (dp);
93751898Smckusick }
93851898Smckusick 
93951898Smckusick /*
94051898Smckusick  * Scan for a host match in a directory tree.
94151898Smckusick  */
94251898Smckusick chk_host(dp, saddr, defsetp)
94351898Smckusick 	struct dirlist *dp;
94451898Smckusick 	u_long saddr;
94551898Smckusick 	int *defsetp;
94651898Smckusick {
94751898Smckusick 	register struct hostlist *hp;
94851898Smckusick 	register struct grouplist *grp;
94951898Smckusick 	register u_long **addrp;
95051898Smckusick 
95151898Smckusick 	if (dp) {
95251898Smckusick 		if (dp->dp_flag & DP_DEFSET)
95351898Smckusick 			*defsetp = 1;
95451898Smckusick 		hp = dp->dp_hosts;
95551898Smckusick 		while (hp) {
95651898Smckusick 			grp = hp->ht_grp;
95751898Smckusick 			switch (grp->gr_type) {
95851898Smckusick 			case GT_HOST:
95951898Smckusick 			    addrp = (u_long **)
96051898Smckusick 				grp->gr_ptr.gt_hostent->h_addr_list;
96151898Smckusick 			    while (*addrp) {
96251898Smckusick 				if (**addrp == saddr)
96351898Smckusick 				    return (1);
96451898Smckusick 				addrp++;
96551898Smckusick 			    }
96651898Smckusick 			    break;
96751898Smckusick 			case GT_NET:
96851898Smckusick 			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
96951898Smckusick 				grp->gr_ptr.gt_net.nt_net)
97051898Smckusick 				return (1);
97151898Smckusick 			    break;
97251898Smckusick 			};
97351898Smckusick 			hp = hp->ht_next;
97451898Smckusick 		}
97551898Smckusick 	}
97651898Smckusick 	return (0);
97751898Smckusick }
97851898Smckusick 
97951898Smckusick /*
98051898Smckusick  * Scan tree for a host that matches the address.
98151898Smckusick  */
98251898Smckusick scan_tree(dp, saddr)
98351898Smckusick 	register struct dirlist *dp;
98451898Smckusick 	u_long saddr;
98551898Smckusick {
98651898Smckusick 	int defset;
98751898Smckusick 
98851898Smckusick 	if (dp) {
98951898Smckusick 		if (scan_tree(dp->dp_left, saddr))
99051898Smckusick 			return (1);
99151898Smckusick 		if (chk_host(dp, saddr, &defset))
99251898Smckusick 			return (1);
99351898Smckusick 		if (scan_tree(dp->dp_right, saddr))
99451898Smckusick 			return (1);
99551898Smckusick 	}
99651898Smckusick 	return (0);
99751898Smckusick }
99851898Smckusick 
99951898Smckusick /*
100051898Smckusick  * Traverse the dirlist tree and free it up.
100151898Smckusick  */
100251898Smckusick void
100351898Smckusick free_dir(dp)
100451898Smckusick 	register struct dirlist *dp;
100551898Smckusick {
100651898Smckusick 
100751898Smckusick 	if (dp) {
100851898Smckusick 		free_dir(dp->dp_left);
100951898Smckusick 		free_dir(dp->dp_right);
101051898Smckusick 		free_host(dp->dp_hosts);
101151898Smckusick 		free((caddr_t)dp);
101251898Smckusick 	}
101351898Smckusick }
101451898Smckusick 
101551898Smckusick /*
101651898Smckusick  * Parse the option string and update fields.
101751898Smckusick  * Option arguments may either be -<option>=<value> or
101851898Smckusick  * -<option> <value>
101951898Smckusick  */
102051898Smckusick do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
102151898Smckusick 	char **cpp, **endcpp;
102251898Smckusick 	struct exportlist *ep;
102351898Smckusick 	struct grouplist *grp;
102451898Smckusick 	int *has_hostp;
102551898Smckusick 	int *exflagsp;
102651898Smckusick 	struct ucred *cr;
102751898Smckusick {
102851898Smckusick 	register char *cpoptarg, *cpoptend;
102951898Smckusick 	char *cp, *endcp, *cpopt, savedc, savedc2;
103051898Smckusick 	int allflag, usedarg;
103151898Smckusick 
103251898Smckusick 	cpopt = *cpp;
103351898Smckusick 	cpopt++;
103451898Smckusick 	cp = *endcpp;
103551898Smckusick 	savedc = *cp;
103651898Smckusick 	*cp = '\0';
103751898Smckusick 	while (cpopt && *cpopt) {
103851898Smckusick 		allflag = 1;
103951898Smckusick 		usedarg = -2;
104051898Smckusick 		if (cpoptend = index(cpopt, ',')) {
104151898Smckusick 			*cpoptend++ = '\0';
104251898Smckusick 			if (cpoptarg = index(cpopt, '='))
104351898Smckusick 				*cpoptarg++ = '\0';
104451898Smckusick 		} else {
104551898Smckusick 			if (cpoptarg = index(cpopt, '='))
104651898Smckusick 				*cpoptarg++ = '\0';
104751898Smckusick 			else {
104851898Smckusick 				*cp = savedc;
104951898Smckusick 				nextfield(&cp, &endcp);
105051898Smckusick 				**endcpp = '\0';
105151898Smckusick 				if (endcp > cp && *cp != '-') {
105251898Smckusick 					cpoptarg = cp;
105351898Smckusick 					savedc2 = *endcp;
105451898Smckusick 					*endcp = '\0';
105551898Smckusick 					usedarg = 0;
105651667Smckusick 				}
105751667Smckusick 			}
105851667Smckusick 		}
105951898Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
106051898Smckusick 			*exflagsp |= MNT_EXRDONLY;
106151898Smckusick 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
106251898Smckusick 		    !(allflag = strcmp(cpopt, "mapall")) ||
106351898Smckusick 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
106451898Smckusick 			usedarg++;
106551898Smckusick 			parsecred(cpoptarg, cr);
106651898Smckusick 			if (allflag == 0) {
106751898Smckusick 				*exflagsp |= MNT_EXPORTANON;
106851898Smckusick 				opt_flags |= OP_MAPALL;
106951898Smckusick 			} else
107051898Smckusick 				opt_flags |= OP_MAPROOT;
107151898Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
107251898Smckusick 			*exflagsp |= MNT_EXKERB;
107351898Smckusick 			opt_flags |= OP_KERB;
107451898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "mask")) {
107551898Smckusick 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
107651898Smckusick 				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
107751898Smckusick 				return (1);
107851898Smckusick 			}
107951898Smckusick 			usedarg++;
108051898Smckusick 			opt_flags |= OP_MASK;
108151898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "network")) {
108251898Smckusick 			if (grp->gr_type != GT_NULL) {
108351898Smckusick 				syslog(LOG_ERR, "Network/host conflict");
108451898Smckusick 				return (1);
108551898Smckusick 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
108651898Smckusick 				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
108751898Smckusick 				return (1);
108851898Smckusick 			}
108951898Smckusick 			grp->gr_type = GT_NET;
109051898Smckusick 			*has_hostp = 1;
109151898Smckusick 			usedarg++;
109251898Smckusick 			opt_flags |= OP_NET;
109351898Smckusick 		} else if (!strcmp(cpopt, "alldirs")) {
109451898Smckusick 			opt_flags |= OP_ALLDIRS;
109551898Smckusick #ifdef ISO
109651898Smckusick 		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
109751898Smckusick 			if (get_isoaddr(cpoptarg, grp)) {
109851898Smckusick 				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
109951898Smckusick 				return (1);
110051898Smckusick 			}
110151898Smckusick 			*has_hostp = 1;
110251898Smckusick 			usedarg++;
110351898Smckusick 			opt_flags |= OP_ISO;
110451898Smckusick #endif /* ISO */
110551898Smckusick 		} else {
110651898Smckusick 			syslog(LOG_ERR, "Bad opt %s", cpopt);
110751898Smckusick 			return (1);
110851667Smckusick 		}
110951898Smckusick 		if (usedarg >= 0) {
111051898Smckusick 			*endcp = savedc2;
111151898Smckusick 			**endcpp = savedc;
111251898Smckusick 			if (usedarg > 0) {
111351898Smckusick 				*cpp = cp;
111451898Smckusick 				*endcpp = endcp;
111551898Smckusick 			}
111651898Smckusick 			return (0);
111751898Smckusick 		}
111851898Smckusick 		cpopt = cpoptend;
111951667Smckusick 	}
112051898Smckusick 	**endcpp = savedc;
112151898Smckusick 	return (0);
112251898Smckusick }
112351898Smckusick 
112451898Smckusick /*
112551898Smckusick  * Translate a character string to the corresponding list of network
112651898Smckusick  * addresses for a hostname.
112751898Smckusick  */
112851898Smckusick get_host(cp, grp)
112951898Smckusick 	char *cp;
113051898Smckusick 	register struct grouplist *grp;
113151898Smckusick {
113251898Smckusick 	register struct hostent *hp, *nhp;
113351898Smckusick 	register char **addrp, **naddrp;
113451898Smckusick 	struct hostent t_host;
113551898Smckusick 	int i;
113651898Smckusick 	u_long saddr;
113751898Smckusick 	char *aptr[2];
113851898Smckusick 
113951898Smckusick 	if (grp->gr_type != GT_NULL)
114051898Smckusick 		return (1);
114151898Smckusick 	if ((hp = gethostbyname(cp)) == NULL) {
114251898Smckusick 		if (isdigit(*cp)) {
114351898Smckusick 			saddr = inet_addr(cp);
114451898Smckusick 			if (saddr == -1) {
114551898Smckusick 				syslog(LOG_ERR, "Inet_addr failed");
114651898Smckusick 				return (1);
114751898Smckusick 			}
114851898Smckusick 			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
114951898Smckusick 				AF_INET)) == NULL) {
115051898Smckusick 				hp = &t_host;
115151898Smckusick 				hp->h_name = cp;
115251898Smckusick 				hp->h_addrtype = AF_INET;
115351898Smckusick 				hp->h_length = sizeof (u_long);
115451898Smckusick 				hp->h_addr_list = aptr;
115551898Smckusick 				aptr[0] = (char *)&saddr;
115651898Smckusick 				aptr[1] = (char *)0;
115751898Smckusick 			}
115851898Smckusick 		} else {
115951898Smckusick 			syslog(LOG_ERR, "Gethostbyname failed");
116051898Smckusick 			return (1);
116151898Smckusick 		}
116251898Smckusick 	}
116351898Smckusick 	grp->gr_type = GT_HOST;
116451898Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
116551898Smckusick 		malloc(sizeof(struct hostent));
116651898Smckusick 	if (nhp == (struct hostent *)0)
116751898Smckusick 		out_of_mem();
116851898Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
116951898Smckusick 		sizeof(struct hostent));
117051898Smckusick 	i = strlen(hp->h_name)+1;
117151898Smckusick 	nhp->h_name = (char *)malloc(i);
117251898Smckusick 	if (nhp->h_name == (char *)0)
117351898Smckusick 		out_of_mem();
117451898Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
117551898Smckusick 	addrp = hp->h_addr_list;
117651898Smckusick 	i = 1;
117751898Smckusick 	while (*addrp++)
117851898Smckusick 		i++;
117951898Smckusick 	naddrp = nhp->h_addr_list = (char **)
118051898Smckusick 		malloc(i*sizeof(char *));
118151898Smckusick 	if (naddrp == (char **)0)
118251898Smckusick 		out_of_mem();
118351898Smckusick 	addrp = hp->h_addr_list;
118451898Smckusick 	while (*addrp) {
118551898Smckusick 		*naddrp = (char *)
118651898Smckusick 		    malloc(hp->h_length);
118751898Smckusick 		if (*naddrp == (char *)0)
118851898Smckusick 		    out_of_mem();
118951898Smckusick 		bcopy(*addrp, *naddrp,
119051898Smckusick 			hp->h_length);
119151898Smckusick 		addrp++;
119251898Smckusick 		naddrp++;
119351898Smckusick 	}
119451898Smckusick 	*naddrp = (char *)0;
119551898Smckusick 	return (0);
119651898Smckusick }
119751898Smckusick 
119851898Smckusick /*
119951898Smckusick  * Free up an exports list component
120051898Smckusick  */
120151898Smckusick void
120251898Smckusick free_exp(ep)
120351898Smckusick 	register struct exportlist *ep;
120451898Smckusick {
120551898Smckusick 
120651898Smckusick 	if (ep->ex_defdir) {
120751898Smckusick 		free_host(ep->ex_defdir->dp_hosts);
120851898Smckusick 		free((caddr_t)ep->ex_defdir);
120951898Smckusick 	}
121051898Smckusick 	if (ep->ex_fsdir)
121151898Smckusick 		free(ep->ex_fsdir);
121251898Smckusick 	free_dir(ep->ex_dirl);
121351898Smckusick 	free((caddr_t)ep);
121451898Smckusick }
121551898Smckusick 
121651898Smckusick /*
121751898Smckusick  * Free hosts.
121851898Smckusick  */
121951898Smckusick void
122051898Smckusick free_host(hp)
122151898Smckusick 	register struct hostlist *hp;
122251898Smckusick {
122351898Smckusick 	register struct hostlist *hp2;
122451898Smckusick 
122551898Smckusick 	while (hp) {
122651898Smckusick 		hp2 = hp;
122751898Smckusick 		hp = hp->ht_next;
122851898Smckusick 		free((caddr_t)hp2);
122951898Smckusick 	}
123051898Smckusick }
123151898Smckusick 
123251898Smckusick struct hostlist *
123351898Smckusick get_ht()
123451898Smckusick {
123551898Smckusick 	register struct hostlist *hp;
123651898Smckusick 
123751898Smckusick 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
123851898Smckusick 	if (hp == (struct hostlist *)0)
123951898Smckusick 		out_of_mem();
124051898Smckusick 	hp->ht_next = (struct hostlist *)0;
124151898Smckusick 	return (hp);
124251898Smckusick }
124351898Smckusick 
124451898Smckusick #ifdef ISO
124551898Smckusick /*
124651898Smckusick  * Translate an iso address.
124751898Smckusick  */
124851898Smckusick get_isoaddr(cp, grp)
124951898Smckusick 	char *cp;
125051898Smckusick 	struct grouplist *grp;
125151898Smckusick {
125251898Smckusick 	struct iso_addr *isop;
125351898Smckusick 	struct sockaddr_iso *isoaddr;
125451898Smckusick 
125551898Smckusick 	if (grp->gr_type != GT_NULL)
125651898Smckusick 		return (1);
125751898Smckusick 	if ((isop = iso_addr(cp)) == NULL) {
125851898Smckusick 		syslog(LOG_ERR,
125951898Smckusick 		    "iso_addr failed, ignored");
126051898Smckusick 		return (1);
126151898Smckusick 	}
126251898Smckusick 	isoaddr = (struct sockaddr_iso *)
126351898Smckusick 	    malloc(sizeof (struct sockaddr_iso));
126451898Smckusick 	if (isoaddr == (struct sockaddr_iso *)0)
126551898Smckusick 		out_of_mem();
126651898Smckusick 	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
126751898Smckusick 	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
126851898Smckusick 		sizeof (struct iso_addr));
126951898Smckusick 	isoaddr->siso_len = sizeof (struct sockaddr_iso);
127051898Smckusick 	isoaddr->siso_family = AF_ISO;
127151898Smckusick 	grp->gr_type = GT_ISO;
127251898Smckusick 	grp->gr_ptr.gt_isoaddr = isoaddr;
127351898Smckusick 	return (0);
127451898Smckusick }
127551898Smckusick #endif	/* ISO */
127651898Smckusick 
127751898Smckusick /*
127851898Smckusick  * Out of memory, fatal
127951898Smckusick  */
128051898Smckusick void
128151898Smckusick out_of_mem()
128251898Smckusick {
128351898Smckusick 
128451898Smckusick 	syslog(LOG_ERR, "Out of memory");
128551667Smckusick 	exit(2);
128651667Smckusick }
128751667Smckusick 
128851898Smckusick /*
128951898Smckusick  * Do the mount syscall with the update flag to push the export info into
129051898Smckusick  * the kernel.
129151898Smckusick  */
129251898Smckusick do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
129351667Smckusick 	struct exportlist *ep;
129451667Smckusick 	struct grouplist *grp;
129551898Smckusick 	int exflags;
129651667Smckusick 	struct ucred *anoncrp;
129751898Smckusick 	char *dirp;
129851898Smckusick 	int dirplen;
129951898Smckusick 	struct statfs *fsb;
130051667Smckusick {
130151898Smckusick 	register char *cp = (char *)0;
130251667Smckusick 	register u_long **addrp;
130351898Smckusick 	int done;
130451898Smckusick 	char savedc;
130551898Smckusick 	struct sockaddr_in sin, imask;
1306*52109Smckusick 	struct ufs_args args;
130751898Smckusick 	u_long net;
130851667Smckusick 
130951667Smckusick 	args.fspec = 0;
131051667Smckusick 	args.exflags = exflags;
131151667Smckusick 	args.anon = *anoncrp;
131251667Smckusick 	sin.sin_family = AF_INET;
131351667Smckusick 	sin.sin_port = 0;
131451667Smckusick 	sin.sin_len = sizeof(sin);
131551898Smckusick 	imask.sin_family = AF_INET;
131651898Smckusick 	imask.sin_port = 0;
131751898Smckusick 	imask.sin_len = sizeof(sin);
131851898Smckusick 	if (grp->gr_type == GT_HOST)
131951667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
132051898Smckusick 	else
132151898Smckusick 		addrp = (u_long **)0;
132251667Smckusick 	done = FALSE;
132351898Smckusick 	while (!done) {
132451898Smckusick 		switch (grp->gr_type) {
132551898Smckusick 		case GT_HOST:
132651898Smckusick 			if (addrp)
132751712Smckusick 				sin.sin_addr.s_addr = **addrp;
132851712Smckusick 			else
132951667Smckusick 				sin.sin_addr.s_addr = INADDR_ANY;
133051667Smckusick 			args.saddr = (struct sockaddr *)&sin;
133151667Smckusick 			args.slen = sizeof(sin);
133251898Smckusick 			args.msklen = 0;
133351898Smckusick 			break;
133451898Smckusick 		case GT_NET:
133551898Smckusick 			if (grp->gr_ptr.gt_net.nt_mask)
133651898Smckusick 			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
133751898Smckusick 			else {
133851898Smckusick 			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
133951898Smckusick 			    if (IN_CLASSA(net))
134051898Smckusick 				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
134151898Smckusick 			    else if (IN_CLASSB(net))
134251898Smckusick 				imask.sin_addr.s_addr =
134351898Smckusick 				    inet_addr("255.255.0.0");
134451898Smckusick 			    else
134551898Smckusick 				imask.sin_addr.s_addr =
134651898Smckusick 				    inet_addr("255.255.255.0");
134751898Smckusick 			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
134851898Smckusick 			}
134951898Smckusick 			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
135051898Smckusick 			args.saddr = (struct sockaddr *)&sin;
135151898Smckusick 			args.slen = sizeof (sin);
135251898Smckusick 			args.smask = (struct sockaddr *)&imask;
135351898Smckusick 			args.msklen = sizeof (imask);
135451898Smckusick 			break;
135551667Smckusick #ifdef ISO
135651898Smckusick 		case GT_ISO:
135751667Smckusick 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
135851667Smckusick 			args.slen = sizeof (struct sockaddr_iso);
135951898Smckusick 			args.msklen = 0;
136051898Smckusick 			break;
136151667Smckusick #endif	/* ISO */
136251898Smckusick 		default:
136351667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
136451898Smckusick 			if (cp)
136551898Smckusick 				*cp = savedc;
136651898Smckusick 			return (1);
136751898Smckusick 		};
1368*52109Smckusick 
1369*52109Smckusick 		/*
1370*52109Smckusick 		 * XXX:
1371*52109Smckusick 		 * Maybe I should just use the fsb->f_mntonname path instead
1372*52109Smckusick 		 * of looping back up the dirp to the mount point??
1373*52109Smckusick 		 * Also, needs to know how to export all types of local
1374*52109Smckusick 		 * exportable file systems and not just MOUNT_UFS.
1375*52109Smckusick 		 */
1376*52109Smckusick 		while (mount(fsb->f_type, dirp,
1377*52109Smckusick 		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
137851898Smckusick 			if (cp)
137951898Smckusick 				*cp-- = savedc;
138051898Smckusick 			else
138151898Smckusick 				cp = dirp + dirplen - 1;
138251667Smckusick 			if (errno == EPERM) {
138351667Smckusick 				syslog(LOG_ERR,
138451898Smckusick 				   "Can't change attributes for %s.\n", dirp);
138551898Smckusick 				return (1);
138651667Smckusick 			}
138751898Smckusick 			if (opt_flags & OP_ALLDIRS) {
138851898Smckusick 				syslog(LOG_ERR, "Not root dir");
138951898Smckusick 				return (1);
139051898Smckusick 			}
139151667Smckusick 			/* back up over the last component */
139251898Smckusick 			while (*cp == '/' && cp > dirp)
139351667Smckusick 				cp--;
139451898Smckusick 			while (*(cp - 1) != '/' && cp > dirp)
139551667Smckusick 				cp--;
139651898Smckusick 			if (cp == dirp) {
139751898Smckusick 				if (debug)
139851667Smckusick 					fprintf(stderr,"mnt unsucc\n");
139951898Smckusick 				syslog(LOG_ERR, "Can't export %s", dirp);
140051898Smckusick 				return (1);
140151667Smckusick 			}
140251667Smckusick 			savedc = *cp;
140351667Smckusick 			*cp = '\0';
140451667Smckusick 		}
140551898Smckusick 		if (addrp) {
140651667Smckusick 			++addrp;
140751898Smckusick 			if (*addrp == (u_long *)0)
140851667Smckusick 				done = TRUE;
140951898Smckusick 		} else
141051898Smckusick 			done = TRUE;
141151898Smckusick 	}
141251898Smckusick 	if (cp)
141351898Smckusick 		*cp = savedc;
141451898Smckusick 	return (0);
141551898Smckusick }
141651898Smckusick 
141751898Smckusick /*
141851898Smckusick  * Translate a net address.
141951898Smckusick  */
142051898Smckusick get_net(cp, net, maskflg)
142151898Smckusick 	char *cp;
142251898Smckusick 	struct netmsk *net;
142351898Smckusick 	int maskflg;
142451898Smckusick {
142551898Smckusick 	register struct netent *np;
142651898Smckusick 	register long netaddr;
142751898Smckusick 	struct in_addr inetaddr, inetaddr2;
142851898Smckusick 	char *name;
142951898Smckusick 
143051898Smckusick 	if (np = getnetbyname(cp))
143151898Smckusick 		inetaddr = inet_makeaddr(np->n_net, 0);
143251898Smckusick 	else if (isdigit(*cp)) {
143351898Smckusick 		if ((netaddr = inet_network(cp)) == -1)
143451898Smckusick 			return (1);
143551898Smckusick 		inetaddr = inet_makeaddr(netaddr, 0);
143651898Smckusick 		/*
143751898Smckusick 		 * Due to arbritrary subnet masks, you don't know how many
143851898Smckusick 		 * bits to shift the address to make it into a network,
143951898Smckusick 		 * however you do know how to make a network address into
144051898Smckusick 		 * a host with host == 0 and then compare them.
144151898Smckusick 		 * (What a pest)
144251898Smckusick 		 */
144351898Smckusick 		if (!maskflg) {
144451898Smckusick 			setnetent(0);
144551898Smckusick 			while (np = getnetent()) {
144651898Smckusick 				inetaddr2 = inet_makeaddr(np->n_net, 0);
144751898Smckusick 				if (inetaddr2.s_addr == inetaddr.s_addr)
144851898Smckusick 					break;
144951898Smckusick 			}
145051898Smckusick 			endnetent();
145151667Smckusick 		}
145251898Smckusick 	} else
145351898Smckusick 		return (1);
145451898Smckusick 	if (maskflg)
145551898Smckusick 		net->nt_mask = inetaddr.s_addr;
145651898Smckusick 	else {
145751898Smckusick 		if (np)
145851898Smckusick 			name = np->n_name;
145951898Smckusick 		else
146051898Smckusick 			name = inet_ntoa(inetaddr);
146151898Smckusick 		net->nt_name = (char *)malloc(strlen(name) + 1);
146251898Smckusick 		if (net->nt_name == (char *)0)
146351898Smckusick 			out_of_mem();
146451898Smckusick 		strcpy(net->nt_name, name);
146551898Smckusick 		net->nt_net = inetaddr.s_addr;
146638460Smckusick 	}
146751898Smckusick 	return (0);
146838460Smckusick }
146938460Smckusick 
147038460Smckusick /*
147138460Smckusick  * Parse out the next white space separated field
147238460Smckusick  */
147351667Smckusick void
147438460Smckusick nextfield(cp, endcp)
147538460Smckusick 	char **cp;
147638460Smckusick 	char **endcp;
147738460Smckusick {
147838460Smckusick 	register char *p;
147938460Smckusick 
148038460Smckusick 	p = *cp;
148138460Smckusick 	while (*p == ' ' || *p == '\t')
148238460Smckusick 		p++;
148351898Smckusick 	if (*p == '\n' || *p == '\0')
148438460Smckusick 		*cp = *endcp = p;
148551898Smckusick 	else {
148651898Smckusick 		*cp = p++;
148751898Smckusick 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
148851898Smckusick 			p++;
148951898Smckusick 		*endcp = p;
149038460Smckusick 	}
149138460Smckusick }
149239681Smckusick 
149339681Smckusick /*
149451898Smckusick  * Get an exports file line. Skip over blank lines and handle line
149551898Smckusick  * continuations.
149639681Smckusick  */
149751898Smckusick get_line()
149839681Smckusick {
149951898Smckusick 	register char *p, *cp;
150051898Smckusick 	register int len;
150151898Smckusick 	int totlen, cont_line;
150239681Smckusick 
150351898Smckusick 	/*
150451898Smckusick 	 * Loop around ignoring blank lines and getting all continuation lines.
150551898Smckusick 	 */
150651898Smckusick 	p = line;
150751898Smckusick 	totlen = 0;
150851898Smckusick 	do {
150951898Smckusick 		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
151051898Smckusick 			return (0);
151151898Smckusick 		len = strlen(p);
151251898Smckusick 		cp = p + len - 1;
151351898Smckusick 		cont_line = 0;
151451898Smckusick 		while (cp >= p &&
151551898Smckusick 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
151651898Smckusick 			if (*cp == '\\')
151751898Smckusick 				cont_line = 1;
151851898Smckusick 			cp--;
151951898Smckusick 			len--;
152051898Smckusick 		}
152151898Smckusick 		*++cp = '\0';
152251898Smckusick 		if (len > 0) {
152351898Smckusick 			totlen += len;
152451898Smckusick 			if (totlen >= LINESIZ) {
152551898Smckusick 				syslog(LOG_ERR, "Exports line too long");
152651898Smckusick 				exit(2);
152751898Smckusick 			}
152851898Smckusick 			p = cp;
152951898Smckusick 		}
153051898Smckusick 	} while (totlen == 0 || cont_line);
153151898Smckusick 	return (1);
153244015Smckusick }
153344015Smckusick 
153451667Smckusick /*
153551667Smckusick  * Parse a description of a credential.
153651667Smckusick  */
153751667Smckusick parsecred(namelist, cr)
153851667Smckusick 	char *namelist;
153951667Smckusick 	register struct ucred *cr;
154051667Smckusick {
154151667Smckusick 	register char *name;
154251667Smckusick 	register int cnt;
154351667Smckusick 	char *names;
154451667Smckusick 	struct passwd *pw;
154551667Smckusick 	struct group *gr;
154651667Smckusick 	int ngroups, groups[NGROUPS + 1];
154751667Smckusick 
154851667Smckusick 	/*
154951667Smckusick 	 * Set up the unpriviledged user.
155051667Smckusick 	 */
155151667Smckusick 	cr->cr_ref = 1;
155251667Smckusick 	cr->cr_uid = -2;
155351667Smckusick 	cr->cr_groups[0] = -2;
155451667Smckusick 	cr->cr_ngroups = 1;
155551667Smckusick 	/*
155651667Smckusick 	 * Get the user's password table entry.
155751667Smckusick 	 */
155851667Smckusick 	names = strsep(&namelist, " \t\n");
155951667Smckusick 	name = strsep(&names, ":");
156051667Smckusick 	if (isdigit(*name) || *name == '-')
156151667Smckusick 		pw = getpwuid(atoi(name));
156251667Smckusick 	else
156351667Smckusick 		pw = getpwnam(name);
156451667Smckusick 	/*
156551667Smckusick 	 * Credentials specified as those of a user.
156651667Smckusick 	 */
156751667Smckusick 	if (names == NULL) {
156851667Smckusick 		if (pw == NULL) {
156951667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
157051667Smckusick 			return;
157151667Smckusick 		}
157251667Smckusick 		cr->cr_uid = pw->pw_uid;
157351667Smckusick 		ngroups = NGROUPS + 1;
157451667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
157551667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
157651667Smckusick 		/*
157751667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
157851667Smckusick 		 */
157951667Smckusick 		cr->cr_ngroups = ngroups - 1;
158051667Smckusick 		cr->cr_groups[0] = groups[0];
158151667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
158251667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
158351667Smckusick 		return;
158451667Smckusick 	}
158551667Smckusick 	/*
158651667Smckusick 	 * Explicit credential specified as a colon separated list:
158751667Smckusick 	 *	uid:gid:gid:...
158851667Smckusick 	 */
158951667Smckusick 	if (pw != NULL)
159051667Smckusick 		cr->cr_uid = pw->pw_uid;
159151667Smckusick 	else if (isdigit(*name) || *name == '-')
159251667Smckusick 		cr->cr_uid = atoi(name);
159351667Smckusick 	else {
159451667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
159551667Smckusick 		return;
159651667Smckusick 	}
159751667Smckusick 	cr->cr_ngroups = 0;
159851667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
159951667Smckusick 		name = strsep(&names, ":");
160051667Smckusick 		if (isdigit(*name) || *name == '-') {
160151667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
160251667Smckusick 		} else {
160351667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
160451667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
160551667Smckusick 				continue;
160651667Smckusick 			}
160751667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
160851667Smckusick 		}
160951667Smckusick 	}
161051667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
161151667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
161251667Smckusick }
161351667Smckusick 
161444015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
161544015Smckusick /*
161644015Smckusick  * Routines that maintain the remote mounttab
161744015Smckusick  */
161851667Smckusick void
161951667Smckusick get_mountlist()
162044015Smckusick {
162144015Smckusick 	register struct mountlist *mlp, **mlpp;
162244015Smckusick 	register char *eos, *dirp;
162344015Smckusick 	int len;
162444015Smckusick 	char str[STRSIZ];
162544015Smckusick 	FILE *mlfile;
162644015Smckusick 
162751712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
162851667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
162944015Smckusick 		return;
163044015Smckusick 	}
163144015Smckusick 	mlpp = &mlhead;
163244015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
163344015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
163444015Smckusick 		    (dirp = index(str, ' ')) == NULL)
163544015Smckusick 			continue;
163644015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
163744015Smckusick 		len = dirp-str;
163844015Smckusick 		if (len > RPCMNT_NAMELEN)
163944015Smckusick 			len = RPCMNT_NAMELEN;
164044015Smckusick 		bcopy(str, mlp->ml_host, len);
164144015Smckusick 		mlp->ml_host[len] = '\0';
164244015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
164344015Smckusick 			dirp++;
164444015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
164544015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
164644015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
164744015Smckusick 			len = strlen(dirp);
164844015Smckusick 		else
164944015Smckusick 			len = eos-dirp;
165044015Smckusick 		if (len > RPCMNT_PATHLEN)
165144015Smckusick 			len = RPCMNT_PATHLEN;
165244015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
165344015Smckusick 		mlp->ml_dirp[len] = '\0';
165444015Smckusick 		mlp->ml_next = (struct mountlist *)0;
165544015Smckusick 		*mlpp = mlp;
165644015Smckusick 		mlpp = &mlp->ml_next;
165744015Smckusick 	}
165844015Smckusick 	fclose(mlfile);
165944015Smckusick }
166044015Smckusick 
166151667Smckusick void
166251667Smckusick del_mlist(hostp, dirp)
166344015Smckusick 	register char *hostp, *dirp;
166444015Smckusick {
166544015Smckusick 	register struct mountlist *mlp, **mlpp;
166651712Smckusick 	struct mountlist *mlp2;
166744015Smckusick 	FILE *mlfile;
166844015Smckusick 	int fnd = 0;
166944015Smckusick 
167044015Smckusick 	mlpp = &mlhead;
167144015Smckusick 	mlp = mlhead;
167244015Smckusick 	while (mlp) {
167344015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
167444015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
167544015Smckusick 			fnd = 1;
167651712Smckusick 			mlp2 = mlp;
167751712Smckusick 			*mlpp = mlp = mlp->ml_next;
167851712Smckusick 			free((caddr_t)mlp2);
167951712Smckusick 		} else {
168051712Smckusick 			mlpp = &mlp->ml_next;
168151712Smckusick 			mlp = mlp->ml_next;
168239681Smckusick 		}
168339681Smckusick 	}
168444015Smckusick 	if (fnd) {
168544015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
168651898Smckusick 			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
168744015Smckusick 			return;
168844015Smckusick 		}
168944015Smckusick 		mlp = mlhead;
169044015Smckusick 		while (mlp) {
169144015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
169244015Smckusick 			mlp = mlp->ml_next;
169344015Smckusick 		}
169444015Smckusick 		fclose(mlfile);
169544015Smckusick 	}
169639681Smckusick }
169744015Smckusick 
169851667Smckusick void
169951667Smckusick add_mlist(hostp, dirp)
170044015Smckusick 	register char *hostp, *dirp;
170144015Smckusick {
170244015Smckusick 	register struct mountlist *mlp, **mlpp;
170344015Smckusick 	FILE *mlfile;
170444015Smckusick 
170544015Smckusick 	mlpp = &mlhead;
170644015Smckusick 	mlp = mlhead;
170744015Smckusick 	while (mlp) {
170844015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
170944015Smckusick 			return;
171044015Smckusick 		mlpp = &mlp->ml_next;
171144015Smckusick 		mlp = mlp->ml_next;
171244015Smckusick 	}
171344015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
171444015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
171544015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
171644015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
171744015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
171844015Smckusick 	mlp->ml_next = (struct mountlist *)0;
171944015Smckusick 	*mlpp = mlp;
172044015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
172151898Smckusick 		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
172244015Smckusick 		return;
172344015Smckusick 	}
172444015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
172544015Smckusick 	fclose(mlfile);
172644015Smckusick }
172744015Smckusick 
172844015Smckusick /*
172944015Smckusick  * This function is called via. SIGTERM when the system is going down.
173044015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
173144015Smckusick  */
173246709Sbostic void
173344015Smckusick send_umntall()
173444015Smckusick {
173544015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
173644015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
173751667Smckusick 	exit(0);
173844015Smckusick }
173944015Smckusick 
174044015Smckusick umntall_each(resultsp, raddr)
174144015Smckusick 	caddr_t resultsp;
174244015Smckusick 	struct sockaddr_in *raddr;
174344015Smckusick {
174444015Smckusick 	return (1);
174544015Smckusick }
174644015Smckusick 
174744015Smckusick /*
174851667Smckusick  * Free up a group list.
174951667Smckusick  */
175051667Smckusick void
175151667Smckusick free_grp(grp)
175251667Smckusick 	register struct grouplist *grp;
175351667Smckusick {
175451667Smckusick 	register char **addrp;
175551667Smckusick 
175651898Smckusick 	if (grp->gr_type == GT_HOST) {
175751712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
175851712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
175951712Smckusick 			while (addrp && *addrp)
176051712Smckusick 				free(*addrp++);
176151712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
176251712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
176351712Smckusick 		}
176451667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
176551898Smckusick 	} else if (grp->gr_type == GT_NET) {
176651898Smckusick 		if (grp->gr_ptr.gt_net.nt_name)
176751898Smckusick 			free(grp->gr_ptr.gt_net.nt_name);
176851667Smckusick 	}
176951667Smckusick #ifdef ISO
177051898Smckusick 	else if (grp->gr_type == GT_ISO)
177151667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
177251667Smckusick #endif
177351667Smckusick 	free((caddr_t)grp);
177451667Smckusick }
177551667Smckusick 
177651667Smckusick /*
177751667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
177851667Smckusick  *
177951667Smckusick  * find the real name of path, by removing all ".", ".."
178051667Smckusick  * and symlink components.
178151667Smckusick  *
178251667Smckusick  * Jan-Simon Pendry, September 1991.
178351667Smckusick  */
178451667Smckusick char *
178551667Smckusick realpath(path, resolved)
178651667Smckusick 	char *path;
178751667Smckusick 	char resolved[MAXPATHLEN];
178851667Smckusick {
178951667Smckusick 	int d = open(".", O_RDONLY);
179051667Smckusick 	int rootd = 0;
179151667Smckusick 	char *p, *q;
179251667Smckusick 	struct stat stb;
179351667Smckusick 	char wbuf[MAXPATHLEN];
179451667Smckusick 
179551667Smckusick 	strcpy(resolved, path);
179651667Smckusick 
179751667Smckusick 	if (d < 0)
179851667Smckusick 		return 0;
179951667Smckusick 
180051667Smckusick loop:;
180151667Smckusick 	q = strrchr(resolved, '/');
180251667Smckusick 	if (q) {
180351667Smckusick 		p = q + 1;
180451667Smckusick 		if (q == resolved)
180551667Smckusick 			q = "/";
180651667Smckusick 		else {
180751667Smckusick 			do
180851667Smckusick 				--q;
180951667Smckusick 			while (q > resolved && *q == '/');
181051667Smckusick 			q[1] = '\0';
181151667Smckusick 			q = resolved;
181251667Smckusick 		}
181351667Smckusick 		if (chdir(q) < 0)
181451667Smckusick 			goto out;
181551667Smckusick 	} else
181651667Smckusick 		p = resolved;
181751667Smckusick 
181851667Smckusick 	if (lstat(p, &stb) == 0) {
181951667Smckusick 		if (S_ISLNK(stb.st_mode)) {
182051667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
182151667Smckusick 			if (n < 0)
182251667Smckusick 				goto out;
182351667Smckusick 			resolved[n] = '\0';
182451667Smckusick 			goto loop;
182551667Smckusick 		}
182651667Smckusick 		if (S_ISDIR(stb.st_mode)) {
182751667Smckusick 			if (chdir(p) < 0)
182851667Smckusick 				goto out;
182951667Smckusick 			p = "";
183051667Smckusick 		}
183151667Smckusick 	}
183251667Smckusick 
183351667Smckusick 	strcpy(wbuf, p);
183451667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
183551667Smckusick 		goto out;
183651667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
183751667Smckusick 		rootd = 1;
183851667Smckusick 
183951667Smckusick 	if (*wbuf) {
184051667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
184151667Smckusick 			errno = ENAMETOOLONG;
184251667Smckusick 			goto out;
184351667Smckusick 		}
184451667Smckusick 		if (rootd == 0)
184551667Smckusick 			strcat(resolved, "/");
184651667Smckusick 		strcat(resolved, wbuf);
184751667Smckusick 	}
184851667Smckusick 
184951667Smckusick 	if (fchdir(d) < 0)
185051667Smckusick 		goto out;
185151667Smckusick 	(void) close(d);
185251667Smckusick 
185351667Smckusick 	return resolved;
185451667Smckusick 
185551667Smckusick out:;
185651667Smckusick 	(void) close(d);
185751667Smckusick 	return 0;
185851667Smckusick }
185951711Smckusick 
186051711Smckusick #ifdef DEBUG
186151711Smckusick void
186251711Smckusick SYSLOG(int pri, const char *fmt, ...)
186351711Smckusick {
186451711Smckusick 	va_list ap;
186551711Smckusick 
186651711Smckusick 	va_start(ap, fmt);
186751711Smckusick 	vfprintf(stderr, fmt, ap);
186851711Smckusick 	va_end(ap);
186951711Smckusick }
187051711Smckusick #endif /* DEBUG */
187151898Smckusick 
187251898Smckusick /*
187351898Smckusick  * Check options for consistency.
187451898Smckusick  */
187551898Smckusick check_options(dp)
187651898Smckusick 	struct dirlist *dp;
187751898Smckusick {
187851898Smckusick 
187951898Smckusick 	if (dp == (struct dirlist *)0)
188051898Smckusick 	    return (1);
188151898Smckusick 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
188251898Smckusick 	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
188351898Smckusick 	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
188451898Smckusick 	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
188551898Smckusick 	    return (1);
188651898Smckusick 	}
188751898Smckusick 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
188851898Smckusick 	    syslog(LOG_ERR, "-mask requires -net");
188951898Smckusick 	    return (1);
189051898Smckusick 	}
189151898Smckusick 	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
189251898Smckusick 	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
189351898Smckusick 	    return (1);
189451898Smckusick 	}
189551898Smckusick 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
189651898Smckusick 	    syslog(LOG_ERR, "-alldir has multiple directories");
189751898Smckusick 	    return (1);
189851898Smckusick 	}
189951898Smckusick 	return (0);
190051898Smckusick }
1901