has_host = FALSE;
grp->gr_type = GT_IGNORE;
struct hostlist *get_ht __P((void));int	get_line __P((void));void	get_mountlist __P((void));int	get_net __P((char *, struct netmsk *, int));void	getexp_err __P((struct exportlist *, struct grouplist *));struct grouplist *get_grp __P((void));void	hang_dirp __P((struct dirlist *, struct grouplist *,	    struct exportlist *, int));void	mntsrv __P((struct svc_req *, SVCXPRT *));void	nextfield __P((char **, char **));void	out_of_mem __P((void));void	parsecred __P((char *, struct ucred *));int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));int	scan_tree __P((struct dirlist *, in_addr_t));void	send_umntall __P((void));int	umntall_each __P((caddr_t, struct sockaddr_in *));int	xdr_dir __P((XDR *, char *));int	xdr_explist __P((XDR *, caddr_t));int	xdr_fhs __P((XDR *, caddr_t));int	xdr_mlist __P((XDR *, caddr_t));struct exportlist *exphead;struct mountlist *mlhead;struct grouplist *grphead;char exname[MAXPATHLEN];struct ucred def_anon = {	1,	(uid_t) -2,	(gid_t) -2,	0,	{ }};int resvport_only = 1;int opt_flags;/* Bits for above */#define	OP_MAPROOT	0x01#define	OP_MAPALL	0x02#define	OP_KERB		0x04#define	OP_MASK		0x08#define	OP_NET		0x10#define	OP_ALLDIRS	0x40int debug = 0;/* * Mountd server for NFS mount protocol as described in: * NFS: Network File System Protocol Specification, RFC1094, Appendix A * The optional arguments are the exports file name * default: _PATH_EXPORTS * "-d" to enable debugging * and "-n" to allow nonroot mount. */intmain(argc, argv)	int argc;	char **argv;{	SVCXPRT *udptransp, *tcptransp;	FILE *pidfile;	int c;	while ((c = getopt(argc, argv, "dnr")) != -1)		switch (c) {		case 'd':			debug = 1;			break;		case 'n':			resvport_only = 0;			break;		case 'r':			/* Compatibility */			break;		default:			fprintf(stderr, "Usage: mountd [-dn] [export_file]\n");			exit(1);		};	argc -= optind;	argv += optind;	grphead = NULL;	exphead = NULL;	mlhead = NULL;	if (argc == 1)		strncpy(exname, *argv, sizeof(exname)-1);	else		strncpy(exname, _PATH_EXPORTS, sizeof exname-1);	exname[sizeof(exname)-1] = '\0';	openlog("mountd", LOG_PID, LOG_DAEMON);	if (debug)		fprintf(stderr, "Getting export list.\n");	get_exportlist();	if (debug)		fprintf(stderr, "Getting mount list.\n");	get_mountlist();	if (debug)		fprintf(stderr, "Here we go.\n");	if (debug == 0) {		daemon(0, 0);		signal(SIGINT, SIG_IGN);		signal(SIGQUIT, SIG_IGN);	}	/* Store pid in file unless mountd is already running */	pidfile = fopen(_PATH_MOUNTDPID, "r");	if (pidfile != NULL) {		if (fscanf(pidfile, "%d\n", &c) > 0 && c > 0) {			if (kill(c, 0) == 0) {				syslog(LOG_ERR, "Already running (pid %d)", c);				exit(1);			}		}		pidfile = freopen(_PATH_MOUNTDPID, "w", pidfile);	} else {		pidfile = fopen(_PATH_MOUNTDPID, "w");	}	fprintf(pidfile, "%d\n", getpid());	fclose(pidfile);	signal(SIGHUP, (void (*) __P((int))) new_exportlist);	signal(SIGTERM, (void (*) __P((int))) send_umntall);	signal(SIGSYS, SIG_IGN);	if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||	    (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {		syslog(LOG_ERR, "Can't create socket");		exit(1);	}	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);	pmap_unset(RPCPROG_MNT, RPCMNT_VER3);	if (!svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP) ||	    !svc_register(udptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_UDP) ||	    !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_TCP) ||	    !svc_register(tcptransp, RPCPROG_MNT, RPCMNT_VER3, mntsrv, IPPROTO_TCP)) {		syslog(LOG_ERR, "Can't register mount");		exit(1);	}	svc_run();	syslog(LOG_ERR, "Mountd died");	exit(1);}/* * The mount rpc service */voidmntsrv(rqstp, transp)	struct svc_req *rqstp;	SVCXPRT *transp;{	struct exportlist *ep;	struct dirlist *dp;	struct fhreturn fhr;	struct stat stb;	struct statfs fsb;	struct hostent *hp;	in_addr_t saddr;	u_short sport;	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];	long bad = 0;	int defset, hostset;	sigset_t sighup_mask;	sigemptyset(&sighup_mask);	sigaddset(&sighup_mask, SIGHUP);	saddr = transp->xp_raddr.sin_addr.s_addr;	sport = ntohs(transp->xp_raddr.sin_port);	hp = NULL;	switch (rqstp->rq_proc) {	case NULLPROC:		if (!svc_sendreply(transp, xdr_void, NULL))			syslog(LOG_ERR, "Can't send reply");		return;	case RPCMNT_MOUNT:		if (sport >= IPPORT_RESERVED && resvport_only) {			svcerr_weakauth(transp);			return;		}		if (!svc_getargs(transp, xdr_dir, rpcpath)) {			svcerr_decode(transp);			return;		}		/*		 * Get the real pathname and make sure it is a file or		 * directory that exists.		 */		if (realpath(rpcpath, dirpath) == 0 ||		    stat(dirpath, &stb) < 0 ||		    (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) ||		    statfs(dirpath, &fsb) < 0) {			chdir("/");	/* Just in case realpath doesn't */			if (debug)				fprintf(stderr, "stat failed on %s\n", dirpath);			bad = ENOENT;	/* We will send error reply later */		}		/* Check in the exports list */		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);		ep = ex_search(&fsb.f_fsid);		hostset = defset = 0;		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&		    chk_host(dp, saddr, &defset, &hostset)) ||		    (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&		    scan_tree(ep->ex_dirl, saddr) == 0))) {			if (bad) {				if (!svc_sendreply(transp, xdr_long,				    (caddr_t)&bad))					syslog(LOG_ERR, "Can't send reply");				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);				return;			}			if (hostset & DP_HOSTSET)				fhr.fhr_flag = hostset;			else				fhr.fhr_flag = defset;			fhr.fhr_vers = rqstp->rq_vers;			/* Get the file handle */			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {				if (errno == ENOSYS) {					syslog(LOG_ERR,					    "Kernel does not support NFS exporting, "					    "mountd aborting..");					_exit(1);				}				bad = errno;				syslog(LOG_ERR, "Can't get fh for %s", dirpath);				if (!svc_sendreply(transp, xdr_long,				    (caddr_t)&bad))					syslog(LOG_ERR, "Can't send reply");				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);				return;			}			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))				syslog(LOG_ERR, "Can't send reply");			if (hp == NULL)				hp = gethostbyaddr((caddr_t)&saddr,				    sizeof(saddr), AF_INET);			if (hp)				add_mlist(hp->h_name, dirpath);			else				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),					dirpath);			if (debug)				fprintf(stderr, "Mount successful.\n");		} else			bad = EACCES;		if (bad && !svc_sendreply(transp, xdr_long, (caddr_t)&bad))			syslog(LOG_ERR, "Can't send reply");		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);		return;	case RPCMNT_DUMP:		if (!svc_sendreply(transp, xdr_mlist, NULL))			syslog(LOG_ERR, "Can't send reply");		return;	case RPCMNT_UMOUNT:		if (sport >= IPPORT_RESERVED && resvport_only) {			svcerr_weakauth(transp);			return;		}		if (!svc_getargs(transp, xdr_dir, dirpath)) {			svcerr_decode(transp);			return;		}		if (!svc_sendreply(transp, xdr_void, NULL))			syslog(LOG_ERR, "Can't send reply");		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);		if (hp)			del_mlist(hp->h_name, dirpath);		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);		return;	case RPCMNT_UMNTALL:		if (sport >= IPPORT_RESERVED && resvport_only) {			svcerr_weakauth(transp);			return;		}		if (!svc_sendreply(transp, xdr_void, NULL))			syslog(LOG_ERR, "Can't send reply");		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);		if (hp)			del_mlist(hp->h_name, NULL);		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), NULL);		return;	case RPCMNT_EXPORT:		if (!svc_sendreply(transp, xdr_explist, NULL))			syslog(LOG_ERR, "Can't send reply");		return;	default:		svcerr_noproc(transp);		return;	}}/* * Xdr conversion for a dirpath string */intxdr_dir(xdrsp, dirp)	XDR *xdrsp;	char *dirp;{	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));}/* * Xdr routine to generate file handle reply */intxdr_fhs(xdrsp, cp)	XDR *xdrsp;	caddr_t cp;{	register struct fhreturn *fhrp = (struct fhreturn *)cp;	long ok = 0, len, auth;	if (!xdr_long(xdrsp, &ok))		return (0);	switch (fhrp->fhr_vers) {	case 1:		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));	case 3:		len = NFSX_V3FH;		if (!xdr_long(xdrsp, &len))			return (0);		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))			return (0);		if (fhrp->fhr_flag & DP_KERB)			auth = RPCAUTH_KERB4;		else			auth = RPCAUTH_UNIX;		len = 1;		if (!xdr_long(xdrsp, &len))			return (0);		return (xdr_long(xdrsp, &auth));	};	return (0);}intxdr_mlist(xdrsp, cp)	XDR *xdrsp;	caddr_t cp;{	struct mountlist *mlp;	int true = 1;	int false = 0;	char *strp;	mlp = mlhead;	while (mlp) {		if (!xdr_bool(xdrsp, &true))			return (0);		strp = &mlp->ml_host[0];		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))			return (0);		strp = &mlp->ml_dirp[0];		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))			return (0);		mlp = mlp->ml_next;	}	if (!xdr_bool(xdrsp, &false))		return (0);	return (1);}/* * Xdr conversion for export list */intxdr_explist(xdrsp, cp)	XDR *xdrsp;	caddr_t cp;{	struct exportlist *ep;	int false = 0;	int putdef;	sigset_t sighup_mask;	sigemptyset(&sighup_mask);	sigaddset(&sighup_mask, SIGHUP);	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);	ep = exphead;	while (ep) {		putdef = 0;		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))			goto errout;		if (ep->ex_defdir && putdef == 0 && put_exlist(ep->ex_defdir,		    xdrsp, NULL, &putdef))			goto errout;		ep = ep->ex_next;	}	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);	if (!xdr_bool(xdrsp, &false))		return (0);	return (1);errout:	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);	return (0);}/* * Called from xdr_explist() to traverse the tree and export the * directory paths. */intput_exlist(dp, xdrsp, adp, putdefp)	struct dirlist *dp;	XDR *xdrsp;	struct dirlist *adp;	int *putdefp;{	struct grouplist *grp;	struct hostlist *hp;	int true = 1;	int false = 0;	int gotalldir = 0;	char *strp;	if (dp) {		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))			return (1);		if (!xdr_bool(xdrsp, &true))			return (1);		strp = dp->dp_dirp;		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))			return (1);		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {			gotalldir = 1;			*putdefp = 1;		}		if ((dp->dp_flag & DP_DEFSET) == 0 &&		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {			hp = dp->dp_hosts;			while (hp) {				grp = hp->ht_grp;				if (grp->gr_type == GT_HOST) {					if (!xdr_bool(xdrsp, &true))						return (1);					strp = grp->gr_ptr.gt_hostent->h_name;					if (!xdr_string(xdrsp, &strp,					    RPCMNT_NAMELEN))						return (1);				} else if (grp->gr_type == GT_NET) {					if (!xdr_bool(xdrsp, &true))						return (1);					strp = grp->gr_ptr.gt_net.nt_name;					if (!xdr_string(xdrsp, &strp,					    RPCMNT_NAMELEN))						return (1);				}				hp = hp->ht_next;				if (gotalldir && hp == NULL) {					hp = adp->dp_hosts;					gotalldir = 0;				}			}		}		if (!xdr_bool(xdrsp, &false))			return (1);		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))			return (1);	}	return (0);}#define LINESIZ	10240char line[LINESIZ];FILE *exp_file;voidnew_exportlist(){	int save_errno = errno;	get_exportlist();	errno = save_errno;}/* * Get the export list */voidget_exportlist(){	struct exportlist *ep, *ep2;	struct grouplist *grp, *tgrp;	struct exportlist **epp;	struct dirlist *dirhead;	struct statfs fsb, *fsp;	struct hostent *hpe;	struct ucred anon;	char *cp, *endcp, *dirp = NULL, *hst, *usr, *dom, savedc;	int len, has_host, exflags, got_nondir, dirplen = 0, num, i, netgrp;	int lookup_failed;	/*	 * First, get rid of the old list	 */	ep = exphead;	while (ep) {		ep2 = ep;		ep = ep->ex_next;		free_exp(ep2);	}	exphead = NULL;	grp = grphead;	while (grp) {		tgrp = grp;		grp = grp->gr_next;		free_grp(tgrp);	}	grphead = NULL;	/*	 * And delete exports that are in the kernel for all local	 * file systems.	 * XXX: Should know how to handle all local exportable file systems	 *      instead of just MOUNT_FFS.	 */	num = getmntinfo(&fsp, MNT_NOWAIT);	for (i = 0; i < num; i++) {		union {			struct ufs_args ua;			struct iso_args ia;			struct mfs_args ma;			struct msdosfs_args da;			struct adosfs_args aa;		} targs;		if (!strncmp(fsp->f_fstypename, MOUNT_MFS, MFSNAMELEN) ||		    !strncmp(fsp->f_fstypename, MOUNT_FFS, MFSNAMELEN) ||		    !strncmp(fsp->f_fstypename, MOUNT_EXT2FS, MFSNAMELEN) ||		    !strncmp(fsp->f_fstypename, MOUNT_MSDOS, MFSNAMELEN) ||		    !strncmp(fsp->f_fstypename, MOUNT_ADOSFS, MFSNAMELEN) ||		    !strncmp(fsp->f_fstypename, MOUNT_CD9660, MFSNAMELEN)) {			bzero((char *)&targs, sizeof(targs));			targs.ua.fspec = NULL;			targs.ua.export.ex_flags = MNT_DELEXPORT;			if (mount(fsp->f_fstypename, fsp->f_mntonname,			    fsp->f_flags | MNT_UPDATE, &targs) < 0)				syslog(LOG_ERR, "Can't delete exports for %s: %m",				    fsp->f_mntonname);		}		fsp++;	}	/*	 * Read in the exports file and build the list, calling	 * mount() as we go along to push the export rules into the kernel.	 */	if ((exp_file = fopen(exname, "r")) == NULL) {		syslog(LOG_ERR, "Can't open %s", exname);		exit(2);	}	dirhead = NULL;	while (get_line()) {		if (debug)			fprintf(stderr, "Got line %s\n",line);		cp = line;		nextfield(&cp, &endcp);		if (*cp == '#')			goto nextline;		/*		 * Set defaults.		 */		has_host = FALSE;		lookup_failed = FALSE;		anon = def_anon;		exflags = MNT_EXPORTED;		got_nondir = 0;		opt_flags = 0;		ep = NULL;		/*		 * Create new exports list entry		 */		len = endcp-cp;		tgrp = grp = get_grp();		while (len > 0) {			if (len > RPCMNT_NAMELEN) {				getexp_err(ep, tgrp);				goto nextline;			}			if (*cp == '-') {				if (ep == NULL) {					getexp_err(ep, tgrp);					goto nextline;				}				if (debug)					fprintf(stderr, "doing opt %s\n", cp);				got_nondir = 1;				if (do_opt(&cp, &endcp, ep, grp, &has_host,				    &exflags, &anon)) {					getexp_err(ep, tgrp);					goto nextline;				}			} else if (*cp == '/') {			    savedc = *endcp;			    *endcp = '\0';			    if (check_dirpath(cp) &&				statfs(cp, &fsb) >= 0) {				if (got_nondir) {				    syslog(LOG_ERR, "Dirs must be first");				    getexp_err(ep, tgrp);				    goto nextline;				}				if (ep) {				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {					getexp_err(ep, tgrp);					goto nextline;				    }				} else {				    /*				     * See if this directory is already				     * in the list.				     */				    ep = ex_search(&fsb.f_fsid);				    if (ep == NULL) {					ep = get_exp();					ep->ex_fs = fsb.f_fsid;					ep->ex_fsdir = (char *)					    malloc(strlen(fsb.f_mntonname) + 1);					if (ep->ex_fsdir)					    strcpy(ep->ex_fsdir,						fsb.f_mntonname);					else					    out_of_mem();					if (debug)					  fprintf(stderr,					      "Making new ep fs=0x%x,0x%x\n",					      fsb.f_fsid.val[0],					      fsb.f_fsid.val[1]);				    } else if (debug)					fprintf(stderr,					    "Found ep fs=0x%x,0x%x\n",					    fsb.f_fsid.val[0],					    fsb.f_fsid.val[1]);				}				/*				 * Add dirpath to export mount point.				 */				dirp = add_expdir(&dirhead, cp, len);				dirplen = len;			    } else {				getexp_err(ep, tgrp);				goto nextline;			    }			    *endcp = savedc;			} else {			    savedc = *endcp;			    *endcp = '\0';			    got_nondir = 1;			    if (ep == NULL) {				getexp_err(ep, tgrp);				goto nextline;			    }			    /*			     * Get the host or netgroup.			     */			    setnetgrent(cp);			    netgrp = getnetgrent((const char **)&hst,				(const char **)&usr, (const char **)&dom);			    do {				if (has_host) {				    grp->gr_next = get_grp();				    grp = grp->gr_next;				}				if (netgrp) {				    if (hst == NULL) {					syslog(LOG_ERR,					    "NULL hostname in netgroup %s, skipping",					    cp);					grp->gr_type = GT_IGNORE;				    } else if (get_host(hst, grp, tgrp)) {					syslog(LOG_ERR,					    "Unknown host (%s) in netgroup %s",					    hst, cp);					has_host = FALSE;					lookup_failed = TRUE;					continue;				    }				} else if (get_host(cp, grp, tgrp)) {				    syslog(LOG_ERR,					"Unknown host (%s) in line %s",					cp, line);				    has_host = FALSE;				    lookup_failed = TRUE;				    continue;				}				has_host = TRUE;			    } while (netgrp && getnetgrent((const char **)&hst,				(const char **)&usr, (const char **)&dom));			    endnetgrent();			    *endcp = savedc;			}			cp = endcp;			nextfield(&cp, &endcp);			len = endcp - cp;		}		/*		 * If the exports list is empty due to unresolvable hostnames		 * we throw away the line.		 */		if (lookup_failed == TRUE && has_host == FALSE &&		    tgrp->gr_type == GT_NULL)  {			getexp_err(ep, tgrp);			goto nextline;		}		if (check_options(dirhead)) {			getexp_err(ep, tgrp);			goto nextline;		}		if (!has_host) {			grp->gr_type = GT_HOST;			if (debug)				fprintf(stderr, "Adding a default entry\n");			/* add a default group and make the grp list NULL */			hpe = (struct hostent *)malloc(sizeof(struct hostent));			if (hpe == NULL)				out_of_mem();			hpe->h_name = strdup("Default");			hpe->h_addrtype = AF_INET;			hpe->h_length = sizeof (u_int32_t);			hpe->h_addr_list = NULL;			grp->gr_ptr.gt_hostent = hpe;		/*		 * Don't allow a network export coincide with a list of		 * host(s) on the same line.		 */		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {			getexp_err(ep, tgrp);			goto nextline;		}		/*		 * Loop through hosts, pushing the exports into the kernel.		 * After loop, tgrp points to the start of the list and		 * grp points to the last entry in the list.		 */		grp = tgrp;		do {			/*			 * Non-zero return indicates an error.  Return			 * val of 1 means line is invalid (not just entry).			 */			i = do_mount(ep, grp, exflags, &anon, dirp, dirplen, &fsb);			if (i == 1) {				getexp_err(ep, tgrp);				goto nextline;			} else if (i == 2) {				syslog(LOG_ERR,				    "Bad exports list entry (%s) in line %s",				    (grp->gr_type == GT_HOST)				    ? grp->gr_ptr.gt_hostent->h_name				    : (grp->gr_type == GT_NET)				    ? grp->gr_ptr.gt_net.nt_name				    : "Unknown", line);			}		} while (grp->gr_next && (grp = grp->gr_next));		/*		 * Success. Update the data structures.		 */		if (has_host) {			hang_dirp(dirhead, tgrp, ep, opt_flags);			grp->gr_next = grphead;			grphead = tgrp;		} else {			hang_dirp(dirhead, NULL, ep,				opt_flags);			free_grp(grp);		}		dirhead = NULL;		if ((ep->ex_flag & EX_LINKED) == 0) {			ep2 = exphead;			epp = &exphead;			/*			 * Insert in the list in alphabetical order.			 */			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {				epp = &ep2->ex_next;				ep2 = ep2->ex_next;			}			if (ep2)				ep->ex_next = ep2;			*epp = ep;			ep->ex_flag |= EX_LINKED;		}nextline:		if (dirhead) {			free_dir(dirhead);			dirhead = NULL;		}	}	fclose(exp_file);}/* * Allocate an export list element */struct exportlist *get_exp(){	struct exportlist *ep;	ep = (struct exportlist *)malloc(sizeof (struct exportlist));	if (ep == NULL)		out_of_mem();	memset(ep, 0, sizeof(struct exportlist));	return (ep);}/* * Allocate a group list element */struct grouplist *get_grp(){	struct grouplist *gp;	gp = (struct grouplist *)malloc(sizeof (struct grouplist));	if (gp == NULL)		out_of_mem();	memset(gp, 0, sizeof(struct grouplist));	return (gp);}/* * Clean up upon an error in get_exportlist(). */voidgetexp_err(ep, grp)	struct exportlist *ep;	struct grouplist *grp;{	struct grouplist *tgrp;	syslog(LOG_ERR, "Bad exports list line %s", line);	if (ep && (ep->ex_flag & EX_LINKED) == 0)		free_exp(ep);	while (grp) {		tgrp = grp;		grp = grp->gr_next;		free_grp(tgrp);	}}/* * Search the export list for a matching fs. */struct exportlist *ex_search(fsid)	fsid_t *fsid;{	struct exportlist *ep;	ep = exphead;	while (ep) {		if (ep->ex_fs.val[0] == fsid->val[0] &&		    ep->ex_fs.val[1] == fsid->val[1])			return (ep);		ep = ep->ex_next;	}	return (ep);}/* * Add a directory path to the list. */char *add_expdir(dpp, cp, len)	struct dirlist **dpp;	char *cp;	int len;{	struct dirlist *dp;	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);	dp->dp_left = *dpp;	dp->dp_right = NULL;	dp->dp_flag = 0;	dp->dp_hosts = NULL;	strcpy(dp->dp_dirp, cp);	*dpp = dp;	return (dp->dp_dirp);}/* * Hang the dir list element off the dirpath binary tree as required * and update the entry for host. */voidhang_dirp(dp, grp, ep, flags)	struct dirlist *dp;	struct grouplist *grp;	struct exportlist *ep;	int flags;{	struct hostlist *hp;	struct dirlist *dp2;	if (flags & OP_ALLDIRS) {		if (ep->ex_defdir)			free((caddr_t)dp);		else			ep->ex_defdir = dp;		if (grp == NULL) {			ep->ex_defdir->dp_flag |= DP_DEFSET;			if (flags & OP_KERB)				ep->ex_defdir->dp_flag |= DP_KERB;		} else while (grp) {			hp = get_ht();			if (flags & OP_KERB)				hp->ht_flag |= DP_KERB;			hp->ht_grp = grp;			hp->ht_next = ep->ex_defdir->dp_hosts;			ep->ex_defdir->dp_hosts = hp;			grp = grp->gr_next;		}	} else {		/*		 * Loop throught the directories adding them to the tree.		 */		while (dp) {			dp2 = dp->dp_left;			add_dlist(&ep->ex_dirl, dp, grp, flags);			dp = dp2;		}	}}/* * Traverse the binary tree either updating a node that is already there * for the new directory or adding the new node. */voidadd_dlist(dpp, newdp, grp, flags)	struct dirlist **dpp;	struct dirlist *newdp;	struct grouplist *grp;	int flags;{	struct dirlist *dp;	struct hostlist *hp;	int cmp;	dp = *dpp;	if (dp) {		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);		if (cmp > 0) {			add_dlist(&dp->dp_left, newdp, grp, flags);			return;		} else if (cmp < 0) {			add_dlist(&dp->dp_right, newdp, grp, flags);			return;		} else			free((caddr_t)newdp);	} else {		dp = newdp;		dp->dp_left = NULL;		*dpp = dp;	}	if (grp) {		/*		 * Hang all of the host(s) off of the directory point.		 */		do {			hp = get_ht();			if (flags & OP_KERB)				hp->ht_flag |= DP_KERB;			hp->ht_grp = grp;			hp->ht_next = dp->dp_hosts;			dp->dp_hosts = hp;			grp = grp->gr_next;		} while (grp);	} else {		dp->dp_flag |= DP_DEFSET;		if (flags & OP_KERB)			dp->dp_flag |= DP_KERB;	}}/* * Search for a dirpath on the export point. */struct dirlist *dirp_search(dp, dirpath)	struct dirlist *dp;	char *dirpath;{	int cmp;	if (dp) {		cmp = strcmp(dp->dp_dirp, dirpath);		if (cmp > 0)			return (dirp_search(dp->dp_left, dirpath));		else if (cmp < 0)			return (dirp_search(dp->dp_right, dirpath));		else			return (dp);	}	return (dp);}/* * Scan for a host match in a directory tree. */intchk_host(dp, saddr, defsetp, hostsetp)	struct dirlist *dp;	in_addr_t saddr;	int *defsetp;	int *hostsetp;{	struct hostlist *hp;	struct grouplist *grp;	u_int32_t **addrp;	if (dp) {		if (dp->dp_flag & DP_DEFSET)			*defsetp = dp->dp_flag;		hp = dp->dp_hosts;		while (hp) {			grp = hp->ht_grp;			switch (grp->gr_type) {			case GT_HOST:			    addrp = (u_int32_t **)				grp->gr_ptr.gt_hostent->h_addr_list;			    while (*addrp) {				if (**addrp == saddr) {				    *hostsetp = (hp->ht_flag | DP_HOSTSET);				    return (1);				}				addrp++;			    }			    break;			case GT_NET:			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==				grp->gr_ptr.gt_net.nt_net) {				*hostsetp = (hp->ht_flag | DP_HOSTSET);				return (1);			    }			    break;			};			hp = hp->ht_next;		}	}	return (0);}/* * Scan tree for a host that matches the address. */intscan_tree(dp, saddr)	struct dirlist *dp;	in_addr_t saddr;{	int defset, hostset;	if (dp) {		if (scan_tree(dp->dp_left, saddr))			return (1);		if (chk_host(dp, saddr, &defset, &hostset))			return (1);		if (scan_tree(dp->dp_right, saddr))			return (1);	}	return (0);}/* * Traverse the dirlist tree and free it up. */voidfree_dir(dp)	struct dirlist *dp;{	if (dp) {		free_dir(dp->dp_left);		free_dir(dp->dp_right);		free_host(dp->dp_hosts);		free((caddr_t)dp);	}}/* * Parse the option string and update fields. * Option arguments may either be -<option>=<value> or * -<option> <value> */intdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)	char **cpp, **endcpp;	struct exportlist *ep;	struct grouplist *grp;	int *has_hostp;	int *exflagsp;	struct ucred *cr;{	char *cpoptarg, *cpoptend;	char *cp, *endcp, *cpopt, savedc, savedc2 = 0;	int allflag, usedarg;	cpopt = *cpp;	cpopt++;	cp = *endcpp;	savedc = *cp;	*cp = '\0';	while (cpopt && *cpopt) {		allflag = 1;		usedarg = -2;		if ((cpoptend = strchr(cpopt, ','))) {			*cpoptend++ = '\0';			if ((cpoptarg = strchr(cpopt, '=')))				*cpoptarg++ = '\0';		} else {			if ((cpoptarg = strchr(cpopt, '=')))				*cpoptarg++ = '\0';			else {				*cp = savedc;				nextfield(&cp, &endcp);				**endcpp = '\0';				if (endcp > cp && *cp != '-') {					cpoptarg = cp;					savedc2 = *endcp;					*endcp = '\0';					usedarg = 0;				}			}		}		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {			*exflagsp |= MNT_EXRDONLY;		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||		    !(allflag = strcmp(cpopt, "mapall")) ||		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {			usedarg++;			parsecred(cpoptarg, cr);			if (allflag == 0) {				*exflagsp |= MNT_EXPORTANON;				opt_flags |= OP_MAPALL;			} else				opt_flags |= OP_MAPROOT;		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {			*exflagsp |= MNT_EXKERB;			opt_flags |= OP_KERB;		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||		    !strcmp(cpopt, "m"))) {			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);				return (1);			}			usedarg++;			opt_flags |= OP_MASK;		} else if (cpoptarg && (!strcmp(cpopt, "network") ||		    !strcmp(cpopt, "n"))) {			if (grp->gr_type != GT_NULL) {				syslog(LOG_ERR, "Network/host conflict");				return (1);			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {				syslog(LOG_ERR, "Bad net: %s", cpoptarg);				return (1);			}			grp->gr_type = GT_NET;			*has_hostp = 1;			usedarg++;			opt_flags |= OP_NET;		} else if (!strcmp(cpopt, "alldirs")) {			opt_flags |= OP_ALLDIRS;		} else {			syslog(LOG_ERR, "Bad opt %s", cpopt);			return (1);		}		if (usedarg >= 0) {			*endcp = savedc2;			**endcpp = savedc;			if (usedarg > 0) {				*cpp = cp;				*endcpp = endcp;			}			return (0);		}		cpopt = cpoptend;	}	**endcpp = savedc;	return (0);}/* * Translate a character string to the corresponding list of network * addresses for a hostname. */intget_host(cp, grp, tgrp)	char *cp;	struct grouplist *grp;	struct grouplist *tgrp;{	struct grouplist *checkgrp;	struct hostent *hp, *nhp;	char **addrp, **naddrp;	struct hostent t_host;	int i;	in_addr_t saddr;	char *aptr[2];	if (grp->gr_type != GT_NULL)		return (1);	if ((hp = gethostbyname(cp)) == NULL) {		if (isdigit(*cp)) {			saddr = inet_addr(cp);			if (saddr == -1) {				syslog(LOG_ERR, "inet_addr failed for %s", cp);				return (1);			}			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),				AF_INET)) == NULL) {				hp = &t_host;				hp->h_name = cp;				hp->h_addrtype = AF_INET;				hp->h_length = sizeof (u_int32_t);				hp->h_addr_list = aptr;				aptr[0] = (char *)&saddr;				aptr[1] = NULL;			}		} else {			syslog(LOG_ERR, "gethostbyname; failed for %s: %s", cp,			    hstrerror(h_errno));			return (1);		}	}	/* only insert each host onto the list once */	for (checkgrp = tgrp; checkgrp; checkgrp = checkgrp->gr_next) {		if (checkgrp->gr_type == GT_HOST &&		    checkgrp->gr_ptr.gt_hostent != NULL &&		    !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) {			grp->gr_type = GT_IGNORE;			return (0);		}	}	grp->gr_type = GT_HOST;	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)		malloc(sizeof(struct hostent));	if (nhp == NULL)		out_of_mem();	memcpy(nhp, hp, sizeof(struct hostent));	i = strlen(hp->h_name)+1;	nhp->h_name = (char *)malloc(i);	if (nhp->h_name == NULL)		out_of_mem();	memcpy(nhp->h_name, hp->h_name, i);	addrp = hp->h_addr_list;	i = 1;	while (*addrp++)		i++;	naddrp = nhp->h_addr_list = (char **)		malloc(i*sizeof(char *));	if (naddrp == NULL)		out_of_mem();	addrp = hp->h_addr_list;	while (*addrp) {		*naddrp = (char *)		    malloc(hp->h_length);		if (*naddrp == NULL)		    out_of_mem();		memcpy(*naddrp, *addrp, hp->h_length);		addrp++;		naddrp++;	}	*naddrp = NULL;	if (debug)		fprintf(stderr, "got host %s\n", hp->h_name);	return (0);}/* * Free up an exports list component */voidfree_exp(ep)	struct exportlist *ep;{	if (ep->ex_defdir) {		free_host(ep->ex_defdir->dp_hosts);		free((caddr_t)ep->ex_defdir);	}	if (ep->ex_fsdir)		free(ep->ex_fsdir);	free_dir(ep->ex_dirl);	free((caddr_t)ep);}/* * Free hosts. */voidfree_host(hp)	struct hostlist *hp;{	struct hostlist *hp2;	while (hp) {		hp2 = hp;		hp = hp->ht_next;		free((caddr_t)hp2);	}}struct hostlist *get_ht(){	struct hostlist *hp;	hp = (struct hostlist *)malloc(sizeof (struct hostlist));	if (hp == NULL)		out_of_mem();	hp->ht_next = NULL;	hp->ht_flag = 0;	return (hp);}