mountd.c revision 8871
1161764Sobrien/*
279968Sobrien * Copyright (c) 1989, 1993
379968Sobrien *	The Regents of the University of California.  All rights reserved.
4133936Sobrien *
579968Sobrien * This code is derived from software contributed to Berkeley by
679968Sobrien * Herb Hasler and Rick Macklem at The University of Guelph.
779968Sobrien *
879968Sobrien * Redistribution and use in source and binary forms, with or without
979968Sobrien * modification, are permitted provided that the following conditions
1079968Sobrien * are met:
1179968Sobrien * 1. Redistributions of source code must retain the above copyright
1279968Sobrien *    notice, this list of conditions and the following disclaimer.
1379968Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1479968Sobrien *    notice, this list of conditions and the following disclaimer in the
1579968Sobrien *    documentation and/or other materials provided with the distribution.
1679968Sobrien * 3. All advertising materials mentioning features or use of this software
1779968Sobrien *    must display the following acknowledgement:
1879968Sobrien *	This product includes software developed by the University of
1979968Sobrien *	California, Berkeley and its contributors.
2079968Sobrien * 4. Neither the name of the University nor the names of its contributors
2179968Sobrien *    may be used to endorse or promote products derived from this software
2279968Sobrien *    without specific prior written permission.
2379968Sobrien *
2479968Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2579968Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2679968Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2779968Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2879968Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2979968Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3079968Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3179968Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3279968Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3379968Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3479968Sobrien * SUCH DAMAGE.
3579968Sobrien */
3679968Sobrien
3779968Sobrien#ifndef lint
3879968Sobrienstatic char copyright[] =
3979968Sobrien"@(#) Copyright (c) 1989, 1993\n\
4079968Sobrien	The Regents of the University of California.  All rights reserved.\n";
4179968Sobrien#endif /*not lint*/
4279968Sobrien
4379968Sobrien#ifndef lint
4479968Sobrien/*static char sccsid[] = "From: @(#)mountd.c	8.8 (Berkeley) 2/20/94";*/
4579968Sobrienstatic const char rcsid[] =
4679968Sobrien	"$Id: mountd.c,v 1.6 1995/05/21 19:31:09 phk Exp $";
4779968Sobrien#endif /*not lint*/
4879968Sobrien
4979968Sobrien#include <sys/param.h>
5079968Sobrien#include <sys/file.h>
51133936Sobrien#include <sys/ioctl.h>
5279968Sobrien#include <sys/mount.h>
5379968Sobrien#include <sys/socket.h>
5479968Sobrien#include <sys/stat.h>
5579968Sobrien#include <sys/syslog.h>
5679968Sobrien#include <sys/ucred.h>
5779968Sobrien
5879968Sobrien#include <rpc/rpc.h>
5979968Sobrien#include <rpc/pmap_clnt.h>
6079968Sobrien#include <rpc/pmap_prot.h>
6179968Sobrien#ifdef ISO
6279968Sobrien#include <netiso/iso.h>
6379968Sobrien#endif
6479968Sobrien#include <nfs/rpcv2.h>
6579968Sobrien#include <nfs/nfsv2.h>
6679968Sobrien
6779968Sobrien#include <arpa/inet.h>
6879968Sobrien
6979968Sobrien#include <ctype.h>
7079968Sobrien#include <errno.h>
7179968Sobrien#include <grp.h>
7279968Sobrien#include <netdb.h>
7379968Sobrien#include <pwd.h>
7479968Sobrien#include <signal.h>
7579968Sobrien#include <stdio.h>
7679968Sobrien#include <stdlib.h>
7779968Sobrien#include <string.h>
7879968Sobrien#include <unistd.h>
7979968Sobrien#include "pathnames.h"
8079968Sobrien
8179968Sobrien#ifdef DEBUG
8279968Sobrien#include <stdarg.h>
8379968Sobrien#endif
8479968Sobrien
8579968Sobrien/*
8679968Sobrien * Structures for keeping the mount list and export list
8779968Sobrien */
8879968Sobrienstruct mountlist {
8979968Sobrien	struct mountlist *ml_next;
9079968Sobrien	char	ml_host[RPCMNT_NAMELEN+1];
9179968Sobrien	char	ml_dirp[RPCMNT_PATHLEN+1];
9279968Sobrien};
9379968Sobrien
9479968Sobrienstruct dirlist {
9579968Sobrien	struct dirlist	*dp_left;
9679968Sobrien	struct dirlist	*dp_right;
9779968Sobrien	int		dp_flag;
98108746Sobrien	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
99108746Sobrien	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
100161764Sobrien};
101108746Sobrien/* dp_flag bits */
102108746Sobrien#define	DP_DEFSET	0x1
103108746Sobrien
104108746Sobrienstruct exportlist {
105108746Sobrien	struct exportlist *ex_next;
106108746Sobrien	struct dirlist	*ex_dirl;
107108746Sobrien	struct dirlist	*ex_defdir;
108108746Sobrien	int		ex_flag;
109108746Sobrien	fsid_t		ex_fs;
110108746Sobrien	char		*ex_fsdir;
111108746Sobrien};
112108746Sobrien/* ex_flag bits */
113108746Sobrien#define	EX_LINKED	0x1
114108746Sobrien
115108746Sobrienstruct netmsk {
116108746Sobrien	u_long	nt_net;
117108746Sobrien	u_long	nt_mask;
118108746Sobrien	char *nt_name;
119108746Sobrien};
120108746Sobrien
12179968Sobrienunion grouptypes {
12279968Sobrien	struct hostent *gt_hostent;
12392282Sobrien	struct netmsk	gt_net;
12492282Sobrien#ifdef ISO
12592282Sobrien	struct sockaddr_iso *gt_isoaddr;
12692282Sobrien#endif
12792282Sobrien};
12879968Sobrien
12979968Sobrienstruct grouplist {
13079968Sobrien	int gr_type;
13179968Sobrien	union grouptypes gr_ptr;
13279968Sobrien	struct grouplist *gr_next;
13392282Sobrien};
13479968Sobrien/* Group types */
13579968Sobrien#define	GT_NULL		0x0
13679968Sobrien#define	GT_HOST		0x1
13779968Sobrien#define	GT_NET		0x2
13879968Sobrien#define	GT_ISO		0x4
13979968Sobrien#define GT_IGNORE	0x5
14079968Sobrien
14179968Sobrienstruct hostlist {
14279968Sobrien	struct grouplist *ht_grp;
14379968Sobrien	struct hostlist	 *ht_next;
14479968Sobrien};
14579968Sobrien
14679968Sobrien/* Global defs */
14779968Sobrienchar	*add_expdir __P((struct dirlist **, char *, int));
14879968Sobrienvoid	add_dlist __P((struct dirlist **, struct dirlist *,
14979968Sobrien				struct grouplist *));
15079968Sobrienvoid	add_mlist __P((char *, char *));
15179968Sobrienint	check_dirpath __P((char *));
15279968Sobrienint	check_options __P((struct dirlist *));
15379968Sobrienint	chk_host __P((struct dirlist *, u_long, int *));
15479968Sobrienvoid	del_mlist __P((char *, char *));
15579968Sobrienstruct dirlist *dirp_search __P((struct dirlist *, char *));
15679968Sobrienint	do_mount __P((struct exportlist *, struct grouplist *, int,
15779968Sobrien				struct ucred *, char *, int, struct statfs *));
15879968Sobrienint	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
15979968Sobrien				int *, int *, struct ucred *));
16079968Sobrienstruct	exportlist *ex_search __P((fsid_t *));
16179968Sobrienstruct	exportlist *get_exp __P((void));
16279968Sobrienvoid	free_dir __P((struct dirlist *));
16379968Sobrienvoid	free_exp __P((struct exportlist *));
16479968Sobrienvoid	free_grp __P((struct grouplist *));
16579968Sobrienvoid	free_host __P((struct hostlist *));
16679968Sobrienvoid	get_exportlist __P((void));
16779968Sobrienint	get_host __P((char *, struct grouplist *, struct grouplist *));
16879968Sobrienstruct hostlist *get_ht __P((void));
169110242Sobrienint	get_line __P((void));
170110242Sobrienvoid	get_mountlist __P((void));
17179968Sobrienint	get_net __P((char *, struct netmsk *, int));
17279968Sobrienvoid	getexp_err __P((struct exportlist *, struct grouplist *));
17379968Sobrienstruct grouplist *get_grp __P((void));
17479968Sobrienvoid	hang_dirp __P((struct dirlist *, struct grouplist *,
17579968Sobrien				struct exportlist *, int));
17679968Sobrienvoid	mntsrv __P((struct svc_req *, SVCXPRT *));
17779968Sobrienvoid	nextfield __P((char **, char **));
17879968Sobrienvoid	out_of_mem __P((void));
17979968Sobrienvoid	parsecred __P((char *, struct ucred *));
18079968Sobrienint	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
181110242Sobrienint	scan_tree __P((struct dirlist *, u_long));
182110242Sobrienvoid	send_umntall __P((void));
183110242Sobrienint	umntall_each __P((caddr_t, struct sockaddr_in *));
18479968Sobrienint	xdr_dir __P((XDR *, char *));
18579968Sobrienint	xdr_explist __P((XDR *, caddr_t));
18679968Sobrienint	xdr_fhs __P((XDR *, nfsv2fh_t *));
18779968Sobrienint	xdr_mlist __P((XDR *, caddr_t));
18879968Sobrien
18979968Sobrien/* C library */
19079968Sobrienint	getnetgrent();
19179968Sobrienvoid	endnetgrent();
19279968Sobrienvoid	setnetgrent();
19379968Sobrien
19479968Sobrien#ifdef ISO
19579968Sobrienstruct iso_addr *iso_addr();
19679968Sobrien#endif
19779968Sobrien
19879968Sobrienstruct exportlist *exphead;
19979968Sobrienstruct mountlist *mlhead;
20079968Sobrienstruct grouplist *grphead;
20179968Sobrienchar exname[MAXPATHLEN];
20279968Sobrienstruct ucred def_anon = {
20379968Sobrien	1,
20479968Sobrien	(uid_t) -2,
20579968Sobrien	1,
20679968Sobrien	{ (gid_t) -2 }
20779968Sobrien};
20879968Sobrienint root_only = 1;
20979968Sobrienint opt_flags;
21079968Sobrien/* Bits for above */
21179968Sobrien#define	OP_MAPROOT	0x01
21279968Sobrien#define	OP_MAPALL	0x02
21379968Sobrien#define	OP_KERB		0x04
21479968Sobrien#define	OP_MASK		0x08
21579968Sobrien#define	OP_NET		0x10
21679968Sobrien#define	OP_ISO		0x20
21779968Sobrien#define	OP_ALLDIRS	0x40
21879968Sobrien
21979968Sobrien#ifdef DEBUG
22079968Sobrienint debug = 1;
22179968Sobrienvoid	SYSLOG __P((int, const char *, ...));
22279968Sobrien#define syslog SYSLOG
22379968Sobrien#else
22479968Sobrienint debug = 0;
22579968Sobrien#endif
22679968Sobrien
22779968Sobrien/*
22879968Sobrien * Mountd server for NFS mount protocol as described in:
22979968Sobrien * NFS: Network File System Protocol Specification, RFC1094, Appendix A
23079968Sobrien * The optional arguments are the exports file name
23179968Sobrien * default: _PATH_EXPORTS
23279968Sobrien * and "-n" to allow nonroot mount.
23379968Sobrien */
23479968Sobrienint
23579968Sobrienmain(argc, argv)
23679968Sobrien	int argc;
23779968Sobrien	char **argv;
23879968Sobrien{
23979968Sobrien	SVCXPRT *transp;
24079968Sobrien	int c;
24179968Sobrien	struct vfsconf *vfc;
24279968Sobrien
24379968Sobrien	vfc = getvfsbyname("nfs");
24479968Sobrien	if(!vfc && vfsisloadable("nfs")) {
24579968Sobrien		if(vfsload("nfs"))
24679968Sobrien			err(1, "vfsload(nfs)");
24779968Sobrien		endvfsent();	/* flush cache */
24879968Sobrien		vfc = getvfsbyname("nfs");
24979968Sobrien	}
25079968Sobrien	if(!vfc) {
25179968Sobrien		errx(1, "NFS support is not available in the running kernel");
25279968Sobrien	}
25379968Sobrien
25479968Sobrien	while ((c = getopt(argc, argv, "dn")) != EOF)
25592282Sobrien		switch (c) {
25692282Sobrien		case 'd':
25792282Sobrien			debug = debug ? 0 : 1;
25879968Sobrien			break;
25979968Sobrien		case 'n':
26079968Sobrien			root_only = 0;
26179968Sobrien			break;
26292282Sobrien		default:
26379968Sobrien			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
26492282Sobrien			exit(1);
26579968Sobrien		};
26679968Sobrien	argc -= optind;
26779968Sobrien	argv += optind;
26879968Sobrien	grphead = (struct grouplist *)NULL;
26979968Sobrien	exphead = (struct exportlist *)NULL;
27079968Sobrien	mlhead = (struct mountlist *)NULL;
27179968Sobrien	if (argc == 1) {
27292282Sobrien		strncpy(exname, *argv, MAXPATHLEN-1);
27379968Sobrien		exname[MAXPATHLEN-1] = '\0';
27479968Sobrien	} else
27579968Sobrien		strcpy(exname, _PATH_EXPORTS);
27679968Sobrien	openlog("mountd", LOG_PID, LOG_DAEMON);
27779968Sobrien	if (debug)
27879968Sobrien		fprintf(stderr,"Getting export list.\n");
27979968Sobrien	get_exportlist();
28079968Sobrien	if (debug)
28192282Sobrien		fprintf(stderr,"Getting mount list.\n");
28279968Sobrien	get_mountlist();
28379968Sobrien	if (debug)
28479968Sobrien		fprintf(stderr,"Here we go.\n");
28579968Sobrien	if (debug == 0) {
28679968Sobrien		daemon(0, 0);
28779968Sobrien		signal(SIGINT, SIG_IGN);
28879968Sobrien		signal(SIGQUIT, SIG_IGN);
28979968Sobrien	}
29079968Sobrien	signal(SIGHUP, (void (*) __P((int))) get_exportlist);
29179968Sobrien	signal(SIGTERM, (void (*) __P((int))) send_umntall);
29279968Sobrien	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
29379968Sobrien	  if (pidfile != NULL) {
29479968Sobrien		fprintf(pidfile, "%d\n", getpid());
29579968Sobrien		fclose(pidfile);
29679968Sobrien	  }
29779968Sobrien	}
29879968Sobrien	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
29979968Sobrien		syslog(LOG_ERR, "Can't create socket");
30079968Sobrien		exit(1);
30179968Sobrien	}
30279968Sobrien	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
30379968Sobrien	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
30479968Sobrien	    IPPROTO_UDP)) {
30579968Sobrien		syslog(LOG_ERR, "Can't register mount");
30679968Sobrien		exit(1);
30779968Sobrien	}
30879968Sobrien	svc_run();
30979968Sobrien	syslog(LOG_ERR, "Mountd died");
31079968Sobrien	exit(1);
31179968Sobrien}
31292282Sobrien
31379968Sobrien/*
31479968Sobrien * The mount rpc service
31579968Sobrien */
31679968Sobrienvoid
31779968Sobrienmntsrv(rqstp, transp)
31879968Sobrien	struct svc_req *rqstp;
31979968Sobrien	SVCXPRT *transp;
32079968Sobrien{
32179968Sobrien	struct exportlist *ep;
32279968Sobrien	struct dirlist *dp;
32379968Sobrien	nfsv2fh_t nfh;
32479968Sobrien	struct authunix_parms *ucr;
32579968Sobrien	struct stat stb;
32679968Sobrien	struct statfs fsb;
32779968Sobrien	struct hostent *hp;
32879968Sobrien	u_long saddr;
32979968Sobrien	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
33079968Sobrien	int bad = ENOENT, omask, defset;
33179968Sobrien	uid_t uid = -2;
33279968Sobrien
333108746Sobrien	/* Get authorization */
33479968Sobrien	switch (rqstp->rq_cred.oa_flavor) {
33579968Sobrien	case AUTH_UNIX:
33679968Sobrien		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
337108746Sobrien		uid = ucr->aup_uid;
33879968Sobrien		break;
33979968Sobrien	case AUTH_NULL:
34079968Sobrien	default:
34179968Sobrien		break;
34279968Sobrien	}
34379968Sobrien
34479968Sobrien	saddr = transp->xp_raddr.sin_addr.s_addr;
34579968Sobrien	hp = (struct hostent *)NULL;
34679968Sobrien	switch (rqstp->rq_proc) {
34779968Sobrien	case NULLPROC:
34879968Sobrien		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
34979968Sobrien			syslog(LOG_ERR, "Can't send reply");
35079968Sobrien		return;
35179968Sobrien	case RPCMNT_MOUNT:
35279968Sobrien		if ((uid != 0 && root_only) || uid == -2) {
35379968Sobrien			svcerr_weakauth(transp);
35479968Sobrien			return;
35579968Sobrien		}
35679968Sobrien		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
35779968Sobrien			svcerr_decode(transp);
35879968Sobrien			return;
35979968Sobrien		}
36079968Sobrien
36179968Sobrien		/*
36279968Sobrien		 * Get the real pathname and make sure it is a directory
36379968Sobrien		 * that exists.
36479968Sobrien		 */
36579968Sobrien		if (realpath(rpcpath, dirpath) == 0 ||
36679968Sobrien		    stat(dirpath, &stb) < 0 ||
36779968Sobrien		    (stb.st_mode & S_IFMT) != S_IFDIR ||
36879968Sobrien		    statfs(dirpath, &fsb) < 0) {
36979968Sobrien			chdir("/");	/* Just in case realpath doesn't */
37079968Sobrien			if (debug)
37179968Sobrien				fprintf(stderr, "stat failed on %s\n", dirpath);
37279968Sobrien			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
37379968Sobrien				syslog(LOG_ERR, "Can't send reply");
37479968Sobrien			return;
37579968Sobrien		}
37679968Sobrien
37779968Sobrien		/* Check in the exports list */
37879968Sobrien		omask = sigblock(sigmask(SIGHUP));
37979968Sobrien		ep = ex_search(&fsb.f_fsid);
38079968Sobrien		defset = 0;
38179968Sobrien		if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
38279968Sobrien		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
38379968Sobrien		     chk_host(dp, saddr, &defset)) ||
38479968Sobrien		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
38579968Sobrien		      scan_tree(ep->ex_dirl, saddr) == 0))) {
38679968Sobrien			/* Get the file handle */
38779968Sobrien			bzero((caddr_t)&nfh, sizeof(nfh));
38879968Sobrien			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
38979968Sobrien				bad = errno;
39079968Sobrien				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
39179968Sobrien				if (!svc_sendreply(transp, xdr_long,
39279968Sobrien				    (caddr_t)&bad))
39379968Sobrien					syslog(LOG_ERR, "Can't send reply");
394161764Sobrien				sigsetmask(omask);
39579968Sobrien				return;
39679968Sobrien			}
39779968Sobrien			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
39879968Sobrien				syslog(LOG_ERR, "Can't send reply");
39979968Sobrien			if (hp == NULL)
40079968Sobrien				hp = gethostbyaddr((caddr_t)&saddr,
40179968Sobrien				    sizeof(saddr), AF_INET);
40279968Sobrien			if (hp)
40379968Sobrien				add_mlist(hp->h_name, dirpath);
40479968Sobrien			else
40579968Sobrien				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
40679968Sobrien					dirpath);
407110242Sobrien			if (debug)
408110242Sobrien				fprintf(stderr,"Mount successfull.\n");
409110242Sobrien		} else {
410110242Sobrien			bad = EACCES;
411110242Sobrien			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
412110242Sobrien				syslog(LOG_ERR, "Can't send reply");
413110242Sobrien		}
414110242Sobrien		sigsetmask(omask);
415110242Sobrien		return;
41679968Sobrien	case RPCMNT_DUMP:
41779968Sobrien		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
41879968Sobrien			syslog(LOG_ERR, "Can't send reply");
41979968Sobrien		return;
42079968Sobrien	case RPCMNT_UMOUNT:
42179968Sobrien		if ((uid != 0 && root_only) || uid == -2) {
42279968Sobrien			svcerr_weakauth(transp);
42379968Sobrien			return;
42479968Sobrien		}
42579968Sobrien		if (!svc_getargs(transp, xdr_dir, dirpath)) {
42679968Sobrien			svcerr_decode(transp);
42779968Sobrien			return;
42879968Sobrien		}
42979968Sobrien		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
43079968Sobrien			syslog(LOG_ERR, "Can't send reply");
43179968Sobrien		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
43279968Sobrien		if (hp)
43379968Sobrien			del_mlist(hp->h_name, dirpath);
43479968Sobrien		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
43579968Sobrien		return;
43679968Sobrien	case RPCMNT_UMNTALL:
43779968Sobrien		if ((uid != 0 && root_only) || uid == -2) {
43879968Sobrien			svcerr_weakauth(transp);
43979968Sobrien			return;
44079968Sobrien		}
441161764Sobrien		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
44279968Sobrien			syslog(LOG_ERR, "Can't send reply");
44379968Sobrien		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
44479968Sobrien		if (hp)
44579968Sobrien			del_mlist(hp->h_name, (char *)NULL);
44679968Sobrien		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
44779968Sobrien		return;
44879968Sobrien	case RPCMNT_EXPORT:
44979968Sobrien		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
45079968Sobrien			syslog(LOG_ERR, "Can't send reply");
45179968Sobrien		return;
45279968Sobrien	default:
45379968Sobrien		svcerr_noproc(transp);
45479968Sobrien		return;
45579968Sobrien	}
45679968Sobrien}
45779968Sobrien
45879968Sobrien/*
45979968Sobrien * Xdr conversion for a dirpath string
46079968Sobrien */
46179968Sobrienint
46279968Sobrienxdr_dir(xdrsp, dirp)
46379968Sobrien	XDR *xdrsp;
46479968Sobrien	char *dirp;
46579968Sobrien{
46679968Sobrien	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
46779968Sobrien}
46879968Sobrien
46979968Sobrien/*
47079968Sobrien * Xdr routine to generate fhstatus
47179968Sobrien */
47279968Sobrienint
47379968Sobrienxdr_fhs(xdrsp, nfh)
47479968Sobrien	XDR *xdrsp;
47579968Sobrien	nfsv2fh_t *nfh;
47679968Sobrien{
47779968Sobrien	u_long ok = 0;
47879968Sobrien
47979968Sobrien	if (!xdr_long(xdrsp, &ok))
48079968Sobrien		return (0);
48179968Sobrien	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
48279968Sobrien}
48379968Sobrien
48479968Sobrienint
48579968Sobrienxdr_mlist(xdrsp, cp)
48679968Sobrien	XDR *xdrsp;
48792282Sobrien	caddr_t cp;
48892282Sobrien{
48992282Sobrien	struct mountlist *mlp;
49092282Sobrien	int true = 1;
49192282Sobrien	int false = 0;
49279968Sobrien	char *strp;
49379968Sobrien
49492282Sobrien	mlp = mlhead;
49579968Sobrien	while (mlp) {
49679968Sobrien		if (!xdr_bool(xdrsp, &true))
49779968Sobrien			return (0);
49879968Sobrien		strp = &mlp->ml_host[0];
49979968Sobrien		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
50079968Sobrien			return (0);
50179968Sobrien		strp = &mlp->ml_dirp[0];
50279968Sobrien		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
50379968Sobrien			return (0);
50479968Sobrien		mlp = mlp->ml_next;
50579968Sobrien	}
50679968Sobrien	if (!xdr_bool(xdrsp, &false))
50779968Sobrien		return (0);
50879968Sobrien	return (1);
50979968Sobrien}
51079968Sobrien
51179968Sobrien/*
51279968Sobrien * Xdr conversion for export list
51379968Sobrien */
514108746Sobrienint
51579968Sobrienxdr_explist(xdrsp, cp)
51679968Sobrien	XDR *xdrsp;
51779968Sobrien	caddr_t cp;
51879968Sobrien{
51979968Sobrien	struct exportlist *ep;
52079968Sobrien	int false = 0;
521108746Sobrien	int omask, putdef;
52279968Sobrien
52379968Sobrien	omask = sigblock(sigmask(SIGHUP));
52479968Sobrien	ep = exphead;
52579968Sobrien	while (ep) {
52679968Sobrien		putdef = 0;
52779968Sobrien		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
52879968Sobrien			goto errout;
52979968Sobrien		if (ep->ex_defdir && putdef == 0 &&
53079968Sobrien			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
53179968Sobrien			&putdef))
53279968Sobrien			goto errout;
53379968Sobrien		ep = ep->ex_next;
53479968Sobrien	}
53579968Sobrien	sigsetmask(omask);
53679968Sobrien	if (!xdr_bool(xdrsp, &false))
537108746Sobrien		return (0);
538108746Sobrien	return (1);
53979968Sobrienerrout:
540108746Sobrien	sigsetmask(omask);
54179968Sobrien	return (0);
54279968Sobrien}
54379968Sobrien
54479968Sobrien/*
54579968Sobrien * Called from xdr_explist() to traverse the tree and export the
54679968Sobrien * directory paths.
54779968Sobrien */
54879968Sobrienint
54979968Sobrienput_exlist(dp, xdrsp, adp, putdefp)
55079968Sobrien	struct dirlist *dp;
55179968Sobrien	XDR *xdrsp;
55279968Sobrien	struct dirlist *adp;
55379968Sobrien	int *putdefp;
55479968Sobrien{
55579968Sobrien	struct grouplist *grp;
55679968Sobrien	struct hostlist *hp;
55779968Sobrien	int true = 1;
55879968Sobrien	int false = 0;
55979968Sobrien	int gotalldir = 0;
56079968Sobrien	char *strp;
56179968Sobrien
56279968Sobrien	if (dp) {
56379968Sobrien		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
56479968Sobrien			return (1);
56579968Sobrien		if (!xdr_bool(xdrsp, &true))
56679968Sobrien			return (1);
56779968Sobrien		strp = dp->dp_dirp;
56879968Sobrien		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
56979968Sobrien			return (1);
57079968Sobrien		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
57179968Sobrien			gotalldir = 1;
57279968Sobrien			*putdefp = 1;
57379968Sobrien		}
57479968Sobrien		if ((dp->dp_flag & DP_DEFSET) == 0 &&
57579968Sobrien		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
57679968Sobrien			hp = dp->dp_hosts;
57779968Sobrien			while (hp) {
57879968Sobrien				grp = hp->ht_grp;
57979968Sobrien				if (grp->gr_type == GT_HOST) {
58079968Sobrien					if (!xdr_bool(xdrsp, &true))
58179968Sobrien						return (1);
58279968Sobrien					strp = grp->gr_ptr.gt_hostent->h_name;
58379968Sobrien					if (!xdr_string(xdrsp, &strp,
58479968Sobrien					    RPCMNT_NAMELEN))
58579968Sobrien						return (1);
58679968Sobrien				} else if (grp->gr_type == GT_NET) {
58779968Sobrien					if (!xdr_bool(xdrsp, &true))
58879968Sobrien						return (1);
58979968Sobrien					strp = grp->gr_ptr.gt_net.nt_name;
59079968Sobrien					if (!xdr_string(xdrsp, &strp,
59179968Sobrien					    RPCMNT_NAMELEN))
59279968Sobrien						return (1);
59379968Sobrien				}
59479968Sobrien				hp = hp->ht_next;
59579968Sobrien				if (gotalldir && hp == (struct hostlist *)NULL) {
59679968Sobrien					hp = adp->dp_hosts;
59779968Sobrien					gotalldir = 0;
59879968Sobrien				}
59979968Sobrien			}
60079968Sobrien		}
60179968Sobrien		if (!xdr_bool(xdrsp, &false))
60279968Sobrien			return (1);
60379968Sobrien		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
60479968Sobrien			return (1);
60579968Sobrien	}
60679968Sobrien	return (0);
60779968Sobrien}
60879968Sobrien
60979968Sobrien#define LINESIZ	10240
61079968Sobrienchar line[LINESIZ];
61179968SobrienFILE *exp_file;
61279968Sobrien
61379968Sobrien/*
61479968Sobrien * Get the export list
61579968Sobrien */
61679968Sobrienvoid
61779968Sobrienget_exportlist()
61879968Sobrien{
61979968Sobrien	struct exportlist *ep, *ep2;
62079968Sobrien	struct grouplist *grp, *tgrp;
62179968Sobrien	struct exportlist **epp;
62279968Sobrien	struct dirlist *dirhead;
62379968Sobrien	struct statfs fsb, *fsp;
62479968Sobrien	struct hostent *hpe;
62579968Sobrien	struct ucred anon;
62679968Sobrien	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
62779968Sobrien	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
62879968Sobrien
62979968Sobrien	/*
63079968Sobrien	 * First, get rid of the old list
63179968Sobrien	 */
63279968Sobrien	ep = exphead;
63379968Sobrien	while (ep) {
63479968Sobrien		ep2 = ep;
63579968Sobrien		ep = ep->ex_next;
63679968Sobrien		free_exp(ep2);
63779968Sobrien	}
63879968Sobrien	exphead = (struct exportlist *)NULL;
63979968Sobrien
64079968Sobrien	grp = grphead;
64179968Sobrien	while (grp) {
64279968Sobrien		tgrp = grp;
64379968Sobrien		grp = grp->gr_next;
64479968Sobrien		free_grp(tgrp);
64579968Sobrien	}
64679968Sobrien	grphead = (struct grouplist *)NULL;
64779968Sobrien
64879968Sobrien	/*
64979968Sobrien	 * And delete exports that are in the kernel for all local
65079968Sobrien	 * file systems.
65179968Sobrien	 * XXX: Should know how to handle all local exportable file systems
65279968Sobrien	 *      instead of just MOUNT_UFS.
65379968Sobrien	 */
65479968Sobrien	num = getmntinfo(&fsp, MNT_NOWAIT);
65579968Sobrien	for (i = 0; i < num; i++) {
65679968Sobrien		union {
65779968Sobrien			struct ufs_args ua;
65879968Sobrien			struct iso_args ia;
65979968Sobrien			struct mfs_args ma;
66079968Sobrien		} targs;
66179968Sobrien
66279968Sobrien		switch (fsp->f_type) {
66379968Sobrien		case MOUNT_MFS:
66479968Sobrien		case MOUNT_UFS:
66579968Sobrien		case MOUNT_CD9660:
66679968Sobrien		case MOUNT_MSDOS:
66779968Sobrien			targs.ua.fspec = NULL;
66879968Sobrien			targs.ua.export.ex_flags = MNT_DELEXPORT;
66979968Sobrien			if (mount(fsp->f_type, fsp->f_mntonname,
67079968Sobrien				  fsp->f_flags | MNT_UPDATE,
67179968Sobrien				  (caddr_t)&targs) < 0)
67279968Sobrien				syslog(LOG_ERR, "Can't delete exports for %s",
67379968Sobrien				       fsp->f_mntonname);
67479968Sobrien		}
67579968Sobrien		fsp++;
67679968Sobrien	}
67779968Sobrien
67879968Sobrien	/*
67979968Sobrien	 * Read in the exports file and build the list, calling
68079968Sobrien	 * mount() as we go along to push the export rules into the kernel.
68179968Sobrien	 */
68279968Sobrien	if ((exp_file = fopen(exname, "r")) == NULL) {
68379968Sobrien		syslog(LOG_ERR, "Can't open %s", exname);
68479968Sobrien		exit(2);
68579968Sobrien	}
68679968Sobrien	dirhead = (struct dirlist *)NULL;
68779968Sobrien	while (get_line()) {
68879968Sobrien		if (debug)
68979968Sobrien			fprintf(stderr,"Got line %s\n",line);
69079968Sobrien		cp = line;
69179968Sobrien		nextfield(&cp, &endcp);
69279968Sobrien		if (*cp == '#')
69379968Sobrien			goto nextline;
69479968Sobrien
69579968Sobrien		/*
69679968Sobrien		 * Set defaults.
69779968Sobrien		 */
69879968Sobrien		has_host = FALSE;
69979968Sobrien		anon = def_anon;
70079968Sobrien		exflags = MNT_EXPORTED;
70179968Sobrien		got_nondir = 0;
70279968Sobrien		opt_flags = 0;
70379968Sobrien		ep = (struct exportlist *)NULL;
70479968Sobrien
70579968Sobrien		/*
70679968Sobrien		 * Create new exports list entry
70779968Sobrien		 */
70879968Sobrien		len = endcp-cp;
70979968Sobrien		tgrp = grp = get_grp();
71079968Sobrien		while (len > 0) {
71179968Sobrien			if (len > RPCMNT_NAMELEN) {
71279968Sobrien			    getexp_err(ep, tgrp);
71379968Sobrien			    goto nextline;
71479968Sobrien			}
71579968Sobrien			if (*cp == '-') {
71679968Sobrien			    if (ep == (struct exportlist *)NULL) {
71779968Sobrien				getexp_err(ep, tgrp);
71879968Sobrien				goto nextline;
71979968Sobrien			    }
72079968Sobrien			    if (debug)
72179968Sobrien				fprintf(stderr, "doing opt %s\n", cp);
72279968Sobrien			    got_nondir = 1;
72379968Sobrien			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
72479968Sobrien				&exflags, &anon)) {
72579968Sobrien				getexp_err(ep, tgrp);
72679968Sobrien				goto nextline;
72779968Sobrien			    }
72879968Sobrien			} else if (*cp == '/') {
72979968Sobrien			    savedc = *endcp;
73079968Sobrien			    *endcp = '\0';
73179968Sobrien			    if (check_dirpath(cp) &&
73279968Sobrien				statfs(cp, &fsb) >= 0) {
73379968Sobrien				if (got_nondir) {
73479968Sobrien				    syslog(LOG_ERR, "Dirs must be first");
73579968Sobrien				    getexp_err(ep, tgrp);
73679968Sobrien				    goto nextline;
73779968Sobrien				}
73879968Sobrien				if (ep) {
73979968Sobrien				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
74079968Sobrien					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
74179968Sobrien					getexp_err(ep, tgrp);
74279968Sobrien					goto nextline;
74379968Sobrien				    }
74479968Sobrien				} else {
74592282Sobrien				    /*
74692282Sobrien				     * See if this directory is already
74792282Sobrien				     * in the list.
74892282Sobrien				     */
74992282Sobrien				    ep = ex_search(&fsb.f_fsid);
75092282Sobrien				    if (ep == (struct exportlist *)NULL) {
75192282Sobrien					ep = get_exp();
75292282Sobrien					ep->ex_fs = fsb.f_fsid;
75379968Sobrien					ep->ex_fsdir = (char *)
75492282Sobrien					    malloc(strlen(fsb.f_mntonname) + 1);
75579968Sobrien					if (ep->ex_fsdir)
75679968Sobrien					    strcpy(ep->ex_fsdir,
75779968Sobrien						fsb.f_mntonname);
75879968Sobrien					else
75979968Sobrien					    out_of_mem();
76079968Sobrien					if (debug)
76179968Sobrien					  fprintf(stderr,
76279968Sobrien					      "Making new ep fs=0x%x,0x%x\n",
76379968Sobrien					      fsb.f_fsid.val[0],
76479968Sobrien					      fsb.f_fsid.val[1]);
76579968Sobrien				    } else if (debug)
76679968Sobrien					fprintf(stderr,
76779968Sobrien					    "Found ep fs=0x%x,0x%x\n",
76879968Sobrien					    fsb.f_fsid.val[0],
76979968Sobrien					    fsb.f_fsid.val[1]);
77079968Sobrien				}
77179968Sobrien
77279968Sobrien				/*
77379968Sobrien				 * Add dirpath to export mount point.
77479968Sobrien				 */
77579968Sobrien				dirp = add_expdir(&dirhead, cp, len);
77679968Sobrien				dirplen = len;
77779968Sobrien			    } else {
77879968Sobrien				getexp_err(ep, tgrp);
77979968Sobrien				goto nextline;
78079968Sobrien			    }
78179968Sobrien			    *endcp = savedc;
78279968Sobrien			} else {
78379968Sobrien			    savedc = *endcp;
78479968Sobrien			    *endcp = '\0';
78579968Sobrien			    got_nondir = 1;
78679968Sobrien			    if (ep == (struct exportlist *)NULL) {
78779968Sobrien				getexp_err(ep, tgrp);
78879968Sobrien				goto nextline;
78979968Sobrien			    }
79079968Sobrien
79179968Sobrien			    /*
79279968Sobrien			     * Get the host or netgroup.
79379968Sobrien			     */
79479968Sobrien			    setnetgrent(cp);
79579968Sobrien			    netgrp = getnetgrent(&hst, &usr, &dom);
79679968Sobrien			    do {
79779968Sobrien				if (has_host) {
79879968Sobrien				    grp->gr_next = get_grp();
79979968Sobrien				    grp = grp->gr_next;
80079968Sobrien				}
80179968Sobrien				if (netgrp) {
80279968Sobrien				    if (get_host(hst, grp, tgrp)) {
80379968Sobrien					syslog(LOG_ERR, "Bad netgroup %s", cp);
80479968Sobrien					getexp_err(ep, tgrp);
80579968Sobrien					goto nextline;
80679968Sobrien				    }
80779968Sobrien				} else if (get_host(cp, grp, tgrp)) {
80879968Sobrien				    getexp_err(ep, tgrp);
80992282Sobrien				    goto nextline;
810133936Sobrien				}
81179968Sobrien				has_host = TRUE;
81279968Sobrien			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
81379968Sobrien			    endnetgrent();
81479968Sobrien			    *endcp = savedc;
81579968Sobrien			}
81692282Sobrien			cp = endcp;
81792282Sobrien			nextfield(&cp, &endcp);
81892282Sobrien			len = endcp - cp;
81992282Sobrien		}
82092282Sobrien		if (check_options(dirhead)) {
82192282Sobrien			getexp_err(ep, tgrp);
82292282Sobrien			goto nextline;
82392282Sobrien		}
82492282Sobrien		if (!has_host) {
82592282Sobrien			grp->gr_type = GT_HOST;
82679968Sobrien			if (debug)
82779968Sobrien				fprintf(stderr,"Adding a default entry\n");
82879968Sobrien			/* add a default group and make the grp list NULL */
82979968Sobrien			hpe = (struct hostent *)malloc(sizeof(struct hostent));
83079968Sobrien			if (hpe == (struct hostent *)NULL)
83179968Sobrien				out_of_mem();
83279968Sobrien			hpe->h_name = "Default";
83379968Sobrien			hpe->h_addrtype = AF_INET;
83479968Sobrien			hpe->h_length = sizeof (u_long);
83579968Sobrien			hpe->h_addr_list = (char **)NULL;
83679968Sobrien			grp->gr_ptr.gt_hostent = hpe;
83779968Sobrien
83879968Sobrien		/*
83979968Sobrien		 * Don't allow a network export coincide with a list of
84079968Sobrien		 * host(s) on the same line.
84179968Sobrien		 */
84279968Sobrien		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
84379968Sobrien			getexp_err(ep, tgrp);
84479968Sobrien			goto nextline;
84579968Sobrien		}
84679968Sobrien
84779968Sobrien		/*
84879968Sobrien		 * Loop through hosts, pushing the exports into the kernel.
84979968Sobrien		 * After loop, tgrp points to the start of the list and
85079968Sobrien		 * grp points to the last entry in the list.
851110242Sobrien		 */
852110242Sobrien		grp = tgrp;
853110242Sobrien		do {
854110242Sobrien		    if (do_mount(ep, grp, exflags, &anon, dirp,
855110242Sobrien			dirplen, &fsb)) {
856110242Sobrien			getexp_err(ep, tgrp);
857110242Sobrien			goto nextline;
858110242Sobrien		    }
859110242Sobrien		} while (grp->gr_next && (grp = grp->gr_next));
860110242Sobrien
861110242Sobrien		/*
862110242Sobrien		 * Success. Update the data structures.
863110242Sobrien		 */
864110242Sobrien		if (has_host) {
865110242Sobrien			hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
866110242Sobrien			grp->gr_next = grphead;
867110242Sobrien			grphead = tgrp;
868110242Sobrien		} else {
869110242Sobrien			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
870110242Sobrien			(opt_flags & OP_ALLDIRS));
871110242Sobrien			free_grp(grp);
872110242Sobrien		}
873110242Sobrien		dirhead = (struct dirlist *)NULL;
874110242Sobrien		if ((ep->ex_flag & EX_LINKED) == 0) {
875110242Sobrien			ep2 = exphead;
876110242Sobrien			epp = &exphead;
877110242Sobrien
878110242Sobrien			/*
879110242Sobrien			 * Insert in the list in alphabetical order.
880110242Sobrien			 */
881110242Sobrien			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
882110242Sobrien				epp = &ep2->ex_next;
883110242Sobrien				ep2 = ep2->ex_next;
884110242Sobrien			}
885110242Sobrien			if (ep2)
886110242Sobrien				ep->ex_next = ep2;
887110242Sobrien			*epp = ep;
888110242Sobrien			ep->ex_flag |= EX_LINKED;
889110242Sobrien		}
890110242Sobriennextline:
891110242Sobrien		if (dirhead) {
892110242Sobrien			free_dir(dirhead);
893110242Sobrien			dirhead = (struct dirlist *)NULL;
894110242Sobrien		}
895110242Sobrien	}
896110242Sobrien	fclose(exp_file);
897110242Sobrien}
898110242Sobrien
899110242Sobrien/*
900110242Sobrien * Allocate an export list element
901110242Sobrien */
902110242Sobrienstruct exportlist *
903110242Sobrienget_exp()
904110242Sobrien{
905110242Sobrien	struct exportlist *ep;
906110242Sobrien
907110242Sobrien	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
908110242Sobrien	if (ep == (struct exportlist *)NULL)
909110242Sobrien		out_of_mem();
910110242Sobrien	bzero((caddr_t)ep, sizeof (struct exportlist));
911110242Sobrien	return (ep);
912110242Sobrien}
913110242Sobrien
914110242Sobrien/*
915110242Sobrien * Allocate a group list element
916110242Sobrien */
917110242Sobrienstruct grouplist *
918110242Sobrienget_grp()
919110242Sobrien{
920110242Sobrien	struct grouplist *gp;
921110242Sobrien
922110242Sobrien	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
923110242Sobrien	if (gp == (struct grouplist *)NULL)
924110242Sobrien		out_of_mem();
925110242Sobrien	bzero((caddr_t)gp, sizeof (struct grouplist));
926110242Sobrien	return (gp);
927110242Sobrien}
928110242Sobrien
929110242Sobrien/*
930110242Sobrien * Clean up upon an error in get_exportlist().
931110242Sobrien */
932110242Sobrienvoid
933110242Sobriengetexp_err(ep, grp)
934110242Sobrien	struct exportlist *ep;
935110242Sobrien	struct grouplist *grp;
936110242Sobrien{
937110242Sobrien	struct grouplist *tgrp;
938110242Sobrien
939110242Sobrien	syslog(LOG_ERR, "Bad exports list line %s", line);
940110242Sobrien	if (ep && (ep->ex_flag & EX_LINKED) == 0)
941110242Sobrien		free_exp(ep);
942110242Sobrien	while (grp) {
943110242Sobrien		tgrp = grp;
944110242Sobrien		grp = grp->gr_next;
945110242Sobrien		free_grp(tgrp);
946110242Sobrien	}
947110242Sobrien}
948110242Sobrien
949110242Sobrien/*
950110242Sobrien * Search the export list for a matching fs.
951110242Sobrien */
952110242Sobrienstruct exportlist *
953110242Sobrienex_search(fsid)
954110242Sobrien	fsid_t *fsid;
955110242Sobrien{
956110242Sobrien	struct exportlist *ep;
957110242Sobrien
958110242Sobrien	ep = exphead;
959110242Sobrien	while (ep) {
960110242Sobrien		if (ep->ex_fs.val[0] == fsid->val[0] &&
961110242Sobrien		    ep->ex_fs.val[1] == fsid->val[1])
962110242Sobrien			return (ep);
963110242Sobrien		ep = ep->ex_next;
964110242Sobrien	}
965110242Sobrien	return (ep);
966110242Sobrien}
967110242Sobrien
968110242Sobrien/*
969110242Sobrien * Add a directory path to the list.
970110242Sobrien */
971110242Sobrienchar *
972110242Sobrienadd_expdir(dpp, cp, len)
973110242Sobrien	struct dirlist **dpp;
974	char *cp;
975	int len;
976{
977	struct dirlist *dp;
978
979	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
980	dp->dp_left = *dpp;
981	dp->dp_right = (struct dirlist *)NULL;
982	dp->dp_flag = 0;
983	dp->dp_hosts = (struct hostlist *)NULL;
984	strcpy(dp->dp_dirp, cp);
985	*dpp = dp;
986	return (dp->dp_dirp);
987}
988
989/*
990 * Hang the dir list element off the dirpath binary tree as required
991 * and update the entry for host.
992 */
993void
994hang_dirp(dp, grp, ep, alldirs)
995	struct dirlist *dp;
996	struct grouplist *grp;
997	struct exportlist *ep;
998	int alldirs;
999{
1000	struct hostlist *hp;
1001	struct dirlist *dp2;
1002
1003	if (alldirs) {
1004		if (ep->ex_defdir)
1005			free((caddr_t)dp);
1006		else
1007			ep->ex_defdir = dp;
1008		if (grp == (struct grouplist *)NULL)
1009			ep->ex_defdir->dp_flag |= DP_DEFSET;
1010		else while (grp) {
1011			hp = get_ht();
1012			hp->ht_grp = grp;
1013			hp->ht_next = ep->ex_defdir->dp_hosts;
1014			ep->ex_defdir->dp_hosts = hp;
1015			grp = grp->gr_next;
1016		}
1017	} else {
1018
1019		/*
1020		 * Loop throught the directories adding them to the tree.
1021		 */
1022		while (dp) {
1023			dp2 = dp->dp_left;
1024			add_dlist(&ep->ex_dirl, dp, grp);
1025			dp = dp2;
1026		}
1027	}
1028}
1029
1030/*
1031 * Traverse the binary tree either updating a node that is already there
1032 * for the new directory or adding the new node.
1033 */
1034void
1035add_dlist(dpp, newdp, grp)
1036	struct dirlist **dpp;
1037	struct dirlist *newdp;
1038	struct grouplist *grp;
1039{
1040	struct dirlist *dp;
1041	struct hostlist *hp;
1042	int cmp;
1043
1044	dp = *dpp;
1045	if (dp) {
1046		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1047		if (cmp > 0) {
1048			add_dlist(&dp->dp_left, newdp, grp);
1049			return;
1050		} else if (cmp < 0) {
1051			add_dlist(&dp->dp_right, newdp, grp);
1052			return;
1053		} else
1054			free((caddr_t)newdp);
1055	} else {
1056		dp = newdp;
1057		dp->dp_left = (struct dirlist *)NULL;
1058		*dpp = dp;
1059	}
1060	if (grp) {
1061
1062		/*
1063		 * Hang all of the host(s) off of the directory point.
1064		 */
1065		do {
1066			hp = get_ht();
1067			hp->ht_grp = grp;
1068			hp->ht_next = dp->dp_hosts;
1069			dp->dp_hosts = hp;
1070			grp = grp->gr_next;
1071		} while (grp);
1072	} else
1073		dp->dp_flag |= DP_DEFSET;
1074}
1075
1076/*
1077 * Search for a dirpath on the export point.
1078 */
1079struct dirlist *
1080dirp_search(dp, dirpath)
1081	struct dirlist *dp;
1082	char *dirpath;
1083{
1084	int cmp;
1085
1086	if (dp) {
1087		cmp = strcmp(dp->dp_dirp, dirpath);
1088		if (cmp > 0)
1089			return (dirp_search(dp->dp_left, dirpath));
1090		else if (cmp < 0)
1091			return (dirp_search(dp->dp_right, dirpath));
1092		else
1093			return (dp);
1094	}
1095	return (dp);
1096}
1097
1098/*
1099 * Scan for a host match in a directory tree.
1100 */
1101int
1102chk_host(dp, saddr, defsetp)
1103	struct dirlist *dp;
1104	u_long saddr;
1105	int *defsetp;
1106{
1107	struct hostlist *hp;
1108	struct grouplist *grp;
1109	u_long **addrp;
1110
1111	if (dp) {
1112		if (dp->dp_flag & DP_DEFSET)
1113			*defsetp = 1;
1114		hp = dp->dp_hosts;
1115		while (hp) {
1116			grp = hp->ht_grp;
1117			switch (grp->gr_type) {
1118			case GT_HOST:
1119			    addrp = (u_long **)
1120				grp->gr_ptr.gt_hostent->h_addr_list;
1121			    while (*addrp) {
1122				if (**addrp == saddr)
1123				    return (1);
1124				addrp++;
1125			    }
1126			    break;
1127			case GT_NET:
1128			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1129				grp->gr_ptr.gt_net.nt_net)
1130				return (1);
1131			    break;
1132			};
1133			hp = hp->ht_next;
1134		}
1135	}
1136	return (0);
1137}
1138
1139/*
1140 * Scan tree for a host that matches the address.
1141 */
1142int
1143scan_tree(dp, saddr)
1144	struct dirlist *dp;
1145	u_long saddr;
1146{
1147	int defset;
1148
1149	if (dp) {
1150		if (scan_tree(dp->dp_left, saddr))
1151			return (1);
1152		if (chk_host(dp, saddr, &defset))
1153			return (1);
1154		if (scan_tree(dp->dp_right, saddr))
1155			return (1);
1156	}
1157	return (0);
1158}
1159
1160/*
1161 * Traverse the dirlist tree and free it up.
1162 */
1163void
1164free_dir(dp)
1165	struct dirlist *dp;
1166{
1167
1168	if (dp) {
1169		free_dir(dp->dp_left);
1170		free_dir(dp->dp_right);
1171		free_host(dp->dp_hosts);
1172		free((caddr_t)dp);
1173	}
1174}
1175
1176/*
1177 * Parse the option string and update fields.
1178 * Option arguments may either be -<option>=<value> or
1179 * -<option> <value>
1180 */
1181int
1182do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1183	char **cpp, **endcpp;
1184	struct exportlist *ep;
1185	struct grouplist *grp;
1186	int *has_hostp;
1187	int *exflagsp;
1188	struct ucred *cr;
1189{
1190	char *cpoptarg, *cpoptend;
1191	char *cp, *endcp, *cpopt, savedc, savedc2;
1192	int allflag, usedarg;
1193
1194	cpopt = *cpp;
1195	cpopt++;
1196	cp = *endcpp;
1197	savedc = *cp;
1198	*cp = '\0';
1199	while (cpopt && *cpopt) {
1200		allflag = 1;
1201		usedarg = -2;
1202		if (cpoptend = index(cpopt, ',')) {
1203			*cpoptend++ = '\0';
1204			if (cpoptarg = index(cpopt, '='))
1205				*cpoptarg++ = '\0';
1206		} else {
1207			if (cpoptarg = index(cpopt, '='))
1208				*cpoptarg++ = '\0';
1209			else {
1210				*cp = savedc;
1211				nextfield(&cp, &endcp);
1212				**endcpp = '\0';
1213				if (endcp > cp && *cp != '-') {
1214					cpoptarg = cp;
1215					savedc2 = *endcp;
1216					*endcp = '\0';
1217					usedarg = 0;
1218				}
1219			}
1220		}
1221		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1222			*exflagsp |= MNT_EXRDONLY;
1223		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1224		    !(allflag = strcmp(cpopt, "mapall")) ||
1225		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1226			usedarg++;
1227			parsecred(cpoptarg, cr);
1228			if (allflag == 0) {
1229				*exflagsp |= MNT_EXPORTANON;
1230				opt_flags |= OP_MAPALL;
1231			} else
1232				opt_flags |= OP_MAPROOT;
1233		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1234			*exflagsp |= MNT_EXKERB;
1235			opt_flags |= OP_KERB;
1236		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1237			!strcmp(cpopt, "m"))) {
1238			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1239				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1240				return (1);
1241			}
1242			usedarg++;
1243			opt_flags |= OP_MASK;
1244		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
1245			!strcmp(cpopt, "n"))) {
1246			if (grp->gr_type != GT_NULL) {
1247				syslog(LOG_ERR, "Network/host conflict");
1248				return (1);
1249			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1250				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1251				return (1);
1252			}
1253			grp->gr_type = GT_NET;
1254			*has_hostp = 1;
1255			usedarg++;
1256			opt_flags |= OP_NET;
1257		} else if (!strcmp(cpopt, "alldirs")) {
1258			opt_flags |= OP_ALLDIRS;
1259#ifdef ISO
1260		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1261			if (get_isoaddr(cpoptarg, grp)) {
1262				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1263				return (1);
1264			}
1265			*has_hostp = 1;
1266			usedarg++;
1267			opt_flags |= OP_ISO;
1268#endif /* ISO */
1269		} else {
1270			syslog(LOG_ERR, "Bad opt %s", cpopt);
1271			return (1);
1272		}
1273		if (usedarg >= 0) {
1274			*endcp = savedc2;
1275			**endcpp = savedc;
1276			if (usedarg > 0) {
1277				*cpp = cp;
1278				*endcpp = endcp;
1279			}
1280			return (0);
1281		}
1282		cpopt = cpoptend;
1283	}
1284	**endcpp = savedc;
1285	return (0);
1286}
1287
1288/*
1289 * Translate a character string to the corresponding list of network
1290 * addresses for a hostname.
1291 */
1292int
1293get_host(cp, grp, tgrp)
1294	char *cp;
1295	struct grouplist *grp;
1296	struct grouplist *tgrp;
1297{
1298	struct grouplist *checkgrp;
1299	struct hostent *hp, *nhp;
1300	char **addrp, **naddrp;
1301	struct hostent t_host;
1302	int i;
1303	u_long saddr;
1304	char *aptr[2];
1305
1306	if (grp->gr_type != GT_NULL)
1307		return (1);
1308	if ((hp = gethostbyname(cp)) == NULL) {
1309		if (isdigit(*cp)) {
1310			saddr = inet_addr(cp);
1311			if (saddr == -1) {
1312				syslog(LOG_ERR, "Inet_addr failed");
1313				return (1);
1314			}
1315			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1316				AF_INET)) == NULL) {
1317				hp = &t_host;
1318				hp->h_name = cp;
1319				hp->h_addrtype = AF_INET;
1320				hp->h_length = sizeof (u_long);
1321				hp->h_addr_list = aptr;
1322				aptr[0] = (char *)&saddr;
1323				aptr[1] = (char *)NULL;
1324			}
1325		} else {
1326			syslog(LOG_ERR, "Gethostbyname failed");
1327			return (1);
1328		}
1329	}
1330        /*
1331         * Sanity check: make sure we don't already have an entry
1332         * for this host in the grouplist.
1333         */
1334        checkgrp = tgrp;
1335        while (checkgrp) {
1336                if (checkgrp->gr_ptr.gt_hostent != NULL &&
1337                    !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) {
1338                        grp->gr_type = GT_IGNORE;
1339			return(0);
1340		}
1341                checkgrp = checkgrp->gr_next;
1342        }
1343
1344	grp->gr_type = GT_HOST;
1345	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1346		malloc(sizeof(struct hostent));
1347	if (nhp == (struct hostent *)NULL)
1348		out_of_mem();
1349	bcopy((caddr_t)hp, (caddr_t)nhp,
1350		sizeof(struct hostent));
1351	i = strlen(hp->h_name)+1;
1352	nhp->h_name = (char *)malloc(i);
1353	if (nhp->h_name == (char *)NULL)
1354		out_of_mem();
1355	bcopy(hp->h_name, nhp->h_name, i);
1356	addrp = hp->h_addr_list;
1357	i = 1;
1358	while (*addrp++)
1359		i++;
1360	naddrp = nhp->h_addr_list = (char **)
1361		malloc(i*sizeof(char *));
1362	if (naddrp == (char **)NULL)
1363		out_of_mem();
1364	addrp = hp->h_addr_list;
1365	while (*addrp) {
1366		*naddrp = (char *)
1367		    malloc(hp->h_length);
1368		if (*naddrp == (char *)NULL)
1369		    out_of_mem();
1370		bcopy(*addrp, *naddrp,
1371			hp->h_length);
1372		addrp++;
1373		naddrp++;
1374	}
1375	*naddrp = (char *)NULL;
1376	if (debug)
1377		fprintf(stderr, "got host %s\n", hp->h_name);
1378	return (0);
1379}
1380
1381/*
1382 * Free up an exports list component
1383 */
1384void
1385free_exp(ep)
1386	struct exportlist *ep;
1387{
1388
1389	if (ep->ex_defdir) {
1390		free_host(ep->ex_defdir->dp_hosts);
1391		free((caddr_t)ep->ex_defdir);
1392	}
1393	if (ep->ex_fsdir)
1394		free(ep->ex_fsdir);
1395	free_dir(ep->ex_dirl);
1396	free((caddr_t)ep);
1397}
1398
1399/*
1400 * Free hosts.
1401 */
1402void
1403free_host(hp)
1404	struct hostlist *hp;
1405{
1406	struct hostlist *hp2;
1407
1408	while (hp) {
1409		hp2 = hp;
1410		hp = hp->ht_next;
1411		free((caddr_t)hp2);
1412	}
1413}
1414
1415struct hostlist *
1416get_ht()
1417{
1418	struct hostlist *hp;
1419
1420	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1421	if (hp == (struct hostlist *)NULL)
1422		out_of_mem();
1423	hp->ht_next = (struct hostlist *)NULL;
1424	return (hp);
1425}
1426
1427#ifdef ISO
1428/*
1429 * Translate an iso address.
1430 */
1431get_isoaddr(cp, grp)
1432	char *cp;
1433	struct grouplist *grp;
1434{
1435	struct iso_addr *isop;
1436	struct sockaddr_iso *isoaddr;
1437
1438	if (grp->gr_type != GT_NULL)
1439		return (1);
1440	if ((isop = iso_addr(cp)) == NULL) {
1441		syslog(LOG_ERR,
1442		    "iso_addr failed, ignored");
1443		return (1);
1444	}
1445	isoaddr = (struct sockaddr_iso *)
1446	    malloc(sizeof (struct sockaddr_iso));
1447	if (isoaddr == (struct sockaddr_iso *)NULL)
1448		out_of_mem();
1449	bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1450	bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
1451		sizeof (struct iso_addr));
1452	isoaddr->siso_len = sizeof (struct sockaddr_iso);
1453	isoaddr->siso_family = AF_ISO;
1454	grp->gr_type = GT_ISO;
1455	grp->gr_ptr.gt_isoaddr = isoaddr;
1456	return (0);
1457}
1458#endif	/* ISO */
1459
1460/*
1461 * Out of memory, fatal
1462 */
1463void
1464out_of_mem()
1465{
1466
1467	syslog(LOG_ERR, "Out of memory");
1468	exit(2);
1469}
1470
1471/*
1472 * Do the mount syscall with the update flag to push the export info into
1473 * the kernel.
1474 */
1475int
1476do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1477	struct exportlist *ep;
1478	struct grouplist *grp;
1479	int exflags;
1480	struct ucred *anoncrp;
1481	char *dirp;
1482	int dirplen;
1483	struct statfs *fsb;
1484{
1485	char *cp = (char *)NULL;
1486	u_long **addrp;
1487	int done;
1488	char savedc = '\0';
1489	struct sockaddr_in sin, imask;
1490	union {
1491		struct ufs_args ua;
1492		struct iso_args ia;
1493		struct mfs_args ma;
1494	} args;
1495	u_long net;
1496
1497	args.ua.fspec = 0;
1498	args.ua.export.ex_flags = exflags;
1499	args.ua.export.ex_anon = *anoncrp;
1500	bzero((char *)&sin, sizeof(sin));
1501	bzero((char *)&imask, sizeof(imask));
1502	sin.sin_family = AF_INET;
1503	sin.sin_len = sizeof(sin);
1504	imask.sin_family = AF_INET;
1505	imask.sin_len = sizeof(sin);
1506	if (grp->gr_type == GT_HOST)
1507		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1508	else
1509		addrp = (u_long **)NULL;
1510	done = FALSE;
1511	while (!done) {
1512		switch (grp->gr_type) {
1513		case GT_HOST:
1514			if (addrp) {
1515				sin.sin_addr.s_addr = **addrp;
1516				args.ua.export.ex_addrlen = sizeof(sin);
1517			} else
1518				args.ua.export.ex_addrlen = 0;
1519			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1520			args.ua.export.ex_masklen = 0;
1521			break;
1522		case GT_NET:
1523			if (grp->gr_ptr.gt_net.nt_mask)
1524			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1525			else {
1526			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1527			    if (IN_CLASSA(net))
1528				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1529			    else if (IN_CLASSB(net))
1530				imask.sin_addr.s_addr =
1531				    inet_addr("255.255.0.0");
1532			    else
1533				imask.sin_addr.s_addr =
1534				    inet_addr("255.255.255.0");
1535			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1536			}
1537			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1538			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1539			args.ua.export.ex_addrlen = sizeof (sin);
1540			args.ua.export.ex_mask = (struct sockaddr *)&imask;
1541			args.ua.export.ex_masklen = sizeof (imask);
1542			break;
1543#ifdef ISO
1544		case GT_ISO:
1545			args.ua.export.ex_addr =
1546				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1547			args.ua.export.ex_addrlen =
1548				sizeof(struct sockaddr_iso);
1549			args.ua.export.ex_masklen = 0;
1550			break;
1551#endif	/* ISO */
1552		case GT_IGNORE:
1553			return(0);
1554			break;
1555		default:
1556			syslog(LOG_ERR, "Bad grouptype");
1557			if (cp)
1558				*cp = savedc;
1559			return (1);
1560		};
1561
1562		/*
1563		 * XXX:
1564		 * Maybe I should just use the fsb->f_mntonname path instead
1565		 * of looping back up the dirp to the mount point??
1566		 * Also, needs to know how to export all types of local
1567		 * exportable file systems and not just MOUNT_UFS.
1568		 */
1569		while (mount(fsb->f_type, dirp,
1570		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1571			if (cp)
1572				*cp-- = savedc;
1573			else
1574				cp = dirp + dirplen - 1;
1575			if (errno == EPERM) {
1576				syslog(LOG_ERR,
1577				   "Can't change attributes for %s.\n", dirp);
1578				return (1);
1579			}
1580			if (opt_flags & OP_ALLDIRS) {
1581				syslog(LOG_ERR, "Could not remount %s: %m",
1582					dirp);
1583				return (1);
1584			}
1585			/* back up over the last component */
1586			while (*cp == '/' && cp > dirp)
1587				cp--;
1588			while (*(cp - 1) != '/' && cp > dirp)
1589				cp--;
1590			if (cp == dirp) {
1591				if (debug)
1592					fprintf(stderr,"mnt unsucc\n");
1593				syslog(LOG_ERR, "Can't export %s", dirp);
1594				return (1);
1595			}
1596			savedc = *cp;
1597			*cp = '\0';
1598		}
1599		if (addrp) {
1600			++addrp;
1601			if (*addrp == (u_long *)NULL)
1602				done = TRUE;
1603		} else
1604			done = TRUE;
1605	}
1606	if (cp)
1607		*cp = savedc;
1608	return (0);
1609}
1610
1611/*
1612 * Translate a net address.
1613 */
1614int
1615get_net(cp, net, maskflg)
1616	char *cp;
1617	struct netmsk *net;
1618	int maskflg;
1619{
1620	struct netent *np;
1621	long netaddr;
1622	struct in_addr inetaddr, inetaddr2;
1623	char *name;
1624
1625	if (np = getnetbyname(cp))
1626		inetaddr = inet_makeaddr(np->n_net, 0);
1627	else if (isdigit(*cp)) {
1628		if ((netaddr = inet_network(cp)) == -1)
1629			return (1);
1630		inetaddr = inet_makeaddr(netaddr, 0);
1631		/*
1632		 * Due to arbritrary subnet masks, you don't know how many
1633		 * bits to shift the address to make it into a network,
1634		 * however you do know how to make a network address into
1635		 * a host with host == 0 and then compare them.
1636		 * (What a pest)
1637		 */
1638		if (!maskflg) {
1639			setnetent(0);
1640			while (np = getnetent()) {
1641				inetaddr2 = inet_makeaddr(np->n_net, 0);
1642				if (inetaddr2.s_addr == inetaddr.s_addr)
1643					break;
1644			}
1645			endnetent();
1646		}
1647	} else
1648		return (1);
1649	if (maskflg)
1650		net->nt_mask = inetaddr.s_addr;
1651	else {
1652		if (np)
1653			name = np->n_name;
1654		else
1655			name = inet_ntoa(inetaddr);
1656		net->nt_name = (char *)malloc(strlen(name) + 1);
1657		if (net->nt_name == (char *)NULL)
1658			out_of_mem();
1659		strcpy(net->nt_name, name);
1660		net->nt_net = inetaddr.s_addr;
1661	}
1662	return (0);
1663}
1664
1665/*
1666 * Parse out the next white space separated field
1667 */
1668void
1669nextfield(cp, endcp)
1670	char **cp;
1671	char **endcp;
1672{
1673	char *p;
1674
1675	p = *cp;
1676	while (*p == ' ' || *p == '\t')
1677		p++;
1678	if (*p == '\n' || *p == '\0')
1679		*cp = *endcp = p;
1680	else {
1681		*cp = p++;
1682		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1683			p++;
1684		*endcp = p;
1685	}
1686}
1687
1688/*
1689 * Get an exports file line. Skip over blank lines and handle line
1690 * continuations.
1691 */
1692int
1693get_line()
1694{
1695	char *p, *cp;
1696	int len;
1697	int totlen, cont_line;
1698
1699	/*
1700	 * Loop around ignoring blank lines and getting all continuation lines.
1701	 */
1702	p = line;
1703	totlen = 0;
1704	do {
1705		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1706			return (0);
1707		len = strlen(p);
1708		cp = p + len - 1;
1709		cont_line = 0;
1710		while (cp >= p &&
1711		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1712			if (*cp == '\\')
1713				cont_line = 1;
1714			cp--;
1715			len--;
1716		}
1717		*++cp = '\0';
1718		if (len > 0) {
1719			totlen += len;
1720			if (totlen >= LINESIZ) {
1721				syslog(LOG_ERR, "Exports line too long");
1722				exit(2);
1723			}
1724			p = cp;
1725		}
1726	} while (totlen == 0 || cont_line);
1727	return (1);
1728}
1729
1730/*
1731 * Parse a description of a credential.
1732 */
1733void
1734parsecred(namelist, cr)
1735	char *namelist;
1736	struct ucred *cr;
1737{
1738	char *name;
1739	int cnt;
1740	char *names;
1741	struct passwd *pw;
1742	struct group *gr;
1743	int ngroups, groups[NGROUPS + 1];
1744
1745	/*
1746	 * Set up the unpriviledged user.
1747	 */
1748	cr->cr_ref = 1;
1749	cr->cr_uid = -2;
1750	cr->cr_groups[0] = -2;
1751	cr->cr_ngroups = 1;
1752	/*
1753	 * Get the user's password table entry.
1754	 */
1755	names = strsep(&namelist, " \t\n");
1756	name = strsep(&names, ":");
1757	if (isdigit(*name) || *name == '-')
1758		pw = getpwuid(atoi(name));
1759	else
1760		pw = getpwnam(name);
1761	/*
1762	 * Credentials specified as those of a user.
1763	 */
1764	if (names == NULL) {
1765		if (pw == NULL) {
1766			syslog(LOG_ERR, "Unknown user: %s", name);
1767			return;
1768		}
1769		cr->cr_uid = pw->pw_uid;
1770		ngroups = NGROUPS + 1;
1771		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1772			syslog(LOG_ERR, "Too many groups");
1773		/*
1774		 * Convert from int's to gid_t's and compress out duplicate
1775		 */
1776		cr->cr_ngroups = ngroups - 1;
1777		cr->cr_groups[0] = groups[0];
1778		for (cnt = 2; cnt < ngroups; cnt++)
1779			cr->cr_groups[cnt - 1] = groups[cnt];
1780		return;
1781	}
1782	/*
1783	 * Explicit credential specified as a colon separated list:
1784	 *	uid:gid:gid:...
1785	 */
1786	if (pw != NULL)
1787		cr->cr_uid = pw->pw_uid;
1788	else if (isdigit(*name) || *name == '-')
1789		cr->cr_uid = atoi(name);
1790	else {
1791		syslog(LOG_ERR, "Unknown user: %s", name);
1792		return;
1793	}
1794	cr->cr_ngroups = 0;
1795	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1796		name = strsep(&names, ":");
1797		if (isdigit(*name) || *name == '-') {
1798			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1799		} else {
1800			if ((gr = getgrnam(name)) == NULL) {
1801				syslog(LOG_ERR, "Unknown group: %s", name);
1802				continue;
1803			}
1804			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1805		}
1806	}
1807	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1808		syslog(LOG_ERR, "Too many groups");
1809}
1810
1811#define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1812/*
1813 * Routines that maintain the remote mounttab
1814 */
1815void
1816get_mountlist()
1817{
1818	struct mountlist *mlp, **mlpp;
1819	char *eos, *dirp;
1820	int len;
1821	char str[STRSIZ];
1822	FILE *mlfile;
1823
1824	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1825		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1826		return;
1827	}
1828	mlpp = &mlhead;
1829	while (fgets(str, STRSIZ, mlfile) != NULL) {
1830		if ((dirp = index(str, '\t')) == NULL &&
1831		    (dirp = index(str, ' ')) == NULL)
1832			continue;
1833		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1834		len = dirp-str;
1835		if (len > RPCMNT_NAMELEN)
1836			len = RPCMNT_NAMELEN;
1837		bcopy(str, mlp->ml_host, len);
1838		mlp->ml_host[len] = '\0';
1839		while (*dirp == '\t' || *dirp == ' ')
1840			dirp++;
1841		if ((eos = index(dirp, '\t')) == NULL &&
1842		    (eos = index(dirp, ' ')) == NULL &&
1843		    (eos = index(dirp, '\n')) == NULL)
1844			len = strlen(dirp);
1845		else
1846			len = eos-dirp;
1847		if (len > RPCMNT_PATHLEN)
1848			len = RPCMNT_PATHLEN;
1849		bcopy(dirp, mlp->ml_dirp, len);
1850		mlp->ml_dirp[len] = '\0';
1851		mlp->ml_next = (struct mountlist *)NULL;
1852		*mlpp = mlp;
1853		mlpp = &mlp->ml_next;
1854	}
1855	fclose(mlfile);
1856}
1857
1858void
1859del_mlist(hostp, dirp)
1860	char *hostp, *dirp;
1861{
1862	struct mountlist *mlp, **mlpp;
1863	struct mountlist *mlp2;
1864	FILE *mlfile;
1865	int fnd = 0;
1866
1867	mlpp = &mlhead;
1868	mlp = mlhead;
1869	while (mlp) {
1870		if (!strcmp(mlp->ml_host, hostp) &&
1871		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1872			fnd = 1;
1873			mlp2 = mlp;
1874			*mlpp = mlp = mlp->ml_next;
1875			free((caddr_t)mlp2);
1876		} else {
1877			mlpp = &mlp->ml_next;
1878			mlp = mlp->ml_next;
1879		}
1880	}
1881	if (fnd) {
1882		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1883			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1884			return;
1885		}
1886		mlp = mlhead;
1887		while (mlp) {
1888			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1889			mlp = mlp->ml_next;
1890		}
1891		fclose(mlfile);
1892	}
1893}
1894
1895void
1896add_mlist(hostp, dirp)
1897	char *hostp, *dirp;
1898{
1899	struct mountlist *mlp, **mlpp;
1900	FILE *mlfile;
1901
1902	mlpp = &mlhead;
1903	mlp = mlhead;
1904	while (mlp) {
1905		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1906			return;
1907		mlpp = &mlp->ml_next;
1908		mlp = mlp->ml_next;
1909	}
1910	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1911	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1912	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1913	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1914	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1915	mlp->ml_next = (struct mountlist *)NULL;
1916	*mlpp = mlp;
1917	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1918		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1919		return;
1920	}
1921	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1922	fclose(mlfile);
1923}
1924
1925/*
1926 * This function is called via. SIGTERM when the system is going down.
1927 * It sends a broadcast RPCMNT_UMNTALL.
1928 */
1929void
1930send_umntall()
1931{
1932	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1933		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1934	exit(0);
1935}
1936
1937int
1938umntall_each(resultsp, raddr)
1939	caddr_t resultsp;
1940	struct sockaddr_in *raddr;
1941{
1942	return (1);
1943}
1944
1945/*
1946 * Free up a group list.
1947 */
1948void
1949free_grp(grp)
1950	struct grouplist *grp;
1951{
1952	char **addrp;
1953
1954	if (grp->gr_type == GT_HOST) {
1955		if (grp->gr_ptr.gt_hostent->h_name) {
1956			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1957			while (addrp && *addrp)
1958				free(*addrp++);
1959			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1960			free(grp->gr_ptr.gt_hostent->h_name);
1961		}
1962		free((caddr_t)grp->gr_ptr.gt_hostent);
1963	} else if (grp->gr_type == GT_NET) {
1964		if (grp->gr_ptr.gt_net.nt_name)
1965			free(grp->gr_ptr.gt_net.nt_name);
1966	}
1967#ifdef ISO
1968	else if (grp->gr_type == GT_ISO)
1969		free((caddr_t)grp->gr_ptr.gt_isoaddr);
1970#endif
1971	free((caddr_t)grp);
1972}
1973
1974#ifdef DEBUG
1975void
1976SYSLOG(int pri, const char *fmt, ...)
1977{
1978	va_list ap;
1979
1980	va_start(ap, fmt);
1981	vfprintf(stderr, fmt, ap);
1982	va_end(ap);
1983}
1984#endif /* DEBUG */
1985
1986/*
1987 * Check options for consistency.
1988 */
1989int
1990check_options(dp)
1991	struct dirlist *dp;
1992{
1993
1994	if (dp == (struct dirlist *)NULL)
1995	    return (1);
1996	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
1997	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
1998	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
1999	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
2000	    return (1);
2001	}
2002	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
2003	    syslog(LOG_ERR, "-mask requires -net");
2004	    return (1);
2005	}
2006	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
2007	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
2008	    return (1);
2009	}
2010	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
2011	    syslog(LOG_ERR, "-alldir has multiple directories");
2012	    return (1);
2013	}
2014	return (0);
2015}
2016
2017/*
2018 * Check an absolute directory path for any symbolic links. Return true
2019 * if no symbolic links are found.
2020 */
2021int
2022check_dirpath(dirp)
2023	char *dirp;
2024{
2025	char *cp;
2026	int ret = 1;
2027	struct stat sb;
2028
2029	cp = dirp + 1;
2030	while (*cp && ret) {
2031		if (*cp == '/') {
2032			*cp = '\0';
2033			if (lstat(dirp, &sb) < 0 ||
2034				(sb.st_mode & S_IFMT) != S_IFDIR)
2035				ret = 0;
2036			*cp = '/';
2037		}
2038		cp++;
2039	}
2040	if (lstat(dirp, &sb) < 0 ||
2041		(sb.st_mode & S_IFMT) != S_IFDIR)
2042		ret = 0;
2043	return (ret);
2044}
2045