mountd.c revision 72650
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1989, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
191558Srgrimes *	California, Berkeley and its contributors.
201558Srgrimes * 4. Neither the name of the University nor the names of its contributors
211558Srgrimes *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
231558Srgrimes *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341558Srgrimes * SUCH DAMAGE.
351558Srgrimes */
361558Srgrimes
371558Srgrimes#ifndef lint
3837663Scharnierstatic const char copyright[] =
391558Srgrimes"@(#) Copyright (c) 1989, 1993\n\
401558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
412999Swollman#endif /*not lint*/
421558Srgrimes
431558Srgrimes#ifndef lint
4437663Scharnier#if 0
4537663Scharnierstatic char sccsid[] = "@(#)mountd.c	8.15 (Berkeley) 5/1/95";
4637663Scharnier#endif
472999Swollmanstatic const char rcsid[] =
4850476Speter  "$FreeBSD: head/usr.sbin/mountd/mountd.c 72650 2001-02-18 13:30:20Z green $";
492999Swollman#endif /*not lint*/
501558Srgrimes
511558Srgrimes#include <sys/param.h>
521558Srgrimes#include <sys/mount.h>
531558Srgrimes#include <sys/stat.h>
541558Srgrimes#include <sys/syslog.h>
5524330Sguido#include <sys/sysctl.h>
561558Srgrimes
571558Srgrimes#include <rpc/rpc.h>
581558Srgrimes#include <rpc/pmap_clnt.h>
591558Srgrimes#include <nfs/rpcv2.h>
609336Sdfr#include <nfs/nfsproto.h>
6124330Sguido#include <nfs/nfs.h>
6223681Speter#include <ufs/ufs/ufsmount.h>
6323681Speter#include <msdosfs/msdosfsmount.h>
6454093Ssemenu#include <ntfs/ntfsmount.h>
6523681Speter#include <isofs/cd9660/cd9660_mount.h>	/* XXX need isofs in include */
661558Srgrimes
671558Srgrimes#include <arpa/inet.h>
681558Srgrimes
691558Srgrimes#include <ctype.h>
7037663Scharnier#include <err.h>
711558Srgrimes#include <errno.h>
721558Srgrimes#include <grp.h>
731558Srgrimes#include <netdb.h>
741558Srgrimes#include <pwd.h>
751558Srgrimes#include <signal.h>
761558Srgrimes#include <stdio.h>
771558Srgrimes#include <stdlib.h>
781558Srgrimes#include <string.h>
791558Srgrimes#include <unistd.h>
801558Srgrimes#include "pathnames.h"
811558Srgrimes
821558Srgrimes#ifdef DEBUG
831558Srgrimes#include <stdarg.h>
841558Srgrimes#endif
851558Srgrimes
861558Srgrimes/*
871558Srgrimes * Structures for keeping the mount list and export list
881558Srgrimes */
891558Srgrimesstruct mountlist {
901558Srgrimes	struct mountlist *ml_next;
911558Srgrimes	char	ml_host[RPCMNT_NAMELEN+1];
921558Srgrimes	char	ml_dirp[RPCMNT_PATHLEN+1];
931558Srgrimes};
941558Srgrimes
951558Srgrimesstruct dirlist {
961558Srgrimes	struct dirlist	*dp_left;
971558Srgrimes	struct dirlist	*dp_right;
981558Srgrimes	int		dp_flag;
991558Srgrimes	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
1001558Srgrimes	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
1011558Srgrimes};
1021558Srgrimes/* dp_flag bits */
1031558Srgrimes#define	DP_DEFSET	0x1
1049336Sdfr#define DP_HOSTSET	0x2
1059336Sdfr#define DP_KERB		0x4
1061558Srgrimes
1071558Srgrimesstruct exportlist {
1081558Srgrimes	struct exportlist *ex_next;
1091558Srgrimes	struct dirlist	*ex_dirl;
1101558Srgrimes	struct dirlist	*ex_defdir;
1111558Srgrimes	int		ex_flag;
1121558Srgrimes	fsid_t		ex_fs;
1131558Srgrimes	char		*ex_fsdir;
11427447Sdfr	char		*ex_indexfile;
1151558Srgrimes};
1161558Srgrimes/* ex_flag bits */
1171558Srgrimes#define	EX_LINKED	0x1
1181558Srgrimes
1191558Srgrimesstruct netmsk {
12042144Sdfr	u_int32_t	nt_net;
12142144Sdfr	u_int32_t	nt_mask;
12242144Sdfr	char		*nt_name;
1231558Srgrimes};
1241558Srgrimes
1251558Srgrimesunion grouptypes {
1261558Srgrimes	struct hostent *gt_hostent;
1271558Srgrimes	struct netmsk	gt_net;
1281558Srgrimes};
1291558Srgrimes
1301558Srgrimesstruct grouplist {
1311558Srgrimes	int gr_type;
1321558Srgrimes	union grouptypes gr_ptr;
1331558Srgrimes	struct grouplist *gr_next;
1341558Srgrimes};
1351558Srgrimes/* Group types */
1361558Srgrimes#define	GT_NULL		0x0
1371558Srgrimes#define	GT_HOST		0x1
1381558Srgrimes#define	GT_NET		0x2
1397401Swpaul#define GT_IGNORE	0x5
1401558Srgrimes
1411558Srgrimesstruct hostlist {
1429336Sdfr	int		 ht_flag;	/* Uses DP_xx bits */
1431558Srgrimes	struct grouplist *ht_grp;
1441558Srgrimes	struct hostlist	 *ht_next;
1451558Srgrimes};
1461558Srgrimes
1479336Sdfrstruct fhreturn {
1489336Sdfr	int	fhr_flag;
1499336Sdfr	int	fhr_vers;
1509336Sdfr	nfsfh_t	fhr_fh;
1519336Sdfr};
1529336Sdfr
1531558Srgrimes/* Global defs */
1541558Srgrimeschar	*add_expdir __P((struct dirlist **, char *, int));
1551558Srgrimesvoid	add_dlist __P((struct dirlist **, struct dirlist *,
1569336Sdfr				struct grouplist *, int));
1571558Srgrimesvoid	add_mlist __P((char *, char *));
1581558Srgrimesint	check_dirpath __P((char *));
1591558Srgrimesint	check_options __P((struct dirlist *));
16042144Sdfrint	chk_host __P((struct dirlist *, u_int32_t, int *, int *));
1611558Srgrimesvoid	del_mlist __P((char *, char *));
1621558Srgrimesstruct dirlist *dirp_search __P((struct dirlist *, char *));
1631558Srgrimesint	do_mount __P((struct exportlist *, struct grouplist *, int,
16472650Sgreen		struct xucred *, char *, int, struct statfs *));
1651558Srgrimesint	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
16672650Sgreen				int *, int *, struct xucred *));
1671558Srgrimesstruct	exportlist *ex_search __P((fsid_t *));
1681558Srgrimesstruct	exportlist *get_exp __P((void));
1691558Srgrimesvoid	free_dir __P((struct dirlist *));
1701558Srgrimesvoid	free_exp __P((struct exportlist *));
1711558Srgrimesvoid	free_grp __P((struct grouplist *));
1721558Srgrimesvoid	free_host __P((struct hostlist *));
1731558Srgrimesvoid	get_exportlist __P((void));
1747401Swpaulint	get_host __P((char *, struct grouplist *, struct grouplist *));
1759336Sdfrint	get_num __P((char *));
1761558Srgrimesstruct hostlist *get_ht __P((void));
1771558Srgrimesint	get_line __P((void));
1781558Srgrimesvoid	get_mountlist __P((void));
1791558Srgrimesint	get_net __P((char *, struct netmsk *, int));
1801558Srgrimesvoid	getexp_err __P((struct exportlist *, struct grouplist *));
1811558Srgrimesstruct grouplist *get_grp __P((void));
1821558Srgrimesvoid	hang_dirp __P((struct dirlist *, struct grouplist *,
1831558Srgrimes				struct exportlist *, int));
1841558Srgrimesvoid	mntsrv __P((struct svc_req *, SVCXPRT *));
1851558Srgrimesvoid	nextfield __P((char **, char **));
1861558Srgrimesvoid	out_of_mem __P((void));
18772650Sgreenvoid	parsecred __P((char *, struct xucred *));
1881558Srgrimesint	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
18942144Sdfrint	scan_tree __P((struct dirlist *, u_int32_t));
19037663Scharnierstatic void usage __P((void));
1911558Srgrimesint	xdr_dir __P((XDR *, char *));
1921558Srgrimesint	xdr_explist __P((XDR *, caddr_t));
1939336Sdfrint	xdr_fhs __P((XDR *, caddr_t));
1941558Srgrimesint	xdr_mlist __P((XDR *, caddr_t));
1951558Srgrimes
1961558Srgrimes/* C library */
1971558Srgrimesint	getnetgrent();
1981558Srgrimesvoid	endnetgrent();
1991558Srgrimesvoid	setnetgrent();
2001558Srgrimes
2011558Srgrimesstruct exportlist *exphead;
2021558Srgrimesstruct mountlist *mlhead;
2031558Srgrimesstruct grouplist *grphead;
2041558Srgrimeschar exname[MAXPATHLEN];
20572650Sgreenstruct xucred def_anon = {
20672650Sgreen	0,
20772650Sgreen	(uid_t)-2,
2081558Srgrimes	1,
20972650Sgreen	{ (gid_t)-2 },
21072650Sgreen	NULL
2111558Srgrimes};
21225087Sdfrint force_v2 = 0;
2139336Sdfrint resvport_only = 1;
2149336Sdfrint dir_only = 1;
21531705Sguidoint log = 0;
2161558Srgrimesint opt_flags;
2171558Srgrimes/* Bits for above */
2181558Srgrimes#define	OP_MAPROOT	0x01
2191558Srgrimes#define	OP_MAPALL	0x02
2201558Srgrimes#define	OP_KERB		0x04
2211558Srgrimes#define	OP_MASK		0x08
2221558Srgrimes#define	OP_NET		0x10
2231558Srgrimes#define	OP_ALLDIRS	0x40
2241558Srgrimes
2251558Srgrimes#ifdef DEBUG
2261558Srgrimesint debug = 1;
2271558Srgrimesvoid	SYSLOG __P((int, const char *, ...));
2281558Srgrimes#define syslog SYSLOG
2291558Srgrimes#else
2301558Srgrimesint debug = 0;
2311558Srgrimes#endif
2321558Srgrimes
2331558Srgrimes/*
2341558Srgrimes * Mountd server for NFS mount protocol as described in:
2351558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A
2361558Srgrimes * The optional arguments are the exports file name
2371558Srgrimes * default: _PATH_EXPORTS
2381558Srgrimes * and "-n" to allow nonroot mount.
2391558Srgrimes */
2401558Srgrimesint
2411558Srgrimesmain(argc, argv)
2421558Srgrimes	int argc;
2431558Srgrimes	char **argv;
2441558Srgrimes{
2459202Srgrimes	SVCXPRT *udptransp, *tcptransp;
24632656Sbde	int c, error, mib[3];
24723681Speter	struct vfsconf vfc;
2481558Srgrimes
24923681Speter	error = getvfsbyname("nfs", &vfc);
25023681Speter	if (error && vfsisloadable("nfs")) {
2512999Swollman		if(vfsload("nfs"))
2522999Swollman			err(1, "vfsload(nfs)");
2532999Swollman		endvfsent();	/* flush cache */
25423681Speter		error = getvfsbyname("nfs", &vfc);
2552999Swollman	}
25623681Speter	if (error)
2572999Swollman		errx(1, "NFS support is not available in the running kernel");
2582999Swollman
25931665Sguido	while ((c = getopt(argc, argv, "2dlnr")) != -1)
2601558Srgrimes		switch (c) {
26125087Sdfr		case '2':
26225087Sdfr			force_v2 = 1;
26325087Sdfr			break;
2649336Sdfr		case 'n':
2659336Sdfr			resvport_only = 0;
2669336Sdfr			break;
2679336Sdfr		case 'r':
2689336Sdfr			dir_only = 0;
2699336Sdfr			break;
2708688Sphk		case 'd':
2718688Sphk			debug = debug ? 0 : 1;
2728688Sphk			break;
27331656Sguido		case 'l':
27431656Sguido			log = 1;
27531656Sguido			break;
2761558Srgrimes		default:
27737663Scharnier			usage();
2781558Srgrimes		};
2791558Srgrimes	argc -= optind;
2801558Srgrimes	argv += optind;
2811558Srgrimes	grphead = (struct grouplist *)NULL;
2821558Srgrimes	exphead = (struct exportlist *)NULL;
2831558Srgrimes	mlhead = (struct mountlist *)NULL;
2841558Srgrimes	if (argc == 1) {
2851558Srgrimes		strncpy(exname, *argv, MAXPATHLEN-1);
2861558Srgrimes		exname[MAXPATHLEN-1] = '\0';
2871558Srgrimes	} else
2881558Srgrimes		strcpy(exname, _PATH_EXPORTS);
2891558Srgrimes	openlog("mountd", LOG_PID, LOG_DAEMON);
2901558Srgrimes	if (debug)
29137663Scharnier		warnx("getting export list");
2921558Srgrimes	get_exportlist();
2931558Srgrimes	if (debug)
29437663Scharnier		warnx("getting mount list");
2951558Srgrimes	get_mountlist();
2961558Srgrimes	if (debug)
29737663Scharnier		warnx("here we go");
2981558Srgrimes	if (debug == 0) {
2991558Srgrimes		daemon(0, 0);
3001558Srgrimes		signal(SIGINT, SIG_IGN);
3011558Srgrimes		signal(SIGQUIT, SIG_IGN);
3021558Srgrimes	}
3031558Srgrimes	signal(SIGHUP, (void (*) __P((int))) get_exportlist);
3041558Srgrimes	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
3051558Srgrimes	  if (pidfile != NULL) {
3061558Srgrimes		fprintf(pidfile, "%d\n", getpid());
3071558Srgrimes		fclose(pidfile);
3081558Srgrimes	  }
3091558Srgrimes	}
31024759Sguido	if (!resvport_only) {
31124759Sguido		mib[0] = CTL_VFS;
31232656Sbde		mib[1] = vfc.vfc_typenum;
31324759Sguido		mib[2] = NFS_NFSPRIVPORT;
31424759Sguido		if (sysctl(mib, 3, NULL, NULL, &resvport_only,
31524759Sguido		    sizeof(resvport_only)) != 0 && errno != ENOENT) {
31624759Sguido			syslog(LOG_ERR, "sysctl: %m");
31724759Sguido			exit(1);
31824759Sguido		}
31924330Sguido	}
3209202Srgrimes	if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||
3219202Srgrimes	    (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {
32237663Scharnier		syslog(LOG_ERR, "can't create socket");
3231558Srgrimes		exit(1);
3241558Srgrimes	}
3259336Sdfr	pmap_unset(RPCPROG_MNT, 1);
3269336Sdfr	pmap_unset(RPCPROG_MNT, 3);
32725087Sdfr	if (!force_v2)
32825087Sdfr		if (!svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
32925087Sdfr		    !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
33037663Scharnier			syslog(LOG_ERR, "can't register mount");
33125087Sdfr			exit(1);
33225087Sdfr		}
3339336Sdfr	if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
33425087Sdfr	    !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP)) {
33537663Scharnier		syslog(LOG_ERR, "can't register mount");
3361558Srgrimes		exit(1);
3371558Srgrimes	}
3381558Srgrimes	svc_run();
33937663Scharnier	syslog(LOG_ERR, "mountd died");
3401558Srgrimes	exit(1);
3411558Srgrimes}
3421558Srgrimes
34337663Scharnierstatic void
34437663Scharnierusage()
34537663Scharnier{
34637663Scharnier	fprintf(stderr,
34737663Scharnier		"usage: mountd [-2] [-d] [-l] [-n] [-r] [export_file]\n");
34837663Scharnier	exit(1);
34937663Scharnier}
35037663Scharnier
3511558Srgrimes/*
3521558Srgrimes * The mount rpc service
3531558Srgrimes */
3541558Srgrimesvoid
3551558Srgrimesmntsrv(rqstp, transp)
3561558Srgrimes	struct svc_req *rqstp;
3571558Srgrimes	SVCXPRT *transp;
3581558Srgrimes{
3591558Srgrimes	struct exportlist *ep;
3601558Srgrimes	struct dirlist *dp;
3619336Sdfr	struct fhreturn fhr;
3621558Srgrimes	struct stat stb;
3631558Srgrimes	struct statfs fsb;
3641558Srgrimes	struct hostent *hp;
36531656Sguido	struct in_addr saddrin;
36642144Sdfr	u_int32_t saddr;
3679336Sdfr	u_short sport;
36823681Speter	char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
36928911Sguido	int bad = 0, defset, hostset;
3709336Sdfr	sigset_t sighup_mask;
3711558Srgrimes
3729336Sdfr	sigemptyset(&sighup_mask);
3739336Sdfr	sigaddset(&sighup_mask, SIGHUP);
3741558Srgrimes	saddr = transp->xp_raddr.sin_addr.s_addr;
37531656Sguido	saddrin = transp->xp_raddr.sin_addr;
3769336Sdfr	sport = ntohs(transp->xp_raddr.sin_port);
3771558Srgrimes	hp = (struct hostent *)NULL;
3781558Srgrimes	switch (rqstp->rq_proc) {
3791558Srgrimes	case NULLPROC:
3801558Srgrimes		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
38137663Scharnier			syslog(LOG_ERR, "can't send reply");
3821558Srgrimes		return;
3831558Srgrimes	case RPCMNT_MOUNT:
3849336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
38531656Sguido			syslog(LOG_NOTICE,
38631656Sguido			    "mount request from %s from unprivileged port",
38731656Sguido			    inet_ntoa(saddrin));
3881558Srgrimes			svcerr_weakauth(transp);
3891558Srgrimes			return;
3901558Srgrimes		}
3911558Srgrimes		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
39231656Sguido			syslog(LOG_NOTICE, "undecodable mount request from %s",
39331656Sguido			    inet_ntoa(saddrin));
3941558Srgrimes			svcerr_decode(transp);
3951558Srgrimes			return;
3961558Srgrimes		}
3971558Srgrimes
3981558Srgrimes		/*
3991558Srgrimes		 * Get the real pathname and make sure it is a directory
4009336Sdfr		 * or a regular file if the -r option was specified
4019336Sdfr		 * and it exists.
4021558Srgrimes		 */
40351968Salfred		if (realpath(rpcpath, dirpath) == NULL ||
4041558Srgrimes		    stat(dirpath, &stb) < 0 ||
4059336Sdfr		    (!S_ISDIR(stb.st_mode) &&
4069336Sdfr		     (dir_only || !S_ISREG(stb.st_mode))) ||
4071558Srgrimes		    statfs(dirpath, &fsb) < 0) {
4081558Srgrimes			chdir("/");	/* Just in case realpath doesn't */
40931656Sguido			syslog(LOG_NOTICE,
41037663Scharnier			    "mount request from %s for non existent path %s",
41131656Sguido			    inet_ntoa(saddrin), dirpath);
4121558Srgrimes			if (debug)
41337663Scharnier				warnx("stat failed on %s", dirpath);
41428911Sguido			bad = ENOENT;	/* We will send error reply later */
4151558Srgrimes		}
4161558Srgrimes
4171558Srgrimes		/* Check in the exports list */
4189336Sdfr		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
4191558Srgrimes		ep = ex_search(&fsb.f_fsid);
4209336Sdfr		hostset = defset = 0;
4219336Sdfr		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
4221558Srgrimes		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
4239336Sdfr		     chk_host(dp, saddr, &defset, &hostset)) ||
4241558Srgrimes		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
4251558Srgrimes		      scan_tree(ep->ex_dirl, saddr) == 0))) {
42628911Sguido			if (bad) {
42728911Sguido				if (!svc_sendreply(transp, xdr_long,
42828911Sguido				    (caddr_t)&bad))
42937663Scharnier					syslog(LOG_ERR, "can't send reply");
43028911Sguido				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
43128911Sguido				return;
43228911Sguido			}
4339336Sdfr			if (hostset & DP_HOSTSET)
4349336Sdfr				fhr.fhr_flag = hostset;
4359336Sdfr			else
4369336Sdfr				fhr.fhr_flag = defset;
4379336Sdfr			fhr.fhr_vers = rqstp->rq_vers;
4381558Srgrimes			/* Get the file handle */
43923681Speter			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
4409336Sdfr			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
4411558Srgrimes				bad = errno;
44237663Scharnier				syslog(LOG_ERR, "can't get fh for %s", dirpath);
4431558Srgrimes				if (!svc_sendreply(transp, xdr_long,
4441558Srgrimes				    (caddr_t)&bad))
44537663Scharnier					syslog(LOG_ERR, "can't send reply");
4469336Sdfr				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
4471558Srgrimes				return;
4481558Srgrimes			}
4499336Sdfr			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
45037663Scharnier				syslog(LOG_ERR, "can't send reply");
4511558Srgrimes			if (hp == NULL)
4521558Srgrimes				hp = gethostbyaddr((caddr_t)&saddr,
4531558Srgrimes				    sizeof(saddr), AF_INET);
4541558Srgrimes			if (hp)
4551558Srgrimes				add_mlist(hp->h_name, dirpath);
4561558Srgrimes			else
45731656Sguido				add_mlist(inet_ntoa(saddrin),
4581558Srgrimes					dirpath);
4591558Srgrimes			if (debug)
46037663Scharnier				warnx("mount successful");
46131656Sguido			if (log)
46231656Sguido				syslog(LOG_NOTICE,
46331656Sguido				    "mount request succeeded from %s for %s",
46431656Sguido				    inet_ntoa(saddrin), dirpath);
46531656Sguido		} else {
4661558Srgrimes			bad = EACCES;
46731656Sguido			syslog(LOG_NOTICE,
46831656Sguido			    "mount request denied from %s for %s",
46931656Sguido			    inet_ntoa(saddrin), dirpath);
47031656Sguido		}
47128911Sguido
47228911Sguido		if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))
47337663Scharnier			syslog(LOG_ERR, "can't send reply");
4749336Sdfr		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
4751558Srgrimes		return;
4761558Srgrimes	case RPCMNT_DUMP:
4771558Srgrimes		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
47837663Scharnier			syslog(LOG_ERR, "can't send reply");
47931656Sguido		else if (log)
48031656Sguido			syslog(LOG_NOTICE,
48131656Sguido			    "dump request succeeded from %s",
48238023Sbde			    inet_ntoa(saddrin));
4831558Srgrimes		return;
4841558Srgrimes	case RPCMNT_UMOUNT:
4859336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
48631656Sguido			syslog(LOG_NOTICE,
48731656Sguido			    "umount request from %s from unprivileged port",
48831656Sguido			    inet_ntoa(saddrin));
4891558Srgrimes			svcerr_weakauth(transp);
4901558Srgrimes			return;
4911558Srgrimes		}
49251968Salfred		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
49331656Sguido			syslog(LOG_NOTICE, "undecodable umount request from %s",
49431656Sguido			    inet_ntoa(saddrin));
4951558Srgrimes			svcerr_decode(transp);
4961558Srgrimes			return;
4971558Srgrimes		}
49851968Salfred		if (realpath(rpcpath, dirpath) == NULL) {
49951968Salfred			syslog(LOG_NOTICE, "umount request from %s "
50051968Salfred			    "for non existent path %s",
50151968Salfred			    inet_ntoa(saddrin), dirpath);
50251968Salfred		}
5031558Srgrimes		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
50437663Scharnier			syslog(LOG_ERR, "can't send reply");
5051558Srgrimes		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
5061558Srgrimes		if (hp)
5071558Srgrimes			del_mlist(hp->h_name, dirpath);
50831656Sguido		del_mlist(inet_ntoa(saddrin), dirpath);
50931656Sguido		if (log)
51031656Sguido			syslog(LOG_NOTICE,
51131656Sguido			    "umount request succeeded from %s for %s",
51231656Sguido			    inet_ntoa(saddrin), dirpath);
5131558Srgrimes		return;
5141558Srgrimes	case RPCMNT_UMNTALL:
5159336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
51631656Sguido			syslog(LOG_NOTICE,
51731656Sguido			    "umountall request from %s from unprivileged port",
51831656Sguido			    inet_ntoa(saddrin));
5191558Srgrimes			svcerr_weakauth(transp);
5201558Srgrimes			return;
5211558Srgrimes		}
5221558Srgrimes		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
52337663Scharnier			syslog(LOG_ERR, "can't send reply");
5241558Srgrimes		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
5251558Srgrimes		if (hp)
5261558Srgrimes			del_mlist(hp->h_name, (char *)NULL);
52731656Sguido		del_mlist(inet_ntoa(saddrin), (char *)NULL);
52831656Sguido		if (log)
52931656Sguido			syslog(LOG_NOTICE,
53031656Sguido			    "umountall request succeeded from %s",
53131656Sguido			    inet_ntoa(saddrin));
5321558Srgrimes		return;
5331558Srgrimes	case RPCMNT_EXPORT:
5341558Srgrimes		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
53537663Scharnier			syslog(LOG_ERR, "can't send reply");
53631656Sguido		if (log)
53731656Sguido			syslog(LOG_NOTICE,
53831656Sguido			    "export request succeeded from %s",
53931656Sguido			    inet_ntoa(saddrin));
5401558Srgrimes		return;
5411558Srgrimes	default:
5421558Srgrimes		svcerr_noproc(transp);
5431558Srgrimes		return;
5441558Srgrimes	}
5451558Srgrimes}
5461558Srgrimes
5471558Srgrimes/*
5481558Srgrimes * Xdr conversion for a dirpath string
5491558Srgrimes */
5501558Srgrimesint
5511558Srgrimesxdr_dir(xdrsp, dirp)
5521558Srgrimes	XDR *xdrsp;
5531558Srgrimes	char *dirp;
5541558Srgrimes{
5551558Srgrimes	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
5561558Srgrimes}
5571558Srgrimes
5581558Srgrimes/*
5599336Sdfr * Xdr routine to generate file handle reply
5601558Srgrimes */
5611558Srgrimesint
5629336Sdfrxdr_fhs(xdrsp, cp)
5631558Srgrimes	XDR *xdrsp;
5649336Sdfr	caddr_t cp;
5651558Srgrimes{
5669336Sdfr	register struct fhreturn *fhrp = (struct fhreturn *)cp;
5679336Sdfr	u_long ok = 0, len, auth;
5681558Srgrimes
5691558Srgrimes	if (!xdr_long(xdrsp, &ok))
5701558Srgrimes		return (0);
5719336Sdfr	switch (fhrp->fhr_vers) {
5729336Sdfr	case 1:
5739336Sdfr		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
5749336Sdfr	case 3:
5759336Sdfr		len = NFSX_V3FH;
5769336Sdfr		if (!xdr_long(xdrsp, &len))
5779336Sdfr			return (0);
5789336Sdfr		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
5799336Sdfr			return (0);
5809336Sdfr		if (fhrp->fhr_flag & DP_KERB)
5819336Sdfr			auth = RPCAUTH_KERB4;
5829336Sdfr		else
5839336Sdfr			auth = RPCAUTH_UNIX;
5849336Sdfr		len = 1;
5859336Sdfr		if (!xdr_long(xdrsp, &len))
5869336Sdfr			return (0);
5879336Sdfr		return (xdr_long(xdrsp, &auth));
5889336Sdfr	};
5899336Sdfr	return (0);
5901558Srgrimes}
5911558Srgrimes
5921558Srgrimesint
5931558Srgrimesxdr_mlist(xdrsp, cp)
5941558Srgrimes	XDR *xdrsp;
5951558Srgrimes	caddr_t cp;
5961558Srgrimes{
5971558Srgrimes	struct mountlist *mlp;
5981558Srgrimes	int true = 1;
5991558Srgrimes	int false = 0;
6001558Srgrimes	char *strp;
6011558Srgrimes
6021558Srgrimes	mlp = mlhead;
6031558Srgrimes	while (mlp) {
6041558Srgrimes		if (!xdr_bool(xdrsp, &true))
6051558Srgrimes			return (0);
6061558Srgrimes		strp = &mlp->ml_host[0];
6071558Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
6081558Srgrimes			return (0);
6091558Srgrimes		strp = &mlp->ml_dirp[0];
6101558Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
6111558Srgrimes			return (0);
6121558Srgrimes		mlp = mlp->ml_next;
6131558Srgrimes	}
6141558Srgrimes	if (!xdr_bool(xdrsp, &false))
6151558Srgrimes		return (0);
6161558Srgrimes	return (1);
6171558Srgrimes}
6181558Srgrimes
6191558Srgrimes/*
6201558Srgrimes * Xdr conversion for export list
6211558Srgrimes */
6221558Srgrimesint
6231558Srgrimesxdr_explist(xdrsp, cp)
6241558Srgrimes	XDR *xdrsp;
6251558Srgrimes	caddr_t cp;
6261558Srgrimes{
6271558Srgrimes	struct exportlist *ep;
6281558Srgrimes	int false = 0;
6299336Sdfr	int putdef;
6309336Sdfr	sigset_t sighup_mask;
6311558Srgrimes
6329336Sdfr	sigemptyset(&sighup_mask);
6339336Sdfr	sigaddset(&sighup_mask, SIGHUP);
6349336Sdfr	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
6351558Srgrimes	ep = exphead;
6361558Srgrimes	while (ep) {
6371558Srgrimes		putdef = 0;
6381558Srgrimes		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
6391558Srgrimes			goto errout;
6401558Srgrimes		if (ep->ex_defdir && putdef == 0 &&
6411558Srgrimes			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
6421558Srgrimes			&putdef))
6431558Srgrimes			goto errout;
6441558Srgrimes		ep = ep->ex_next;
6451558Srgrimes	}
6469336Sdfr	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
6471558Srgrimes	if (!xdr_bool(xdrsp, &false))
6481558Srgrimes		return (0);
6491558Srgrimes	return (1);
6501558Srgrimeserrout:
6519336Sdfr	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
6521558Srgrimes	return (0);
6531558Srgrimes}
6541558Srgrimes
6551558Srgrimes/*
6561558Srgrimes * Called from xdr_explist() to traverse the tree and export the
6571558Srgrimes * directory paths.
6581558Srgrimes */
6591558Srgrimesint
6601558Srgrimesput_exlist(dp, xdrsp, adp, putdefp)
6611558Srgrimes	struct dirlist *dp;
6621558Srgrimes	XDR *xdrsp;
6631558Srgrimes	struct dirlist *adp;
6641558Srgrimes	int *putdefp;
6651558Srgrimes{
6661558Srgrimes	struct grouplist *grp;
6671558Srgrimes	struct hostlist *hp;
6681558Srgrimes	int true = 1;
6691558Srgrimes	int false = 0;
6701558Srgrimes	int gotalldir = 0;
6711558Srgrimes	char *strp;
6721558Srgrimes
6731558Srgrimes	if (dp) {
6741558Srgrimes		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
6751558Srgrimes			return (1);
6761558Srgrimes		if (!xdr_bool(xdrsp, &true))
6771558Srgrimes			return (1);
6781558Srgrimes		strp = dp->dp_dirp;
6791558Srgrimes		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
6801558Srgrimes			return (1);
6811558Srgrimes		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
6821558Srgrimes			gotalldir = 1;
6831558Srgrimes			*putdefp = 1;
6841558Srgrimes		}
6851558Srgrimes		if ((dp->dp_flag & DP_DEFSET) == 0 &&
6861558Srgrimes		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
6871558Srgrimes			hp = dp->dp_hosts;
6881558Srgrimes			while (hp) {
6891558Srgrimes				grp = hp->ht_grp;
6901558Srgrimes				if (grp->gr_type == GT_HOST) {
6911558Srgrimes					if (!xdr_bool(xdrsp, &true))
6921558Srgrimes						return (1);
6931558Srgrimes					strp = grp->gr_ptr.gt_hostent->h_name;
6948871Srgrimes					if (!xdr_string(xdrsp, &strp,
6951558Srgrimes					    RPCMNT_NAMELEN))
6961558Srgrimes						return (1);
6971558Srgrimes				} else if (grp->gr_type == GT_NET) {
6981558Srgrimes					if (!xdr_bool(xdrsp, &true))
6991558Srgrimes						return (1);
7001558Srgrimes					strp = grp->gr_ptr.gt_net.nt_name;
7018871Srgrimes					if (!xdr_string(xdrsp, &strp,
7021558Srgrimes					    RPCMNT_NAMELEN))
7031558Srgrimes						return (1);
7041558Srgrimes				}
7051558Srgrimes				hp = hp->ht_next;
7061558Srgrimes				if (gotalldir && hp == (struct hostlist *)NULL) {
7071558Srgrimes					hp = adp->dp_hosts;
7081558Srgrimes					gotalldir = 0;
7091558Srgrimes				}
7101558Srgrimes			}
7111558Srgrimes		}
7121558Srgrimes		if (!xdr_bool(xdrsp, &false))
7131558Srgrimes			return (1);
7141558Srgrimes		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
7151558Srgrimes			return (1);
7161558Srgrimes	}
7171558Srgrimes	return (0);
7181558Srgrimes}
7191558Srgrimes
7201558Srgrimes#define LINESIZ	10240
7211558Srgrimeschar line[LINESIZ];
7221558SrgrimesFILE *exp_file;
7231558Srgrimes
7241558Srgrimes/*
7251558Srgrimes * Get the export list
7261558Srgrimes */
7271558Srgrimesvoid
7281558Srgrimesget_exportlist()
7291558Srgrimes{
7301558Srgrimes	struct exportlist *ep, *ep2;
7311558Srgrimes	struct grouplist *grp, *tgrp;
7321558Srgrimes	struct exportlist **epp;
7331558Srgrimes	struct dirlist *dirhead;
7341558Srgrimes	struct statfs fsb, *fsp;
7351558Srgrimes	struct hostent *hpe;
73672650Sgreen	struct xucred anon;
7371558Srgrimes	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
7381558Srgrimes	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
7391558Srgrimes
74051968Salfred	dirp = NULL;
74151968Salfred	dirplen = 0;
74251968Salfred
7431558Srgrimes	/*
7441558Srgrimes	 * First, get rid of the old list
7451558Srgrimes	 */
7461558Srgrimes	ep = exphead;
7471558Srgrimes	while (ep) {
7481558Srgrimes		ep2 = ep;
7491558Srgrimes		ep = ep->ex_next;
7501558Srgrimes		free_exp(ep2);
7511558Srgrimes	}
7521558Srgrimes	exphead = (struct exportlist *)NULL;
7531558Srgrimes
7541558Srgrimes	grp = grphead;
7551558Srgrimes	while (grp) {
7561558Srgrimes		tgrp = grp;
7571558Srgrimes		grp = grp->gr_next;
7581558Srgrimes		free_grp(tgrp);
7591558Srgrimes	}
7601558Srgrimes	grphead = (struct grouplist *)NULL;
7611558Srgrimes
7621558Srgrimes	/*
7631558Srgrimes	 * And delete exports that are in the kernel for all local
7641558Srgrimes	 * file systems.
7651558Srgrimes	 * XXX: Should know how to handle all local exportable file systems
76623681Speter	 *      instead of just "ufs".
7671558Srgrimes	 */
7681558Srgrimes	num = getmntinfo(&fsp, MNT_NOWAIT);
7691558Srgrimes	for (i = 0; i < num; i++) {
7701558Srgrimes		union {
7711558Srgrimes			struct ufs_args ua;
7721558Srgrimes			struct iso_args ia;
7731558Srgrimes			struct mfs_args ma;
7749336Sdfr			struct msdosfs_args da;
77554093Ssemenu			struct ntfs_args na;
7761558Srgrimes		} targs;
7771558Srgrimes
77823681Speter		if (!strcmp(fsp->f_fstypename, "mfs") ||
77923681Speter		    !strcmp(fsp->f_fstypename, "ufs") ||
78023681Speter		    !strcmp(fsp->f_fstypename, "msdos") ||
78154093Ssemenu		    !strcmp(fsp->f_fstypename, "ntfs") ||
78223681Speter		    !strcmp(fsp->f_fstypename, "cd9660")) {
7839336Sdfr			targs.ua.fspec = NULL;
7849336Sdfr			targs.ua.export.ex_flags = MNT_DELEXPORT;
7859336Sdfr			if (mount(fsp->f_fstypename, fsp->f_mntonname,
7861558Srgrimes				  fsp->f_flags | MNT_UPDATE,
7871558Srgrimes				  (caddr_t)&targs) < 0)
78837663Scharnier				syslog(LOG_ERR, "can't delete exports for %s",
7891558Srgrimes				       fsp->f_mntonname);
7901558Srgrimes		}
7911558Srgrimes		fsp++;
7921558Srgrimes	}
7931558Srgrimes
7941558Srgrimes	/*
7951558Srgrimes	 * Read in the exports file and build the list, calling
7961558Srgrimes	 * mount() as we go along to push the export rules into the kernel.
7971558Srgrimes	 */
7981558Srgrimes	if ((exp_file = fopen(exname, "r")) == NULL) {
79937663Scharnier		syslog(LOG_ERR, "can't open %s", exname);
8001558Srgrimes		exit(2);
8011558Srgrimes	}
8021558Srgrimes	dirhead = (struct dirlist *)NULL;
8031558Srgrimes	while (get_line()) {
8041558Srgrimes		if (debug)
80537663Scharnier			warnx("got line %s", line);
8061558Srgrimes		cp = line;
8071558Srgrimes		nextfield(&cp, &endcp);
8081558Srgrimes		if (*cp == '#')
8091558Srgrimes			goto nextline;
8101558Srgrimes
8111558Srgrimes		/*
8121558Srgrimes		 * Set defaults.
8131558Srgrimes		 */
8141558Srgrimes		has_host = FALSE;
8151558Srgrimes		anon = def_anon;
8161558Srgrimes		exflags = MNT_EXPORTED;
8171558Srgrimes		got_nondir = 0;
8181558Srgrimes		opt_flags = 0;
8191558Srgrimes		ep = (struct exportlist *)NULL;
8201558Srgrimes
8211558Srgrimes		/*
8221558Srgrimes		 * Create new exports list entry
8231558Srgrimes		 */
8241558Srgrimes		len = endcp-cp;
8251558Srgrimes		tgrp = grp = get_grp();
8261558Srgrimes		while (len > 0) {
8271558Srgrimes			if (len > RPCMNT_NAMELEN) {
8281558Srgrimes			    getexp_err(ep, tgrp);
8291558Srgrimes			    goto nextline;
8301558Srgrimes			}
8311558Srgrimes			if (*cp == '-') {
8321558Srgrimes			    if (ep == (struct exportlist *)NULL) {
8331558Srgrimes				getexp_err(ep, tgrp);
8341558Srgrimes				goto nextline;
8351558Srgrimes			    }
8361558Srgrimes			    if (debug)
83737663Scharnier				warnx("doing opt %s", cp);
8381558Srgrimes			    got_nondir = 1;
8391558Srgrimes			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
8401558Srgrimes				&exflags, &anon)) {
8411558Srgrimes				getexp_err(ep, tgrp);
8421558Srgrimes				goto nextline;
8431558Srgrimes			    }
8441558Srgrimes			} else if (*cp == '/') {
8451558Srgrimes			    savedc = *endcp;
8461558Srgrimes			    *endcp = '\0';
8471558Srgrimes			    if (check_dirpath(cp) &&
8481558Srgrimes				statfs(cp, &fsb) >= 0) {
8491558Srgrimes				if (got_nondir) {
85037663Scharnier				    syslog(LOG_ERR, "dirs must be first");
8511558Srgrimes				    getexp_err(ep, tgrp);
8521558Srgrimes				    goto nextline;
8531558Srgrimes				}
8541558Srgrimes				if (ep) {
8551558Srgrimes				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
8561558Srgrimes					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
8571558Srgrimes					getexp_err(ep, tgrp);
8581558Srgrimes					goto nextline;
8591558Srgrimes				    }
8601558Srgrimes				} else {
8611558Srgrimes				    /*
8621558Srgrimes				     * See if this directory is already
8631558Srgrimes				     * in the list.
8641558Srgrimes				     */
8651558Srgrimes				    ep = ex_search(&fsb.f_fsid);
8661558Srgrimes				    if (ep == (struct exportlist *)NULL) {
8671558Srgrimes					ep = get_exp();
8681558Srgrimes					ep->ex_fs = fsb.f_fsid;
8691558Srgrimes					ep->ex_fsdir = (char *)
8701558Srgrimes					    malloc(strlen(fsb.f_mntonname) + 1);
8711558Srgrimes					if (ep->ex_fsdir)
8721558Srgrimes					    strcpy(ep->ex_fsdir,
8731558Srgrimes						fsb.f_mntonname);
8741558Srgrimes					else
8751558Srgrimes					    out_of_mem();
8761558Srgrimes					if (debug)
87737663Scharnier					  warnx("making new ep fs=0x%x,0x%x",
8781558Srgrimes					      fsb.f_fsid.val[0],
8791558Srgrimes					      fsb.f_fsid.val[1]);
8801558Srgrimes				    } else if (debug)
88137663Scharnier					warnx("found ep fs=0x%x,0x%x",
8821558Srgrimes					    fsb.f_fsid.val[0],
8831558Srgrimes					    fsb.f_fsid.val[1]);
8841558Srgrimes				}
8851558Srgrimes
8861558Srgrimes				/*
8871558Srgrimes				 * Add dirpath to export mount point.
8881558Srgrimes				 */
8891558Srgrimes				dirp = add_expdir(&dirhead, cp, len);
8901558Srgrimes				dirplen = len;
8911558Srgrimes			    } else {
8921558Srgrimes				getexp_err(ep, tgrp);
8931558Srgrimes				goto nextline;
8941558Srgrimes			    }
8951558Srgrimes			    *endcp = savedc;
8961558Srgrimes			} else {
8971558Srgrimes			    savedc = *endcp;
8981558Srgrimes			    *endcp = '\0';
8991558Srgrimes			    got_nondir = 1;
9001558Srgrimes			    if (ep == (struct exportlist *)NULL) {
9011558Srgrimes				getexp_err(ep, tgrp);
9021558Srgrimes				goto nextline;
9031558Srgrimes			    }
9041558Srgrimes
9051558Srgrimes			    /*
9061558Srgrimes			     * Get the host or netgroup.
9071558Srgrimes			     */
9081558Srgrimes			    setnetgrent(cp);
9091558Srgrimes			    netgrp = getnetgrent(&hst, &usr, &dom);
9101558Srgrimes			    do {
9111558Srgrimes				if (has_host) {
9121558Srgrimes				    grp->gr_next = get_grp();
9131558Srgrimes				    grp = grp->gr_next;
9141558Srgrimes				}
9151558Srgrimes				if (netgrp) {
91637003Sjoerg				    if (hst == 0) {
91737663Scharnier					syslog(LOG_ERR,
91837663Scharnier				"null hostname in netgroup %s, skipping", cp);
91937004Sjoerg					grp->gr_type = GT_IGNORE;
92037003Sjoerg				    } else if (get_host(hst, grp, tgrp)) {
92137663Scharnier					syslog(LOG_ERR,
92237663Scharnier			"bad host %s in netgroup %s, skipping", hst, cp);
92329317Sjlemon					grp->gr_type = GT_IGNORE;
9241558Srgrimes				    }
9257401Swpaul				} else if (get_host(cp, grp, tgrp)) {
92637663Scharnier				    syslog(LOG_ERR, "bad host %s, skipping", cp);
92729317Sjlemon				    grp->gr_type = GT_IGNORE;
9281558Srgrimes				}
9291558Srgrimes				has_host = TRUE;
9301558Srgrimes			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
9311558Srgrimes			    endnetgrent();
9321558Srgrimes			    *endcp = savedc;
9331558Srgrimes			}
9341558Srgrimes			cp = endcp;
9351558Srgrimes			nextfield(&cp, &endcp);
9361558Srgrimes			len = endcp - cp;
9371558Srgrimes		}
9381558Srgrimes		if (check_options(dirhead)) {
9391558Srgrimes			getexp_err(ep, tgrp);
9401558Srgrimes			goto nextline;
9411558Srgrimes		}
9421558Srgrimes		if (!has_host) {
9431558Srgrimes			grp->gr_type = GT_HOST;
9441558Srgrimes			if (debug)
94537663Scharnier				warnx("adding a default entry");
9461558Srgrimes			/* add a default group and make the grp list NULL */
9471558Srgrimes			hpe = (struct hostent *)malloc(sizeof(struct hostent));
9481558Srgrimes			if (hpe == (struct hostent *)NULL)
9491558Srgrimes				out_of_mem();
95012348Sjoerg			hpe->h_name = strdup("Default");
9511558Srgrimes			hpe->h_addrtype = AF_INET;
95242144Sdfr			hpe->h_length = sizeof (u_int32_t);
9531558Srgrimes			hpe->h_addr_list = (char **)NULL;
9541558Srgrimes			grp->gr_ptr.gt_hostent = hpe;
9551558Srgrimes
9561558Srgrimes		/*
9571558Srgrimes		 * Don't allow a network export coincide with a list of
9581558Srgrimes		 * host(s) on the same line.
9591558Srgrimes		 */
9601558Srgrimes		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
9611558Srgrimes			getexp_err(ep, tgrp);
9621558Srgrimes			goto nextline;
96329317Sjlemon
96429317Sjlemon        	/*
96529317Sjlemon	         * If an export list was specified on this line, make sure
96629317Sjlemon		 * that we have at least one valid entry, otherwise skip it.
96729317Sjlemon		 */
96829317Sjlemon		} else {
96929317Sjlemon			grp = tgrp;
97029317Sjlemon        		while (grp && grp->gr_type == GT_IGNORE)
97129317Sjlemon				grp = grp->gr_next;
97229317Sjlemon			if (! grp) {
97329317Sjlemon			    getexp_err(ep, tgrp);
97429317Sjlemon			    goto nextline;
97529317Sjlemon			}
9761558Srgrimes		}
9771558Srgrimes
9781558Srgrimes		/*
9791558Srgrimes		 * Loop through hosts, pushing the exports into the kernel.
9801558Srgrimes		 * After loop, tgrp points to the start of the list and
9811558Srgrimes		 * grp points to the last entry in the list.
9821558Srgrimes		 */
9831558Srgrimes		grp = tgrp;
9841558Srgrimes		do {
9851558Srgrimes		    if (do_mount(ep, grp, exflags, &anon, dirp,
9861558Srgrimes			dirplen, &fsb)) {
9871558Srgrimes			getexp_err(ep, tgrp);
9881558Srgrimes			goto nextline;
9891558Srgrimes		    }
9901558Srgrimes		} while (grp->gr_next && (grp = grp->gr_next));
9911558Srgrimes
9921558Srgrimes		/*
9931558Srgrimes		 * Success. Update the data structures.
9941558Srgrimes		 */
9951558Srgrimes		if (has_host) {
9969336Sdfr			hang_dirp(dirhead, tgrp, ep, opt_flags);
9971558Srgrimes			grp->gr_next = grphead;
9981558Srgrimes			grphead = tgrp;
9991558Srgrimes		} else {
10001558Srgrimes			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
10019336Sdfr				opt_flags);
10021558Srgrimes			free_grp(grp);
10031558Srgrimes		}
10041558Srgrimes		dirhead = (struct dirlist *)NULL;
10051558Srgrimes		if ((ep->ex_flag & EX_LINKED) == 0) {
10061558Srgrimes			ep2 = exphead;
10071558Srgrimes			epp = &exphead;
10081558Srgrimes
10091558Srgrimes			/*
10101558Srgrimes			 * Insert in the list in alphabetical order.
10111558Srgrimes			 */
10121558Srgrimes			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
10131558Srgrimes				epp = &ep2->ex_next;
10141558Srgrimes				ep2 = ep2->ex_next;
10151558Srgrimes			}
10161558Srgrimes			if (ep2)
10171558Srgrimes				ep->ex_next = ep2;
10181558Srgrimes			*epp = ep;
10191558Srgrimes			ep->ex_flag |= EX_LINKED;
10201558Srgrimes		}
10211558Srgrimesnextline:
10221558Srgrimes		if (dirhead) {
10231558Srgrimes			free_dir(dirhead);
10241558Srgrimes			dirhead = (struct dirlist *)NULL;
10251558Srgrimes		}
10261558Srgrimes	}
10271558Srgrimes	fclose(exp_file);
10281558Srgrimes}
10291558Srgrimes
10301558Srgrimes/*
10311558Srgrimes * Allocate an export list element
10321558Srgrimes */
10331558Srgrimesstruct exportlist *
10341558Srgrimesget_exp()
10351558Srgrimes{
10361558Srgrimes	struct exportlist *ep;
10371558Srgrimes
10381558Srgrimes	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
10391558Srgrimes	if (ep == (struct exportlist *)NULL)
10401558Srgrimes		out_of_mem();
104123681Speter	memset(ep, 0, sizeof(struct exportlist));
10421558Srgrimes	return (ep);
10431558Srgrimes}
10441558Srgrimes
10451558Srgrimes/*
10461558Srgrimes * Allocate a group list element
10471558Srgrimes */
10481558Srgrimesstruct grouplist *
10491558Srgrimesget_grp()
10501558Srgrimes{
10511558Srgrimes	struct grouplist *gp;
10521558Srgrimes
10531558Srgrimes	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
10541558Srgrimes	if (gp == (struct grouplist *)NULL)
10551558Srgrimes		out_of_mem();
105623681Speter	memset(gp, 0, sizeof(struct grouplist));
10571558Srgrimes	return (gp);
10581558Srgrimes}
10591558Srgrimes
10601558Srgrimes/*
10611558Srgrimes * Clean up upon an error in get_exportlist().
10621558Srgrimes */
10631558Srgrimesvoid
10641558Srgrimesgetexp_err(ep, grp)
10651558Srgrimes	struct exportlist *ep;
10661558Srgrimes	struct grouplist *grp;
10671558Srgrimes{
10681558Srgrimes	struct grouplist *tgrp;
10691558Srgrimes
107037663Scharnier	syslog(LOG_ERR, "bad exports list line %s", line);
10711558Srgrimes	if (ep && (ep->ex_flag & EX_LINKED) == 0)
10721558Srgrimes		free_exp(ep);
10731558Srgrimes	while (grp) {
10741558Srgrimes		tgrp = grp;
10751558Srgrimes		grp = grp->gr_next;
10761558Srgrimes		free_grp(tgrp);
10771558Srgrimes	}
10781558Srgrimes}
10791558Srgrimes
10801558Srgrimes/*
10811558Srgrimes * Search the export list for a matching fs.
10821558Srgrimes */
10831558Srgrimesstruct exportlist *
10841558Srgrimesex_search(fsid)
10851558Srgrimes	fsid_t *fsid;
10861558Srgrimes{
10871558Srgrimes	struct exportlist *ep;
10881558Srgrimes
10891558Srgrimes	ep = exphead;
10901558Srgrimes	while (ep) {
10911558Srgrimes		if (ep->ex_fs.val[0] == fsid->val[0] &&
10921558Srgrimes		    ep->ex_fs.val[1] == fsid->val[1])
10931558Srgrimes			return (ep);
10941558Srgrimes		ep = ep->ex_next;
10951558Srgrimes	}
10961558Srgrimes	return (ep);
10971558Srgrimes}
10981558Srgrimes
10991558Srgrimes/*
11001558Srgrimes * Add a directory path to the list.
11011558Srgrimes */
11021558Srgrimeschar *
11031558Srgrimesadd_expdir(dpp, cp, len)
11041558Srgrimes	struct dirlist **dpp;
11051558Srgrimes	char *cp;
11061558Srgrimes	int len;
11071558Srgrimes{
11081558Srgrimes	struct dirlist *dp;
11091558Srgrimes
11101558Srgrimes	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
111137663Scharnier	if (dp == (struct dirlist *)NULL)
111237663Scharnier		out_of_mem();
11131558Srgrimes	dp->dp_left = *dpp;
11141558Srgrimes	dp->dp_right = (struct dirlist *)NULL;
11151558Srgrimes	dp->dp_flag = 0;
11161558Srgrimes	dp->dp_hosts = (struct hostlist *)NULL;
11171558Srgrimes	strcpy(dp->dp_dirp, cp);
11181558Srgrimes	*dpp = dp;
11191558Srgrimes	return (dp->dp_dirp);
11201558Srgrimes}
11211558Srgrimes
11221558Srgrimes/*
11231558Srgrimes * Hang the dir list element off the dirpath binary tree as required
11241558Srgrimes * and update the entry for host.
11251558Srgrimes */
11261558Srgrimesvoid
11279336Sdfrhang_dirp(dp, grp, ep, flags)
11281558Srgrimes	struct dirlist *dp;
11291558Srgrimes	struct grouplist *grp;
11301558Srgrimes	struct exportlist *ep;
11319336Sdfr	int flags;
11321558Srgrimes{
11331558Srgrimes	struct hostlist *hp;
11341558Srgrimes	struct dirlist *dp2;
11351558Srgrimes
11369336Sdfr	if (flags & OP_ALLDIRS) {
11371558Srgrimes		if (ep->ex_defdir)
11381558Srgrimes			free((caddr_t)dp);
11391558Srgrimes		else
11401558Srgrimes			ep->ex_defdir = dp;
11419336Sdfr		if (grp == (struct grouplist *)NULL) {
11421558Srgrimes			ep->ex_defdir->dp_flag |= DP_DEFSET;
11439336Sdfr			if (flags & OP_KERB)
11449336Sdfr				ep->ex_defdir->dp_flag |= DP_KERB;
11459336Sdfr		} else while (grp) {
11461558Srgrimes			hp = get_ht();
11479336Sdfr			if (flags & OP_KERB)
11489336Sdfr				hp->ht_flag |= DP_KERB;
11491558Srgrimes			hp->ht_grp = grp;
11501558Srgrimes			hp->ht_next = ep->ex_defdir->dp_hosts;
11511558Srgrimes			ep->ex_defdir->dp_hosts = hp;
11521558Srgrimes			grp = grp->gr_next;
11531558Srgrimes		}
11541558Srgrimes	} else {
11551558Srgrimes
11561558Srgrimes		/*
115737663Scharnier		 * Loop through the directories adding them to the tree.
11581558Srgrimes		 */
11591558Srgrimes		while (dp) {
11601558Srgrimes			dp2 = dp->dp_left;
11619336Sdfr			add_dlist(&ep->ex_dirl, dp, grp, flags);
11621558Srgrimes			dp = dp2;
11631558Srgrimes		}
11641558Srgrimes	}
11651558Srgrimes}
11661558Srgrimes
11671558Srgrimes/*
11681558Srgrimes * Traverse the binary tree either updating a node that is already there
11691558Srgrimes * for the new directory or adding the new node.
11701558Srgrimes */
11711558Srgrimesvoid
11729336Sdfradd_dlist(dpp, newdp, grp, flags)
11731558Srgrimes	struct dirlist **dpp;
11741558Srgrimes	struct dirlist *newdp;
11751558Srgrimes	struct grouplist *grp;
11769336Sdfr	int flags;
11771558Srgrimes{
11781558Srgrimes	struct dirlist *dp;
11791558Srgrimes	struct hostlist *hp;
11801558Srgrimes	int cmp;
11811558Srgrimes
11821558Srgrimes	dp = *dpp;
11831558Srgrimes	if (dp) {
11841558Srgrimes		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
11851558Srgrimes		if (cmp > 0) {
11869336Sdfr			add_dlist(&dp->dp_left, newdp, grp, flags);
11871558Srgrimes			return;
11881558Srgrimes		} else if (cmp < 0) {
11899336Sdfr			add_dlist(&dp->dp_right, newdp, grp, flags);
11901558Srgrimes			return;
11911558Srgrimes		} else
11921558Srgrimes			free((caddr_t)newdp);
11931558Srgrimes	} else {
11941558Srgrimes		dp = newdp;
11951558Srgrimes		dp->dp_left = (struct dirlist *)NULL;
11961558Srgrimes		*dpp = dp;
11971558Srgrimes	}
11981558Srgrimes	if (grp) {
11991558Srgrimes
12001558Srgrimes		/*
12011558Srgrimes		 * Hang all of the host(s) off of the directory point.
12021558Srgrimes		 */
12031558Srgrimes		do {
12041558Srgrimes			hp = get_ht();
12059336Sdfr			if (flags & OP_KERB)
12069336Sdfr				hp->ht_flag |= DP_KERB;
12071558Srgrimes			hp->ht_grp = grp;
12081558Srgrimes			hp->ht_next = dp->dp_hosts;
12091558Srgrimes			dp->dp_hosts = hp;
12101558Srgrimes			grp = grp->gr_next;
12111558Srgrimes		} while (grp);
12129336Sdfr	} else {
12131558Srgrimes		dp->dp_flag |= DP_DEFSET;
12149336Sdfr		if (flags & OP_KERB)
12159336Sdfr			dp->dp_flag |= DP_KERB;
12169336Sdfr	}
12171558Srgrimes}
12181558Srgrimes
12191558Srgrimes/*
12201558Srgrimes * Search for a dirpath on the export point.
12211558Srgrimes */
12221558Srgrimesstruct dirlist *
12231558Srgrimesdirp_search(dp, dirpath)
12241558Srgrimes	struct dirlist *dp;
12251558Srgrimes	char *dirpath;
12261558Srgrimes{
12271558Srgrimes	int cmp;
12281558Srgrimes
12291558Srgrimes	if (dp) {
12301558Srgrimes		cmp = strcmp(dp->dp_dirp, dirpath);
12311558Srgrimes		if (cmp > 0)
12321558Srgrimes			return (dirp_search(dp->dp_left, dirpath));
12331558Srgrimes		else if (cmp < 0)
12341558Srgrimes			return (dirp_search(dp->dp_right, dirpath));
12351558Srgrimes		else
12361558Srgrimes			return (dp);
12371558Srgrimes	}
12381558Srgrimes	return (dp);
12391558Srgrimes}
12401558Srgrimes
12411558Srgrimes/*
12421558Srgrimes * Scan for a host match in a directory tree.
12431558Srgrimes */
12441558Srgrimesint
12459336Sdfrchk_host(dp, saddr, defsetp, hostsetp)
12461558Srgrimes	struct dirlist *dp;
124742144Sdfr	u_int32_t saddr;
12481558Srgrimes	int *defsetp;
12499336Sdfr	int *hostsetp;
12501558Srgrimes{
12511558Srgrimes	struct hostlist *hp;
12521558Srgrimes	struct grouplist *grp;
125342144Sdfr	u_int32_t **addrp;
12541558Srgrimes
12551558Srgrimes	if (dp) {
12561558Srgrimes		if (dp->dp_flag & DP_DEFSET)
12579336Sdfr			*defsetp = dp->dp_flag;
12581558Srgrimes		hp = dp->dp_hosts;
12591558Srgrimes		while (hp) {
12601558Srgrimes			grp = hp->ht_grp;
12611558Srgrimes			switch (grp->gr_type) {
12621558Srgrimes			case GT_HOST:
126342144Sdfr			    addrp = (u_int32_t **)
12641558Srgrimes				grp->gr_ptr.gt_hostent->h_addr_list;
12651558Srgrimes			    while (*addrp) {
12669336Sdfr				if (**addrp == saddr) {
12679336Sdfr				    *hostsetp = (hp->ht_flag | DP_HOSTSET);
12681558Srgrimes				    return (1);
12699336Sdfr				}
12701558Srgrimes				addrp++;
12711558Srgrimes			    }
12721558Srgrimes			    break;
12731558Srgrimes			case GT_NET:
12741558Srgrimes			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
12759336Sdfr				grp->gr_ptr.gt_net.nt_net) {
12769336Sdfr				*hostsetp = (hp->ht_flag | DP_HOSTSET);
12771558Srgrimes				return (1);
12789336Sdfr			    }
12791558Srgrimes			    break;
12801558Srgrimes			};
12811558Srgrimes			hp = hp->ht_next;
12821558Srgrimes		}
12831558Srgrimes	}
12841558Srgrimes	return (0);
12851558Srgrimes}
12861558Srgrimes
12871558Srgrimes/*
12881558Srgrimes * Scan tree for a host that matches the address.
12891558Srgrimes */
12901558Srgrimesint
12911558Srgrimesscan_tree(dp, saddr)
12921558Srgrimes	struct dirlist *dp;
129342144Sdfr	u_int32_t saddr;
12941558Srgrimes{
12959336Sdfr	int defset, hostset;
12961558Srgrimes
12971558Srgrimes	if (dp) {
12981558Srgrimes		if (scan_tree(dp->dp_left, saddr))
12991558Srgrimes			return (1);
13009336Sdfr		if (chk_host(dp, saddr, &defset, &hostset))
13011558Srgrimes			return (1);
13021558Srgrimes		if (scan_tree(dp->dp_right, saddr))
13031558Srgrimes			return (1);
13041558Srgrimes	}
13051558Srgrimes	return (0);
13061558Srgrimes}
13071558Srgrimes
13081558Srgrimes/*
13091558Srgrimes * Traverse the dirlist tree and free it up.
13101558Srgrimes */
13111558Srgrimesvoid
13121558Srgrimesfree_dir(dp)
13131558Srgrimes	struct dirlist *dp;
13141558Srgrimes{
13151558Srgrimes
13161558Srgrimes	if (dp) {
13171558Srgrimes		free_dir(dp->dp_left);
13181558Srgrimes		free_dir(dp->dp_right);
13191558Srgrimes		free_host(dp->dp_hosts);
13201558Srgrimes		free((caddr_t)dp);
13211558Srgrimes	}
13221558Srgrimes}
13231558Srgrimes
13241558Srgrimes/*
13251558Srgrimes * Parse the option string and update fields.
13261558Srgrimes * Option arguments may either be -<option>=<value> or
13271558Srgrimes * -<option> <value>
13281558Srgrimes */
13291558Srgrimesint
13301558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
13311558Srgrimes	char **cpp, **endcpp;
13321558Srgrimes	struct exportlist *ep;
13331558Srgrimes	struct grouplist *grp;
13341558Srgrimes	int *has_hostp;
13351558Srgrimes	int *exflagsp;
133672650Sgreen	struct xucred *cr;
13371558Srgrimes{
13381558Srgrimes	char *cpoptarg, *cpoptend;
13391558Srgrimes	char *cp, *endcp, *cpopt, savedc, savedc2;
13401558Srgrimes	int allflag, usedarg;
13411558Srgrimes
134251968Salfred	savedc2 = '\0';
13431558Srgrimes	cpopt = *cpp;
13441558Srgrimes	cpopt++;
13451558Srgrimes	cp = *endcpp;
13461558Srgrimes	savedc = *cp;
13471558Srgrimes	*cp = '\0';
13481558Srgrimes	while (cpopt && *cpopt) {
13491558Srgrimes		allflag = 1;
13501558Srgrimes		usedarg = -2;
135137663Scharnier		if ((cpoptend = strchr(cpopt, ','))) {
13521558Srgrimes			*cpoptend++ = '\0';
135337663Scharnier			if ((cpoptarg = strchr(cpopt, '=')))
13541558Srgrimes				*cpoptarg++ = '\0';
13551558Srgrimes		} else {
135637663Scharnier			if ((cpoptarg = strchr(cpopt, '=')))
13571558Srgrimes				*cpoptarg++ = '\0';
13581558Srgrimes			else {
13591558Srgrimes				*cp = savedc;
13601558Srgrimes				nextfield(&cp, &endcp);
13611558Srgrimes				**endcpp = '\0';
13621558Srgrimes				if (endcp > cp && *cp != '-') {
13631558Srgrimes					cpoptarg = cp;
13641558Srgrimes					savedc2 = *endcp;
13651558Srgrimes					*endcp = '\0';
13661558Srgrimes					usedarg = 0;
13671558Srgrimes				}
13681558Srgrimes			}
13691558Srgrimes		}
13701558Srgrimes		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
13711558Srgrimes			*exflagsp |= MNT_EXRDONLY;
13721558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
13731558Srgrimes		    !(allflag = strcmp(cpopt, "mapall")) ||
13741558Srgrimes		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
13751558Srgrimes			usedarg++;
13761558Srgrimes			parsecred(cpoptarg, cr);
13771558Srgrimes			if (allflag == 0) {
13781558Srgrimes				*exflagsp |= MNT_EXPORTANON;
13791558Srgrimes				opt_flags |= OP_MAPALL;
13801558Srgrimes			} else
13811558Srgrimes				opt_flags |= OP_MAPROOT;
13821558Srgrimes		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
13831558Srgrimes			*exflagsp |= MNT_EXKERB;
13841558Srgrimes			opt_flags |= OP_KERB;
13851558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
13861558Srgrimes			!strcmp(cpopt, "m"))) {
13871558Srgrimes			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
138837663Scharnier				syslog(LOG_ERR, "bad mask: %s", cpoptarg);
13891558Srgrimes				return (1);
13901558Srgrimes			}
13911558Srgrimes			usedarg++;
13921558Srgrimes			opt_flags |= OP_MASK;
13931558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
13941558Srgrimes			!strcmp(cpopt, "n"))) {
13951558Srgrimes			if (grp->gr_type != GT_NULL) {
139637663Scharnier				syslog(LOG_ERR, "network/host conflict");
13971558Srgrimes				return (1);
13981558Srgrimes			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
139937663Scharnier				syslog(LOG_ERR, "bad net: %s", cpoptarg);
14001558Srgrimes				return (1);
14011558Srgrimes			}
14021558Srgrimes			grp->gr_type = GT_NET;
14031558Srgrimes			*has_hostp = 1;
14041558Srgrimes			usedarg++;
14051558Srgrimes			opt_flags |= OP_NET;
14061558Srgrimes		} else if (!strcmp(cpopt, "alldirs")) {
14071558Srgrimes			opt_flags |= OP_ALLDIRS;
140827447Sdfr		} else if (!strcmp(cpopt, "public")) {
140927447Sdfr			*exflagsp |= MNT_EXPUBLIC;
141027447Sdfr		} else if (!strcmp(cpopt, "webnfs")) {
141127447Sdfr			*exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
141227447Sdfr			opt_flags |= OP_MAPALL;
141327447Sdfr		} else if (cpoptarg && !strcmp(cpopt, "index")) {
141427447Sdfr			ep->ex_indexfile = strdup(cpoptarg);
14151558Srgrimes		} else {
141637663Scharnier			syslog(LOG_ERR, "bad opt %s", cpopt);
14171558Srgrimes			return (1);
14181558Srgrimes		}
14191558Srgrimes		if (usedarg >= 0) {
14201558Srgrimes			*endcp = savedc2;
14211558Srgrimes			**endcpp = savedc;
14221558Srgrimes			if (usedarg > 0) {
14231558Srgrimes				*cpp = cp;
14241558Srgrimes				*endcpp = endcp;
14251558Srgrimes			}
14261558Srgrimes			return (0);
14271558Srgrimes		}
14281558Srgrimes		cpopt = cpoptend;
14291558Srgrimes	}
14301558Srgrimes	**endcpp = savedc;
14311558Srgrimes	return (0);
14321558Srgrimes}
14331558Srgrimes
14341558Srgrimes/*
14351558Srgrimes * Translate a character string to the corresponding list of network
14361558Srgrimes * addresses for a hostname.
14371558Srgrimes */
14381558Srgrimesint
14397401Swpaulget_host(cp, grp, tgrp)
14401558Srgrimes	char *cp;
14411558Srgrimes	struct grouplist *grp;
14427401Swpaul	struct grouplist *tgrp;
14431558Srgrimes{
14447401Swpaul	struct grouplist *checkgrp;
14451558Srgrimes	struct hostent *hp, *nhp;
14461558Srgrimes	char **addrp, **naddrp;
14471558Srgrimes	struct hostent t_host;
14481558Srgrimes	int i;
144942144Sdfr	u_int32_t saddr;
14501558Srgrimes	char *aptr[2];
14511558Srgrimes
14521558Srgrimes	if (grp->gr_type != GT_NULL)
14531558Srgrimes		return (1);
14541558Srgrimes	if ((hp = gethostbyname(cp)) == NULL) {
14551558Srgrimes		if (isdigit(*cp)) {
14561558Srgrimes			saddr = inet_addr(cp);
14571558Srgrimes			if (saddr == -1) {
145837663Scharnier 				syslog(LOG_ERR, "inet_addr failed for %s", cp);
14591558Srgrimes				return (1);
14601558Srgrimes			}
14611558Srgrimes			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
14621558Srgrimes				AF_INET)) == NULL) {
14631558Srgrimes				hp = &t_host;
14641558Srgrimes				hp->h_name = cp;
14651558Srgrimes				hp->h_addrtype = AF_INET;
146642144Sdfr				hp->h_length = sizeof (u_int32_t);
14671558Srgrimes				hp->h_addr_list = aptr;
14681558Srgrimes				aptr[0] = (char *)&saddr;
14691558Srgrimes				aptr[1] = (char *)NULL;
14701558Srgrimes			}
14711558Srgrimes		} else {
147237663Scharnier 			syslog(LOG_ERR, "gethostbyname failed for %s", cp);
14731558Srgrimes			return (1);
14741558Srgrimes		}
14751558Srgrimes	}
14767401Swpaul        /*
14777401Swpaul         * Sanity check: make sure we don't already have an entry
14787401Swpaul         * for this host in the grouplist.
14797401Swpaul         */
14807401Swpaul        checkgrp = tgrp;
148137157Swpaul        while (checkgrp != NULL) {
148217887Swpaul		if (checkgrp->gr_type == GT_HOST &&
148317887Swpaul                    checkgrp->gr_ptr.gt_hostent != NULL &&
148437157Swpaul                    (!strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)
148542144Sdfr		|| *(u_int32_t *)checkgrp->gr_ptr.gt_hostent->h_addr ==
148642144Sdfr			*(u_int32_t *)hp->h_addr)) {
14877401Swpaul                        grp->gr_type = GT_IGNORE;
14887401Swpaul			return(0);
14897401Swpaul		}
14907401Swpaul                checkgrp = checkgrp->gr_next;
14917401Swpaul        }
14927401Swpaul
14931558Srgrimes	grp->gr_type = GT_HOST;
14941558Srgrimes	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
14951558Srgrimes		malloc(sizeof(struct hostent));
14961558Srgrimes	if (nhp == (struct hostent *)NULL)
14971558Srgrimes		out_of_mem();
149823681Speter	memmove(nhp, hp, sizeof(struct hostent));
14991558Srgrimes	i = strlen(hp->h_name)+1;
15001558Srgrimes	nhp->h_name = (char *)malloc(i);
15011558Srgrimes	if (nhp->h_name == (char *)NULL)
15021558Srgrimes		out_of_mem();
150323681Speter	memmove(nhp->h_name, hp->h_name, i);
15041558Srgrimes	addrp = hp->h_addr_list;
15051558Srgrimes	i = 1;
15061558Srgrimes	while (*addrp++)
15071558Srgrimes		i++;
150837663Scharnier	naddrp = nhp->h_addr_list = (char **)malloc(i*sizeof(char *));
15091558Srgrimes	if (naddrp == (char **)NULL)
15101558Srgrimes		out_of_mem();
15111558Srgrimes	addrp = hp->h_addr_list;
15121558Srgrimes	while (*addrp) {
151337663Scharnier		*naddrp = (char *)malloc(hp->h_length);
15141558Srgrimes		if (*naddrp == (char *)NULL)
15151558Srgrimes		    out_of_mem();
151623681Speter		memmove(*naddrp, *addrp, hp->h_length);
15171558Srgrimes		addrp++;
15181558Srgrimes		naddrp++;
15191558Srgrimes	}
15201558Srgrimes	*naddrp = (char *)NULL;
15211558Srgrimes	if (debug)
152237663Scharnier		warnx("got host %s", hp->h_name);
15231558Srgrimes	return (0);
15241558Srgrimes}
15251558Srgrimes
15261558Srgrimes/*
15271558Srgrimes * Free up an exports list component
15281558Srgrimes */
15291558Srgrimesvoid
15301558Srgrimesfree_exp(ep)
15311558Srgrimes	struct exportlist *ep;
15321558Srgrimes{
15331558Srgrimes
15341558Srgrimes	if (ep->ex_defdir) {
15351558Srgrimes		free_host(ep->ex_defdir->dp_hosts);
15361558Srgrimes		free((caddr_t)ep->ex_defdir);
15371558Srgrimes	}
15381558Srgrimes	if (ep->ex_fsdir)
15391558Srgrimes		free(ep->ex_fsdir);
154027447Sdfr	if (ep->ex_indexfile)
154127447Sdfr		free(ep->ex_indexfile);
15421558Srgrimes	free_dir(ep->ex_dirl);
15431558Srgrimes	free((caddr_t)ep);
15441558Srgrimes}
15451558Srgrimes
15461558Srgrimes/*
15471558Srgrimes * Free hosts.
15481558Srgrimes */
15491558Srgrimesvoid
15501558Srgrimesfree_host(hp)
15511558Srgrimes	struct hostlist *hp;
15521558Srgrimes{
15531558Srgrimes	struct hostlist *hp2;
15541558Srgrimes
15551558Srgrimes	while (hp) {
15561558Srgrimes		hp2 = hp;
15571558Srgrimes		hp = hp->ht_next;
15581558Srgrimes		free((caddr_t)hp2);
15591558Srgrimes	}
15601558Srgrimes}
15611558Srgrimes
15621558Srgrimesstruct hostlist *
15631558Srgrimesget_ht()
15641558Srgrimes{
15651558Srgrimes	struct hostlist *hp;
15661558Srgrimes
15671558Srgrimes	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
15681558Srgrimes	if (hp == (struct hostlist *)NULL)
15691558Srgrimes		out_of_mem();
15701558Srgrimes	hp->ht_next = (struct hostlist *)NULL;
15719336Sdfr	hp->ht_flag = 0;
15721558Srgrimes	return (hp);
15731558Srgrimes}
15741558Srgrimes
15751558Srgrimes/*
15761558Srgrimes * Out of memory, fatal
15771558Srgrimes */
15781558Srgrimesvoid
15791558Srgrimesout_of_mem()
15801558Srgrimes{
15811558Srgrimes
158237663Scharnier	syslog(LOG_ERR, "out of memory");
15831558Srgrimes	exit(2);
15841558Srgrimes}
15851558Srgrimes
15861558Srgrimes/*
15871558Srgrimes * Do the mount syscall with the update flag to push the export info into
15881558Srgrimes * the kernel.
15891558Srgrimes */
15901558Srgrimesint
15911558Srgrimesdo_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
15921558Srgrimes	struct exportlist *ep;
15931558Srgrimes	struct grouplist *grp;
15941558Srgrimes	int exflags;
159572650Sgreen	struct xucred *anoncrp;
15961558Srgrimes	char *dirp;
15971558Srgrimes	int dirplen;
15981558Srgrimes	struct statfs *fsb;
15991558Srgrimes{
16001558Srgrimes	char *cp = (char *)NULL;
160142144Sdfr	u_int32_t **addrp;
16021558Srgrimes	int done;
16031558Srgrimes	char savedc = '\0';
16041558Srgrimes	struct sockaddr_in sin, imask;
16051558Srgrimes	union {
16061558Srgrimes		struct ufs_args ua;
16071558Srgrimes		struct iso_args ia;
16081558Srgrimes		struct mfs_args ma;
16099336Sdfr#ifdef __NetBSD__
16109336Sdfr		struct msdosfs_args da;
16119336Sdfr#endif
161254093Ssemenu		struct ntfs_args na;
16131558Srgrimes	} args;
161442144Sdfr	u_int32_t net;
16151558Srgrimes
16161558Srgrimes	args.ua.fspec = 0;
16171558Srgrimes	args.ua.export.ex_flags = exflags;
16181558Srgrimes	args.ua.export.ex_anon = *anoncrp;
161927447Sdfr	args.ua.export.ex_indexfile = ep->ex_indexfile;
162023681Speter	memset(&sin, 0, sizeof(sin));
162123681Speter	memset(&imask, 0, sizeof(imask));
16221558Srgrimes	sin.sin_family = AF_INET;
16231558Srgrimes	sin.sin_len = sizeof(sin);
16241558Srgrimes	imask.sin_family = AF_INET;
16251558Srgrimes	imask.sin_len = sizeof(sin);
16261558Srgrimes	if (grp->gr_type == GT_HOST)
162742144Sdfr		addrp = (u_int32_t **)grp->gr_ptr.gt_hostent->h_addr_list;
16281558Srgrimes	else
162942144Sdfr		addrp = (u_int32_t **)NULL;
16301558Srgrimes	done = FALSE;
16311558Srgrimes	while (!done) {
16321558Srgrimes		switch (grp->gr_type) {
16331558Srgrimes		case GT_HOST:
16341558Srgrimes			if (addrp) {
16351558Srgrimes				sin.sin_addr.s_addr = **addrp;
16361558Srgrimes				args.ua.export.ex_addrlen = sizeof(sin);
16371558Srgrimes			} else
16381558Srgrimes				args.ua.export.ex_addrlen = 0;
16391558Srgrimes			args.ua.export.ex_addr = (struct sockaddr *)&sin;
16401558Srgrimes			args.ua.export.ex_masklen = 0;
16411558Srgrimes			break;
16421558Srgrimes		case GT_NET:
16431558Srgrimes			if (grp->gr_ptr.gt_net.nt_mask)
16441558Srgrimes			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
16451558Srgrimes			else {
16461558Srgrimes			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
16471558Srgrimes			    if (IN_CLASSA(net))
16481558Srgrimes				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
16491558Srgrimes			    else if (IN_CLASSB(net))
16501558Srgrimes				imask.sin_addr.s_addr =
16511558Srgrimes				    inet_addr("255.255.0.0");
16521558Srgrimes			    else
16531558Srgrimes				imask.sin_addr.s_addr =
16541558Srgrimes				    inet_addr("255.255.255.0");
16551558Srgrimes			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
16561558Srgrimes			}
16571558Srgrimes			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
16581558Srgrimes			args.ua.export.ex_addr = (struct sockaddr *)&sin;
16591558Srgrimes			args.ua.export.ex_addrlen = sizeof (sin);
16601558Srgrimes			args.ua.export.ex_mask = (struct sockaddr *)&imask;
16611558Srgrimes			args.ua.export.ex_masklen = sizeof (imask);
16621558Srgrimes			break;
16637401Swpaul		case GT_IGNORE:
16647401Swpaul			return(0);
16657401Swpaul			break;
16661558Srgrimes		default:
166737663Scharnier			syslog(LOG_ERR, "bad grouptype");
16681558Srgrimes			if (cp)
16691558Srgrimes				*cp = savedc;
16701558Srgrimes			return (1);
16711558Srgrimes		};
16721558Srgrimes
16731558Srgrimes		/*
16741558Srgrimes		 * XXX:
16751558Srgrimes		 * Maybe I should just use the fsb->f_mntonname path instead
16761558Srgrimes		 * of looping back up the dirp to the mount point??
16771558Srgrimes		 * Also, needs to know how to export all types of local
167823681Speter		 * exportable file systems and not just "ufs".
16791558Srgrimes		 */
16809336Sdfr		while (mount(fsb->f_fstypename, dirp,
16811558Srgrimes		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
16821558Srgrimes			if (cp)
16831558Srgrimes				*cp-- = savedc;
16841558Srgrimes			else
16851558Srgrimes				cp = dirp + dirplen - 1;
16861558Srgrimes			if (errno == EPERM) {
16871558Srgrimes				syslog(LOG_ERR,
168837663Scharnier				   "can't change attributes for %s", dirp);
16891558Srgrimes				return (1);
16901558Srgrimes			}
16911558Srgrimes			if (opt_flags & OP_ALLDIRS) {
169237663Scharnier				syslog(LOG_ERR, "could not remount %s: %m",
16934895Swollman					dirp);
16941558Srgrimes				return (1);
16951558Srgrimes			}
16961558Srgrimes			/* back up over the last component */
16971558Srgrimes			while (*cp == '/' && cp > dirp)
16981558Srgrimes				cp--;
16991558Srgrimes			while (*(cp - 1) != '/' && cp > dirp)
17001558Srgrimes				cp--;
17011558Srgrimes			if (cp == dirp) {
17021558Srgrimes				if (debug)
170337663Scharnier					warnx("mnt unsucc");
170437663Scharnier				syslog(LOG_ERR, "can't export %s", dirp);
17051558Srgrimes				return (1);
17061558Srgrimes			}
17071558Srgrimes			savedc = *cp;
17081558Srgrimes			*cp = '\0';
17091558Srgrimes		}
17101558Srgrimes		if (addrp) {
17111558Srgrimes			++addrp;
171242144Sdfr			if (*addrp == (u_int32_t *)NULL)
17131558Srgrimes				done = TRUE;
17141558Srgrimes		} else
17151558Srgrimes			done = TRUE;
17161558Srgrimes	}
17171558Srgrimes	if (cp)
17181558Srgrimes		*cp = savedc;
17191558Srgrimes	return (0);
17201558Srgrimes}
17211558Srgrimes
17221558Srgrimes/*
17231558Srgrimes * Translate a net address.
17241558Srgrimes */
17251558Srgrimesint
17261558Srgrimesget_net(cp, net, maskflg)
17271558Srgrimes	char *cp;
17281558Srgrimes	struct netmsk *net;
17291558Srgrimes	int maskflg;
17301558Srgrimes{
17311558Srgrimes	struct netent *np;
17321558Srgrimes	long netaddr;
17331558Srgrimes	struct in_addr inetaddr, inetaddr2;
17341558Srgrimes	char *name;
17351558Srgrimes
173625318Spst	if (isdigit(*cp) && ((netaddr = inet_network(cp)) != -1)) {
17371558Srgrimes		inetaddr = inet_makeaddr(netaddr, 0);
17381558Srgrimes		/*
173937663Scharnier		 * Due to arbitrary subnet masks, you don't know how many
17401558Srgrimes		 * bits to shift the address to make it into a network,
17411558Srgrimes		 * however you do know how to make a network address into
17421558Srgrimes		 * a host with host == 0 and then compare them.
17431558Srgrimes		 * (What a pest)
17441558Srgrimes		 */
17451558Srgrimes		if (!maskflg) {
17461558Srgrimes			setnetent(0);
174737663Scharnier			while ((np = getnetent())) {
17481558Srgrimes				inetaddr2 = inet_makeaddr(np->n_net, 0);
17491558Srgrimes				if (inetaddr2.s_addr == inetaddr.s_addr)
17501558Srgrimes					break;
17511558Srgrimes			}
17521558Srgrimes			endnetent();
17531558Srgrimes		}
175425318Spst	} else if ((np = getnetbyname(cp)) != NULL) {
175525318Spst		inetaddr = inet_makeaddr(np->n_net, 0);
17561558Srgrimes	} else
17571558Srgrimes		return (1);
175825318Spst
17591558Srgrimes	if (maskflg)
17601558Srgrimes		net->nt_mask = inetaddr.s_addr;
17611558Srgrimes	else {
17621558Srgrimes		if (np)
17631558Srgrimes			name = np->n_name;
17641558Srgrimes		else
17651558Srgrimes			name = inet_ntoa(inetaddr);
17661558Srgrimes		net->nt_name = (char *)malloc(strlen(name) + 1);
17671558Srgrimes		if (net->nt_name == (char *)NULL)
17681558Srgrimes			out_of_mem();
17691558Srgrimes		strcpy(net->nt_name, name);
17701558Srgrimes		net->nt_net = inetaddr.s_addr;
17711558Srgrimes	}
17721558Srgrimes	return (0);
17731558Srgrimes}
17741558Srgrimes
17751558Srgrimes/*
17761558Srgrimes * Parse out the next white space separated field
17771558Srgrimes */
17781558Srgrimesvoid
17791558Srgrimesnextfield(cp, endcp)
17801558Srgrimes	char **cp;
17811558Srgrimes	char **endcp;
17821558Srgrimes{
17831558Srgrimes	char *p;
17841558Srgrimes
17851558Srgrimes	p = *cp;
17861558Srgrimes	while (*p == ' ' || *p == '\t')
17871558Srgrimes		p++;
17881558Srgrimes	if (*p == '\n' || *p == '\0')
17891558Srgrimes		*cp = *endcp = p;
17901558Srgrimes	else {
17911558Srgrimes		*cp = p++;
17921558Srgrimes		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
17931558Srgrimes			p++;
17941558Srgrimes		*endcp = p;
17951558Srgrimes	}
17961558Srgrimes}
17971558Srgrimes
17981558Srgrimes/*
17991558Srgrimes * Get an exports file line. Skip over blank lines and handle line
18001558Srgrimes * continuations.
18011558Srgrimes */
18021558Srgrimesint
18031558Srgrimesget_line()
18041558Srgrimes{
18051558Srgrimes	char *p, *cp;
18061558Srgrimes	int len;
18071558Srgrimes	int totlen, cont_line;
18081558Srgrimes
18091558Srgrimes	/*
18101558Srgrimes	 * Loop around ignoring blank lines and getting all continuation lines.
18111558Srgrimes	 */
18121558Srgrimes	p = line;
18131558Srgrimes	totlen = 0;
18141558Srgrimes	do {
18151558Srgrimes		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
18161558Srgrimes			return (0);
18171558Srgrimes		len = strlen(p);
18181558Srgrimes		cp = p + len - 1;
18191558Srgrimes		cont_line = 0;
18201558Srgrimes		while (cp >= p &&
18211558Srgrimes		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
18221558Srgrimes			if (*cp == '\\')
18231558Srgrimes				cont_line = 1;
18241558Srgrimes			cp--;
18251558Srgrimes			len--;
18261558Srgrimes		}
18271558Srgrimes		*++cp = '\0';
18281558Srgrimes		if (len > 0) {
18291558Srgrimes			totlen += len;
18301558Srgrimes			if (totlen >= LINESIZ) {
183137663Scharnier				syslog(LOG_ERR, "exports line too long");
18321558Srgrimes				exit(2);
18331558Srgrimes			}
18341558Srgrimes			p = cp;
18351558Srgrimes		}
18361558Srgrimes	} while (totlen == 0 || cont_line);
18371558Srgrimes	return (1);
18381558Srgrimes}
18391558Srgrimes
18401558Srgrimes/*
18411558Srgrimes * Parse a description of a credential.
18421558Srgrimes */
18431558Srgrimesvoid
18441558Srgrimesparsecred(namelist, cr)
18451558Srgrimes	char *namelist;
184672650Sgreen	struct xucred *cr;
18471558Srgrimes{
18481558Srgrimes	char *name;
18491558Srgrimes	int cnt;
18501558Srgrimes	char *names;
18511558Srgrimes	struct passwd *pw;
18521558Srgrimes	struct group *gr;
18531558Srgrimes	int ngroups, groups[NGROUPS + 1];
18541558Srgrimes
18551558Srgrimes	/*
185637663Scharnier	 * Set up the unprivileged user.
18571558Srgrimes	 */
18581558Srgrimes	cr->cr_uid = -2;
18591558Srgrimes	cr->cr_groups[0] = -2;
18601558Srgrimes	cr->cr_ngroups = 1;
18611558Srgrimes	/*
18621558Srgrimes	 * Get the user's password table entry.
18631558Srgrimes	 */
18641558Srgrimes	names = strsep(&namelist, " \t\n");
18651558Srgrimes	name = strsep(&names, ":");
18661558Srgrimes	if (isdigit(*name) || *name == '-')
18671558Srgrimes		pw = getpwuid(atoi(name));
18681558Srgrimes	else
18691558Srgrimes		pw = getpwnam(name);
18701558Srgrimes	/*
18711558Srgrimes	 * Credentials specified as those of a user.
18721558Srgrimes	 */
18731558Srgrimes	if (names == NULL) {
18741558Srgrimes		if (pw == NULL) {
187537663Scharnier			syslog(LOG_ERR, "unknown user: %s", name);
18761558Srgrimes			return;
18771558Srgrimes		}
18781558Srgrimes		cr->cr_uid = pw->pw_uid;
18791558Srgrimes		ngroups = NGROUPS + 1;
18801558Srgrimes		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
188137663Scharnier			syslog(LOG_ERR, "too many groups");
18821558Srgrimes		/*
18831558Srgrimes		 * Convert from int's to gid_t's and compress out duplicate
18841558Srgrimes		 */
18851558Srgrimes		cr->cr_ngroups = ngroups - 1;
18861558Srgrimes		cr->cr_groups[0] = groups[0];
18871558Srgrimes		for (cnt = 2; cnt < ngroups; cnt++)
18881558Srgrimes			cr->cr_groups[cnt - 1] = groups[cnt];
18891558Srgrimes		return;
18901558Srgrimes	}
18911558Srgrimes	/*
18921558Srgrimes	 * Explicit credential specified as a colon separated list:
18931558Srgrimes	 *	uid:gid:gid:...
18941558Srgrimes	 */
18951558Srgrimes	if (pw != NULL)
18961558Srgrimes		cr->cr_uid = pw->pw_uid;
18971558Srgrimes	else if (isdigit(*name) || *name == '-')
18981558Srgrimes		cr->cr_uid = atoi(name);
18991558Srgrimes	else {
190037663Scharnier		syslog(LOG_ERR, "unknown user: %s", name);
19011558Srgrimes		return;
19021558Srgrimes	}
19031558Srgrimes	cr->cr_ngroups = 0;
19041558Srgrimes	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
19051558Srgrimes		name = strsep(&names, ":");
19061558Srgrimes		if (isdigit(*name) || *name == '-') {
19071558Srgrimes			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
19081558Srgrimes		} else {
19091558Srgrimes			if ((gr = getgrnam(name)) == NULL) {
191037663Scharnier				syslog(LOG_ERR, "unknown group: %s", name);
19111558Srgrimes				continue;
19121558Srgrimes			}
19131558Srgrimes			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
19141558Srgrimes		}
19151558Srgrimes	}
19161558Srgrimes	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
191737663Scharnier		syslog(LOG_ERR, "too many groups");
19181558Srgrimes}
19191558Srgrimes
19201558Srgrimes#define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
19211558Srgrimes/*
19221558Srgrimes * Routines that maintain the remote mounttab
19231558Srgrimes */
19241558Srgrimesvoid
19251558Srgrimesget_mountlist()
19261558Srgrimes{
19271558Srgrimes	struct mountlist *mlp, **mlpp;
192823681Speter	char *host, *dirp, *cp;
19291558Srgrimes	char str[STRSIZ];
19301558Srgrimes	FILE *mlfile;
19311558Srgrimes
19321558Srgrimes	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
193353117Sbillf		if (errno == ENOENT)
193453117Sbillf			return;
193553117Sbillf		else {
193653117Sbillf			syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
193753117Sbillf			return;
193853117Sbillf		}
19391558Srgrimes	}
19401558Srgrimes	mlpp = &mlhead;
19411558Srgrimes	while (fgets(str, STRSIZ, mlfile) != NULL) {
194223681Speter		cp = str;
194323681Speter		host = strsep(&cp, " \t\n");
194423681Speter		dirp = strsep(&cp, " \t\n");
194523681Speter		if (host == NULL || dirp == NULL)
19461558Srgrimes			continue;
19471558Srgrimes		mlp = (struct mountlist *)malloc(sizeof (*mlp));
194837663Scharnier		if (mlp == (struct mountlist *)NULL)
194937663Scharnier			out_of_mem();
195023681Speter		strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
195123681Speter		mlp->ml_host[RPCMNT_NAMELEN] = '\0';
195223681Speter		strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
195323681Speter		mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
19541558Srgrimes		mlp->ml_next = (struct mountlist *)NULL;
19551558Srgrimes		*mlpp = mlp;
19561558Srgrimes		mlpp = &mlp->ml_next;
19571558Srgrimes	}
19581558Srgrimes	fclose(mlfile);
19591558Srgrimes}
19601558Srgrimes
19611558Srgrimesvoid
19621558Srgrimesdel_mlist(hostp, dirp)
19631558Srgrimes	char *hostp, *dirp;
19641558Srgrimes{
19651558Srgrimes	struct mountlist *mlp, **mlpp;
19661558Srgrimes	struct mountlist *mlp2;
19671558Srgrimes	FILE *mlfile;
19681558Srgrimes	int fnd = 0;
19691558Srgrimes
19701558Srgrimes	mlpp = &mlhead;
19711558Srgrimes	mlp = mlhead;
19721558Srgrimes	while (mlp) {
19731558Srgrimes		if (!strcmp(mlp->ml_host, hostp) &&
19741558Srgrimes		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
19751558Srgrimes			fnd = 1;
19761558Srgrimes			mlp2 = mlp;
19771558Srgrimes			*mlpp = mlp = mlp->ml_next;
19781558Srgrimes			free((caddr_t)mlp2);
19791558Srgrimes		} else {
19801558Srgrimes			mlpp = &mlp->ml_next;
19811558Srgrimes			mlp = mlp->ml_next;
19821558Srgrimes		}
19831558Srgrimes	}
19841558Srgrimes	if (fnd) {
19851558Srgrimes		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
198637663Scharnier			syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
19871558Srgrimes			return;
19881558Srgrimes		}
19891558Srgrimes		mlp = mlhead;
19901558Srgrimes		while (mlp) {
19911558Srgrimes			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
19921558Srgrimes			mlp = mlp->ml_next;
19931558Srgrimes		}
19941558Srgrimes		fclose(mlfile);
19951558Srgrimes	}
19961558Srgrimes}
19971558Srgrimes
19981558Srgrimesvoid
19991558Srgrimesadd_mlist(hostp, dirp)
20001558Srgrimes	char *hostp, *dirp;
20011558Srgrimes{
20021558Srgrimes	struct mountlist *mlp, **mlpp;
20031558Srgrimes	FILE *mlfile;
20041558Srgrimes
20051558Srgrimes	mlpp = &mlhead;
20061558Srgrimes	mlp = mlhead;
20071558Srgrimes	while (mlp) {
20081558Srgrimes		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
20091558Srgrimes			return;
20101558Srgrimes		mlpp = &mlp->ml_next;
20111558Srgrimes		mlp = mlp->ml_next;
20121558Srgrimes	}
20131558Srgrimes	mlp = (struct mountlist *)malloc(sizeof (*mlp));
201437663Scharnier	if (mlp == (struct mountlist *)NULL)
201537663Scharnier		out_of_mem();
20161558Srgrimes	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
20171558Srgrimes	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
20181558Srgrimes	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
20191558Srgrimes	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
20201558Srgrimes	mlp->ml_next = (struct mountlist *)NULL;
20211558Srgrimes	*mlpp = mlp;
20221558Srgrimes	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
202337663Scharnier		syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
20241558Srgrimes		return;
20251558Srgrimes	}
20261558Srgrimes	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
20271558Srgrimes	fclose(mlfile);
20281558Srgrimes}
20291558Srgrimes
20301558Srgrimes/*
20311558Srgrimes * Free up a group list.
20321558Srgrimes */
20331558Srgrimesvoid
20341558Srgrimesfree_grp(grp)
20351558Srgrimes	struct grouplist *grp;
20361558Srgrimes{
20371558Srgrimes	char **addrp;
20381558Srgrimes
20391558Srgrimes	if (grp->gr_type == GT_HOST) {
20401558Srgrimes		if (grp->gr_ptr.gt_hostent->h_name) {
20411558Srgrimes			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
20421558Srgrimes			while (addrp && *addrp)
20431558Srgrimes				free(*addrp++);
20441558Srgrimes			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
20451558Srgrimes			free(grp->gr_ptr.gt_hostent->h_name);
20461558Srgrimes		}
20471558Srgrimes		free((caddr_t)grp->gr_ptr.gt_hostent);
20481558Srgrimes	} else if (grp->gr_type == GT_NET) {
20491558Srgrimes		if (grp->gr_ptr.gt_net.nt_name)
20501558Srgrimes			free(grp->gr_ptr.gt_net.nt_name);
20511558Srgrimes	}
20521558Srgrimes	free((caddr_t)grp);
20531558Srgrimes}
20541558Srgrimes
20551558Srgrimes#ifdef DEBUG
20561558Srgrimesvoid
20571558SrgrimesSYSLOG(int pri, const char *fmt, ...)
20581558Srgrimes{
20591558Srgrimes	va_list ap;
20601558Srgrimes
20611558Srgrimes	va_start(ap, fmt);
20621558Srgrimes	vfprintf(stderr, fmt, ap);
20631558Srgrimes	va_end(ap);
20641558Srgrimes}
20651558Srgrimes#endif /* DEBUG */
20661558Srgrimes
20671558Srgrimes/*
20681558Srgrimes * Check options for consistency.
20691558Srgrimes */
20701558Srgrimesint
20711558Srgrimescheck_options(dp)
20721558Srgrimes	struct dirlist *dp;
20731558Srgrimes{
20741558Srgrimes
20751558Srgrimes	if (dp == (struct dirlist *)NULL)
20761558Srgrimes	    return (1);
20771558Srgrimes	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
20781558Srgrimes	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
20791558Srgrimes	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
20801558Srgrimes	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
20811558Srgrimes	    return (1);
20821558Srgrimes	}
20831558Srgrimes	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
20841558Srgrimes	    syslog(LOG_ERR, "-mask requires -net");
20851558Srgrimes	    return (1);
20861558Srgrimes	}
20871558Srgrimes	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
208845927Salex	    syslog(LOG_ERR, "-alldirs has multiple directories");
20891558Srgrimes	    return (1);
20901558Srgrimes	}
20911558Srgrimes	return (0);
20921558Srgrimes}
20931558Srgrimes
20941558Srgrimes/*
20951558Srgrimes * Check an absolute directory path for any symbolic links. Return true
20961558Srgrimes * if no symbolic links are found.
20971558Srgrimes */
20981558Srgrimesint
20991558Srgrimescheck_dirpath(dirp)
21001558Srgrimes	char *dirp;
21011558Srgrimes{
21021558Srgrimes	char *cp;
21031558Srgrimes	int ret = 1;
21041558Srgrimes	struct stat sb;
21051558Srgrimes
21061558Srgrimes	cp = dirp + 1;
21071558Srgrimes	while (*cp && ret) {
21081558Srgrimes		if (*cp == '/') {
21091558Srgrimes			*cp = '\0';
21109336Sdfr			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
21111558Srgrimes				ret = 0;
21121558Srgrimes			*cp = '/';
21131558Srgrimes		}
21141558Srgrimes		cp++;
21151558Srgrimes	}
21169336Sdfr	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
21171558Srgrimes		ret = 0;
21181558Srgrimes	return (ret);
21191558Srgrimes}
21209336Sdfr
21219336Sdfr/*
21229336Sdfr * Just translate an ascii string to an integer.
21239336Sdfr */
21249336Sdfrint
21259336Sdfrget_num(cp)
21269336Sdfr	register char *cp;
21279336Sdfr{
21289336Sdfr	register int res = 0;
21299336Sdfr
21309336Sdfr	while (*cp) {
21319336Sdfr		if (*cp < '0' || *cp > '9')
21329336Sdfr			return (-1);
21339336Sdfr		res = res * 10 + (*cp++ - '0');
21349336Sdfr	}
21359336Sdfr	return (res);
21369336Sdfr}
2137