xref: /csrg-svn/sbin/mountd/mountd.c (revision 44338)
138460Smckusick /*
238460Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338460Smckusick  * All rights reserved.
438460Smckusick  *
538460Smckusick  * This code is derived from software contributed to Berkeley by
638460Smckusick  * Rick Macklem at The University of Guelph.
738460Smckusick  *
842703Sbostic  * %sccs.include.redist.c%
938460Smckusick  */
1038460Smckusick 
1138460Smckusick #ifndef lint
1238460Smckusick char copyright[] =
1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1438460Smckusick  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*44338Smckusick static char sccsid[] = "@(#)mountd.c	5.10 (Berkeley) 06/27/90";
1938460Smckusick #endif not lint
2038460Smckusick 
2138460Smckusick #include <sys/param.h>
2238460Smckusick #include <sys/ioctl.h>
2338460Smckusick #include <sys/stat.h>
2439681Smckusick #include <sys/file.h>
2538460Smckusick #include <sys/mount.h>
2638460Smckusick #include <sys/socket.h>
2738460Smckusick #include <sys/errno.h>
2842038Sbostic #include <sys/signal.h>
2942038Sbostic #include <stdio.h>
3042038Sbostic #include <string.h>
3142038Sbostic #include <syslog.h>
3238460Smckusick #include <netdb.h>
3338460Smckusick #include <rpc/rpc.h>
3438460Smckusick #include <rpc/pmap_clnt.h>
3538460Smckusick #include <rpc/pmap_prot.h>
3638460Smckusick #include <nfs/rpcv2.h>
3738460Smckusick #include <nfs/nfsv2.h>
3839681Smckusick #include "pathnames.h"
3938460Smckusick 
4038460Smckusick struct ufid {
4138460Smckusick 	u_short	ufid_len;
4238460Smckusick 	ino_t	ufid_ino;
4338460Smckusick 	long	ufid_gen;
4438460Smckusick };
4538460Smckusick /*
4638460Smckusick  * Structures for keeping the mount list and export list
4738460Smckusick  */
4838460Smckusick struct mountlist {
4944015Smckusick 	struct mountlist *ml_next;
5038460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
5138460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
5238460Smckusick };
5338460Smckusick 
5438460Smckusick struct exportlist {
5538460Smckusick 	struct exportlist *ex_next;
5638460Smckusick 	struct exportlist *ex_prev;
5738460Smckusick 	struct grouplist *ex_groups;
5838460Smckusick 	int	ex_rootuid;
5938460Smckusick 	int	ex_exflags;
6044015Smckusick 	dev_t	ex_dev;
6138460Smckusick 	char	ex_dirp[RPCMNT_PATHLEN+1];
6238460Smckusick };
6338460Smckusick 
6438460Smckusick struct grouplist {
6538460Smckusick 	struct grouplist *gr_next;
6639681Smckusick 	struct hostent *gr_hp;
6738460Smckusick };
6838460Smckusick 
6938460Smckusick /* Global defs */
7038460Smckusick int xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
7144015Smckusick int mntsrv(), get_exportlist(), send_umntall(), umntall_each();
7244015Smckusick void get_mountlist(), add_mlist(), del_mlist();
7338460Smckusick struct exportlist exphead;
7444015Smckusick struct mountlist *mlhead;
7538460Smckusick char exname[MAXPATHLEN];
7638460Smckusick int def_rootuid = -2;
7744015Smckusick int root_only = 1;
7838460Smckusick extern int errno;
7938460Smckusick #ifdef DEBUG
8038460Smckusick int debug = 1;
8138460Smckusick #else
8238460Smckusick int debug = 0;
8338460Smckusick #endif
8438460Smckusick 
8538460Smckusick /*
8638460Smckusick  * Mountd server for NFS mount protocol as described in:
8739681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
8844015Smckusick  * The optional arguments are the exports file name
8939681Smckusick  * default: _PATH_EXPORTS
9044015Smckusick  * and "-n" to allow nonroot mount.
9138460Smckusick  */
9238460Smckusick main(argc, argv)
9338460Smckusick 	int argc;
9444015Smckusick 	char **argv;
9538460Smckusick {
9638460Smckusick 	SVCXPRT *transp;
9744015Smckusick 	int c;
9844015Smckusick 	extern int optind;
9944015Smckusick 	extern char *optarg;
10038460Smckusick 
10144015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
10244015Smckusick 		switch (c) {
10344015Smckusick 		case 'n':
10444015Smckusick 			root_only = 0;
10544015Smckusick 			break;
10644015Smckusick 		default:
10744015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
10844015Smckusick 			exit(1);
10944015Smckusick 		};
11044015Smckusick 	argc -= optind;
11144015Smckusick 	argv += optind;
11244015Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
11344015Smckusick 	mlhead = (struct mountlist *)0;
11444015Smckusick 	if (argc == 1) {
11544015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
11644015Smckusick 		exname[MAXPATHLEN-1] = '\0';
11744015Smckusick 	} else
11844015Smckusick 		strcpy(exname, _PATH_EXPORTS);
119*44338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
12044015Smckusick 	get_exportlist();
12144015Smckusick 	get_mountlist();
12238460Smckusick 	if (debug == 0) {
12338460Smckusick 		if (fork())
12438460Smckusick 			exit(0);
12538460Smckusick 		{ int s;
12638460Smckusick 		for (s = 0; s < 10; s++)
12738460Smckusick 			(void) close(s);
12838460Smckusick 		}
12938460Smckusick 		(void) open("/", O_RDONLY);
13038460Smckusick 		(void) dup2(0, 1);
13138460Smckusick 		(void) dup2(0, 2);
13238460Smckusick 		{ int tt = open("/dev/tty", O_RDWR);
13338460Smckusick 		  if (tt > 0) {
13438460Smckusick 			ioctl(tt, TIOCNOTTY, (char *)0);
13538460Smckusick 			close(tt);
13638460Smckusick 		  }
13738460Smckusick 		}
13838460Smckusick 		(void) setpgrp(0, 0);
13938460Smckusick 		signal(SIGTSTP, SIG_IGN);
14038460Smckusick 		signal(SIGTTIN, SIG_IGN);
14138460Smckusick 		signal(SIGTTOU, SIG_IGN);
14238460Smckusick 		signal(SIGINT, SIG_IGN);
14338460Smckusick 		signal(SIGQUIT, SIG_IGN);
14438460Smckusick 	}
14538460Smckusick 	signal(SIGHUP, get_exportlist);
14644015Smckusick 	signal(SIGTERM, send_umntall);
14740494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
14840494Smckusick 	  if (pidfile != NULL) {
14940494Smckusick 		fprintf(pidfile, "%d\n", getpid());
15040494Smckusick 		fclose(pidfile);
15140494Smckusick 	  }
15240494Smckusick 	}
15338460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
15438460Smckusick 		syslog(LOG_ERR, "Can't create socket");
15538460Smckusick 		exit(1);
15638460Smckusick 	}
15738460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
15838460Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) {
15938460Smckusick 		syslog(LOG_ERR, "Can't register mount");
16038460Smckusick 		exit(1);
16138460Smckusick 	}
16238460Smckusick 	svc_run();
16338460Smckusick 	syslog(LOG_ERR, "Mountd died");
16438460Smckusick }
16538460Smckusick 
16638460Smckusick /*
16738460Smckusick  * The mount rpc service
16838460Smckusick  */
16938460Smckusick mntsrv(rqstp, transp)
17038460Smckusick 	register struct svc_req *rqstp;
17138460Smckusick 	register SVCXPRT *transp;
17238460Smckusick {
17339681Smckusick 	register struct grouplist *grp;
17439681Smckusick 	register u_long **addrp;
17538460Smckusick 	register struct exportlist *ep;
17638460Smckusick 	nfsv2fh_t nfh;
17738460Smckusick 	struct authunix_parms *ucr;
17838460Smckusick 	struct stat stb;
17938460Smckusick 	struct hostent *hp;
18039681Smckusick 	u_long saddr;
18138460Smckusick 	char dirpath[RPCMNT_PATHLEN+1];
18238460Smckusick 	int bad = ENOENT;
18338460Smckusick 	int omask;
18439681Smckusick 	uid_t uid = -2;
18538460Smckusick 
18638460Smckusick 	/* Get authorization */
18738460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
18838460Smckusick 	case AUTH_UNIX:
18938460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
19039681Smckusick 		uid = ucr->aup_uid;
19139681Smckusick 		break;
19238460Smckusick 	case AUTH_NULL:
19338460Smckusick 	default:
19439681Smckusick 		break;
19538460Smckusick 	}
19638460Smckusick 
19739681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
19839681Smckusick 	hp = (struct hostent *)0;
19938460Smckusick 	switch (rqstp->rq_proc) {
20039681Smckusick 	case NULLPROC:
20139681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
20239681Smckusick 			syslog(LOG_ERR, "Can't send reply");
20339681Smckusick 		return;
20438460Smckusick 	case RPCMNT_MOUNT:
20544015Smckusick 		if (uid != 0 && root_only) {
20639681Smckusick 			svcerr_weakauth(transp);
20739681Smckusick 			return;
20839681Smckusick 		}
20938460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
21038460Smckusick 			svcerr_decode(transp);
21138460Smckusick 			return;
21238460Smckusick 		}
21338460Smckusick 
21438460Smckusick 		/* Check to see if it's a valid dirpath */
21538460Smckusick 		if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
21638460Smckusick 			S_IFDIR) {
21738460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
21838460Smckusick 				syslog(LOG_ERR, "Can't send reply");
21938460Smckusick 			return;
22038460Smckusick 		}
22138460Smckusick 
22238460Smckusick 		/* Check in the exports list */
22338460Smckusick 		omask = sigblock(sigmask(SIGHUP));
22438460Smckusick 		ep = exphead.ex_next;
22538460Smckusick 		while (ep != NULL) {
22638460Smckusick 			if (!strcmp(ep->ex_dirp, dirpath)) {
22738460Smckusick 				grp = ep->ex_groups;
22838460Smckusick 				if (grp == NULL)
22938460Smckusick 					break;
23039681Smckusick 
23139681Smckusick 				/* Check for a host match */
23239681Smckusick 				addrp = (u_long **)grp->gr_hp->h_addr_list;
23339681Smckusick 				for (;;) {
23439681Smckusick 					if (**addrp == saddr)
23538460Smckusick 						break;
23639681Smckusick 					if (*++addrp == NULL)
23739681Smckusick 						if (grp = grp->gr_next) {
23839681Smckusick 							addrp = (u_long **)
23939681Smckusick 								grp->gr_hp->h_addr_list;
24039681Smckusick 						} else {
24139681Smckusick 							bad = EACCES;
24239681Smckusick 							if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
24339681Smckusick 								syslog(LOG_ERR, "Can't send reply");
24439681Smckusick 							sigsetmask(omask);
24539681Smckusick 							return;
24639681Smckusick 						}
24738460Smckusick 				}
24839681Smckusick 				hp = grp->gr_hp;
24939681Smckusick 				break;
25038460Smckusick 			}
25138460Smckusick 			ep = ep->ex_next;
25238460Smckusick 		}
25338460Smckusick 		sigsetmask(omask);
25438460Smckusick 		if (ep == NULL) {
25538460Smckusick 			bad = EACCES;
25638460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
25738460Smckusick 				syslog(LOG_ERR, "Can't send reply");
25838460Smckusick 			return;
25938460Smckusick 		}
26038460Smckusick 
26138460Smckusick 		/* Get the file handle */
26238460Smckusick 		bzero((caddr_t)&nfh, sizeof(nfh));
26338460Smckusick 		if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
26438460Smckusick 			bad = errno;
26538460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
26638460Smckusick 				syslog(LOG_ERR, "Can't send reply");
26738460Smckusick 			return;
26838460Smckusick 		}
26938460Smckusick 		if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
27038460Smckusick 			syslog(LOG_ERR, "Can't send reply");
27139681Smckusick 		if (hp == NULL)
27239681Smckusick 			hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
27344015Smckusick 		if (hp)
27444015Smckusick 			add_mlist(hp->h_name, dirpath);
27538460Smckusick 		return;
27638460Smckusick 	case RPCMNT_DUMP:
27738460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
27838460Smckusick 			syslog(LOG_ERR, "Can't send reply");
27938460Smckusick 		return;
28038460Smckusick 	case RPCMNT_UMOUNT:
28144015Smckusick 		if (uid != 0 && root_only) {
28239681Smckusick 			svcerr_weakauth(transp);
28339681Smckusick 			return;
28439681Smckusick 		}
28538460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
28638460Smckusick 			svcerr_decode(transp);
28738460Smckusick 			return;
28838460Smckusick 		}
28938460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
29038460Smckusick 			syslog(LOG_ERR, "Can't send reply");
29144015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
29244015Smckusick 		if (hp)
29344015Smckusick 			del_mlist(hp->h_name, dirpath);
29438460Smckusick 		return;
29538460Smckusick 	case RPCMNT_UMNTALL:
29644015Smckusick 		if (uid != 0 && root_only) {
29739681Smckusick 			svcerr_weakauth(transp);
29839681Smckusick 			return;
29939681Smckusick 		}
30038460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
30138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
30244015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
30344015Smckusick 		if (hp)
30444015Smckusick 			del_mlist(hp->h_name, (char *)0);
30538460Smckusick 		return;
30638460Smckusick 	case RPCMNT_EXPORT:
30738460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
30838460Smckusick 			syslog(LOG_ERR, "Can't send reply");
30938460Smckusick 		return;
31038460Smckusick 	default:
31138460Smckusick 		svcerr_noproc(transp);
31238460Smckusick 		return;
31338460Smckusick 	}
31438460Smckusick }
31538460Smckusick 
31638460Smckusick /*
31738460Smckusick  * Xdr conversion for a dirpath string
31838460Smckusick  */
31938460Smckusick xdr_dir(xdrsp, dirp)
32038460Smckusick 	XDR *xdrsp;
32138460Smckusick 	char *dirp;
32238460Smckusick {
32338460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
32438460Smckusick }
32538460Smckusick 
32638460Smckusick /*
32738460Smckusick  * Xdr routine to generate fhstatus
32838460Smckusick  */
32938460Smckusick xdr_fhs(xdrsp, nfh)
33038460Smckusick 	XDR *xdrsp;
33138460Smckusick 	nfsv2fh_t *nfh;
33238460Smckusick {
33338460Smckusick 	int ok = 0;
33438460Smckusick 
33538460Smckusick 	if (!xdr_long(xdrsp, &ok))
33638460Smckusick 		return (0);
33738460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
33838460Smckusick }
33938460Smckusick 
34038460Smckusick xdr_mlist(xdrsp, cp)
34138460Smckusick 	XDR *xdrsp;
34238460Smckusick 	caddr_t cp;
34338460Smckusick {
34444015Smckusick 	register struct mountlist *mlp;
34538460Smckusick 	int true = 1;
34638460Smckusick 	int false = 0;
34738460Smckusick 	char *strp;
34838460Smckusick 
34944015Smckusick 	mlp = mlhead;
35044015Smckusick 	while (mlp) {
35144015Smckusick 		if (!xdr_bool(xdrsp, &true))
35244015Smckusick 			return (0);
35344015Smckusick 		strp = &mlp->ml_host[0];
35444015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
35544015Smckusick 			return (0);
35644015Smckusick 		strp = &mlp->ml_dirp[0];
35744015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
35844015Smckusick 			return (0);
35944015Smckusick 		mlp = mlp->ml_next;
36038460Smckusick 	}
36138460Smckusick 	if (!xdr_bool(xdrsp, &false))
36238460Smckusick 		return (0);
36338460Smckusick 	return (1);
36438460Smckusick }
36538460Smckusick 
36638460Smckusick /*
36738460Smckusick  * Xdr conversion for export list
36838460Smckusick  */
36938460Smckusick xdr_explist(xdrsp, cp)
37038460Smckusick 	XDR *xdrsp;
37138460Smckusick 	caddr_t cp;
37238460Smckusick {
37338460Smckusick 	register struct exportlist *ep;
37438460Smckusick 	register struct grouplist *grp;
37538460Smckusick 	int true = 1;
37638460Smckusick 	int false = 0;
37738460Smckusick 	char *strp;
37838460Smckusick 	int omask;
37938460Smckusick 
38038460Smckusick 	omask = sigblock(sigmask(SIGHUP));
38138460Smckusick 	ep = exphead.ex_next;
38238460Smckusick 	while (ep != NULL) {
38338460Smckusick 		if (!xdr_bool(xdrsp, &true))
38438460Smckusick 			goto errout;
38538460Smckusick 		strp = &ep->ex_dirp[0];
38638460Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
38738460Smckusick 			goto errout;
38838460Smckusick 		grp = ep->ex_groups;
38938460Smckusick 		while (grp != NULL) {
39038460Smckusick 			if (!xdr_bool(xdrsp, &true))
39138460Smckusick 				goto errout;
39239681Smckusick 			strp = grp->gr_hp->h_name;
39338460Smckusick 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
39438460Smckusick 				goto errout;
39538460Smckusick 			grp = grp->gr_next;
39638460Smckusick 		}
39738460Smckusick 		if (!xdr_bool(xdrsp, &false))
39838460Smckusick 			goto errout;
39938460Smckusick 		ep = ep->ex_next;
40038460Smckusick 	}
40138460Smckusick 	sigsetmask(omask);
40238460Smckusick 	if (!xdr_bool(xdrsp, &false))
40338460Smckusick 		return (0);
40438460Smckusick 	return (1);
40538460Smckusick errout:
40638460Smckusick 	sigsetmask(omask);
40738460Smckusick 	return (0);
40838460Smckusick }
40938460Smckusick 
41038460Smckusick #define LINESIZ	10240
41138460Smckusick char line[LINESIZ];
41238460Smckusick 
41338460Smckusick /*
41438460Smckusick  * Get the export list
41538460Smckusick  */
41638460Smckusick get_exportlist()
41738460Smckusick {
41839681Smckusick 	register struct hostent *hp, *nhp;
41939681Smckusick 	register char **addrp, **naddrp;
42039681Smckusick 	register int i;
42144015Smckusick 	register struct grouplist *grp;
42238460Smckusick 	register struct exportlist *ep, *ep2;
42340368Smckusick 	struct ufs_args args;
42444015Smckusick 	struct stat sb;
42538460Smckusick 	FILE *inf;
42638460Smckusick 	char *cp, *endcp;
42739681Smckusick 	char savedc;
42844015Smckusick 	int len, dirplen;
42938460Smckusick 	int rootuid, exflags;
43044015Smckusick 	u_long saddr;
43144015Smckusick 	struct exportlist *fep;
43238460Smckusick 
43338460Smckusick 	/*
43438460Smckusick 	 * First, get rid of the old list
43538460Smckusick 	 */
43638460Smckusick 	ep = exphead.ex_next;
43738460Smckusick 	while (ep != NULL) {
43838460Smckusick 		ep2 = ep;
43938460Smckusick 		ep = ep->ex_next;
44044015Smckusick 		free_exp(ep2);
44138460Smckusick 	}
44238460Smckusick 
44338460Smckusick 	/*
44438460Smckusick 	 * Read in the exports file and build the list, calling
44538460Smckusick 	 * exportfs() as we go along
44638460Smckusick 	 */
44738460Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
44838460Smckusick 	if ((inf = fopen(exname, "r")) == NULL) {
44938460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
45038460Smckusick 		exit(2);
45138460Smckusick 	}
45238460Smckusick 	while (fgets(line, LINESIZ, inf)) {
45341404Smckusick 		exflags = MNT_EXPORTED;
45438460Smckusick 		rootuid = def_rootuid;
45538460Smckusick 		cp = line;
45638460Smckusick 		nextfield(&cp, &endcp);
45744015Smckusick 
45844015Smckusick 		/*
45944015Smckusick 		 * Get file system devno and see if an entry for this
46044015Smckusick 		 * file system already exists.
46144015Smckusick 		 */
46244015Smckusick 		savedc = *endcp;
46344015Smckusick 		*endcp = '\0';
46444015Smckusick 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR)
46544015Smckusick 			goto err;
46644015Smckusick 		fep = (struct exportlist *)0;
46744015Smckusick 		ep = exphead.ex_next;
46844015Smckusick 		while (ep) {
46944015Smckusick 			if (ep->ex_dev == sb.st_dev) {
47044015Smckusick 				fep = ep;
47144015Smckusick 				break;
47244015Smckusick 			}
47344015Smckusick 			ep = ep->ex_next;
47444015Smckusick 		}
47544015Smckusick 		*endcp = savedc;
47644015Smckusick 
47744015Smckusick 		/*
47844015Smckusick 		 * Create new exports list entry
47944015Smckusick 		 */
48038460Smckusick 		len = endcp-cp;
48138460Smckusick 		if (len <= RPCMNT_PATHLEN && len > 0) {
48238460Smckusick 			ep = (struct exportlist *)malloc(sizeof(*ep));
48338460Smckusick 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
48438460Smckusick 			ep->ex_groups = (struct grouplist *)0;
48538460Smckusick 			bcopy(cp, ep->ex_dirp, len);
48638460Smckusick 			ep->ex_dirp[len] = '\0';
48744015Smckusick 			dirplen = len;
48838460Smckusick 		} else
48938460Smckusick 			goto err;
49038460Smckusick 		cp = endcp;
49138460Smckusick 		nextfield(&cp, &endcp);
49238460Smckusick 		len = endcp-cp;
49338460Smckusick 		while (len > 0) {
49439681Smckusick 			savedc = *endcp;
49539681Smckusick 			*endcp = '\0';
49638460Smckusick 			if (len <= RPCMNT_NAMELEN) {
49738460Smckusick 				if (*cp == '-') {
49844015Smckusick 				    do_opt(cp+1, fep, ep, &exflags, &rootuid);
49944015Smckusick 				} else {
50044015Smckusick 				    if (isdigit(*cp)) {
50144015Smckusick 					saddr = inet_addr(cp);
50244015Smckusick 					if (saddr == -1 ||
50344015Smckusick 					    (hp = gethostbyaddr((caddr_t)&saddr,
50444015Smckusick 					     sizeof(saddr), AF_INET)) == NULL)
50538460Smckusick 						goto err;
50644015Smckusick 				    } else if ((hp = gethostbyname(cp)) == NULL)
50744015Smckusick 					goto err;
50844015Smckusick 				    grp = (struct grouplist *)
50944015Smckusick 					    malloc(sizeof(struct grouplist));
51044015Smckusick 				    if (grp == NULL)
51144015Smckusick 					    goto err;
51244015Smckusick 				    nhp = grp->gr_hp = (struct hostent *)
51344015Smckusick 					    malloc(sizeof(struct hostent));
51444015Smckusick 				    if (nhp == NULL)
51544015Smckusick 					    goto err;
51644015Smckusick 				    bcopy((caddr_t)hp, (caddr_t)nhp,
51744015Smckusick 					    sizeof(struct hostent));
51844015Smckusick 				    i = strlen(hp->h_name)+1;
51944015Smckusick 				    nhp->h_name = (char *)malloc(i);
52044015Smckusick 				    if (nhp->h_name == NULL)
52144015Smckusick 					    goto err;
52244015Smckusick 				    bcopy(hp->h_name, nhp->h_name, i);
52344015Smckusick 				    addrp = hp->h_addr_list;
52444015Smckusick 				    i = 1;
52544015Smckusick 				    while (*addrp++)
52644015Smckusick 					    i++;
52744015Smckusick 				    naddrp = nhp->h_addr_list = (char **)
52844015Smckusick 					    malloc(i*sizeof(char *));
52944015Smckusick 				    if (naddrp == NULL)
53044015Smckusick 					    goto err;
53144015Smckusick 				    addrp = hp->h_addr_list;
53244015Smckusick 				    while (*addrp) {
53344015Smckusick 					    *naddrp = (char *)
53444015Smckusick 					        malloc(hp->h_length);
53544015Smckusick 					    if (*naddrp == NULL)
53639681Smckusick 						goto err;
53744015Smckusick 					    bcopy(*addrp, *naddrp,
53844015Smckusick 						    hp->h_length);
53944015Smckusick 					    addrp++;
54044015Smckusick 					    naddrp++;
54144015Smckusick 				    }
54244015Smckusick 				    *naddrp = (char *)0;
54344015Smckusick 				    grp->gr_next = ep->ex_groups;
54444015Smckusick 				    ep->ex_groups = grp;
54538460Smckusick 				}
54638460Smckusick 			}
54738460Smckusick 			cp = endcp;
54839681Smckusick 			*cp = savedc;
54938460Smckusick 			nextfield(&cp, &endcp);
55038460Smckusick 			len = endcp-cp;
55138460Smckusick 		}
55244015Smckusick 		if (fep == NULL) {
55344015Smckusick 			args.fspec = 0;
55444015Smckusick 			args.exflags = exflags;
55544015Smckusick 			args.exroot = rootuid;
55644015Smckusick 			cp = (char *)0;
55744015Smckusick 			while (mount(MOUNT_UFS, ep->ex_dirp, MNT_UPDATE, &args) < 0) {
55844015Smckusick 				if (cp == NULL)
55944015Smckusick 					cp = ep->ex_dirp + dirplen - 1;
56044015Smckusick 				else
56144015Smckusick 					*cp = savedc;
56244015Smckusick 				/* back up over the last component */
56344015Smckusick 				while (*cp == '/' && cp > ep->ex_dirp)
56444015Smckusick 					cp--;
56544015Smckusick 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
56644015Smckusick 					cp--;
56744015Smckusick 				if (cp == ep->ex_dirp) {
56844015Smckusick 					syslog(LOG_WARNING,
56944015Smckusick 					      "Can't export %s", ep->ex_dirp);
57044015Smckusick 					free_exp(ep);
57144015Smckusick 					goto nextline;
57244015Smckusick 				}
57344015Smckusick 				savedc = *cp;
57444015Smckusick 				*cp = '\0';
57544015Smckusick 			}
57644015Smckusick 			if (cp)
57744015Smckusick 				*cp = savedc;
57838460Smckusick 			ep->ex_rootuid = rootuid;
57938460Smckusick 			ep->ex_exflags = exflags;
58044015Smckusick 		} else {
58144015Smckusick 			ep->ex_rootuid = fep->ex_rootuid;
58244015Smckusick 			ep->ex_exflags = fep->ex_exflags;
58338460Smckusick 		}
58444015Smckusick 		ep->ex_dev = sb.st_dev;
58544015Smckusick 		ep->ex_next = exphead.ex_next;
58644015Smckusick 		ep->ex_prev = &exphead;
58744015Smckusick 		if (ep->ex_next != NULL)
58844015Smckusick 			ep->ex_next->ex_prev = ep;
58944015Smckusick 		exphead.ex_next = ep;
59044015Smckusick nextline:
59144015Smckusick 		;
59238460Smckusick 	}
59338460Smckusick 	fclose(inf);
59438460Smckusick 	return;
59538460Smckusick err:
59639681Smckusick 	syslog(LOG_ERR, "Bad Exports File, mountd Failed");
59738460Smckusick 	exit(2);
59838460Smckusick }
59938460Smckusick 
60038460Smckusick /*
60138460Smckusick  * Parse out the next white space separated field
60238460Smckusick  */
60338460Smckusick nextfield(cp, endcp)
60438460Smckusick 	char **cp;
60538460Smckusick 	char **endcp;
60638460Smckusick {
60738460Smckusick 	register char *p;
60838460Smckusick 
60938460Smckusick 	p = *cp;
61038460Smckusick 	while (*p == ' ' || *p == '\t')
61138460Smckusick 		p++;
61238460Smckusick 	if (*p == '\n' || *p == '\0') {
61338460Smckusick 		*cp = *endcp = p;
61438460Smckusick 		return;
61538460Smckusick 	}
61638460Smckusick 	*cp = p++;
61738460Smckusick 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
61838460Smckusick 		p++;
61938460Smckusick 	*endcp = p;
62038460Smckusick }
62139681Smckusick 
62239681Smckusick /*
62344015Smckusick  * Parse the option string
62439681Smckusick  */
62544015Smckusick do_opt(cpopt, fep, ep, exflagsp, rootuidp)
62644015Smckusick 	register char *cpopt;
62744015Smckusick 	struct exportlist *fep, *ep;
62844015Smckusick 	int *exflagsp, *rootuidp;
62939681Smckusick {
63044015Smckusick 	register char *cpoptarg, *cpoptend;
63139681Smckusick 
63244015Smckusick 	while (cpopt && *cpopt) {
63344015Smckusick 		if (cpoptend = index(cpopt, ','))
63444015Smckusick 			*cpoptend++ = '\0';
63544015Smckusick 		if (cpoptarg = index(cpopt, '='))
63644015Smckusick 			*cpoptarg++ = '\0';
63744015Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
63844015Smckusick 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
63944015Smckusick 				syslog(LOG_WARNING, "ro failed for %s",
64044015Smckusick 				       ep->ex_dirp);
64144015Smckusick 			else
64244015Smckusick 				*exflagsp |= MNT_EXRDONLY;
64344015Smckusick 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
64444015Smckusick 			if (cpoptarg && isdigit(*cpoptarg)) {
64544015Smckusick 				*rootuidp = atoi(cpoptarg);
64644015Smckusick 				if (fep && fep->ex_rootuid != *rootuidp)
64744015Smckusick 					syslog(LOG_WARNING,
64844015Smckusick 					       "uid failed for %s",
64944015Smckusick 					       ep->ex_dirp);
65044015Smckusick 			} else
65144015Smckusick 				syslog(LOG_WARNING,
65244015Smckusick 				       "uid failed for %s",
65344015Smckusick 				       ep->ex_dirp);
65444015Smckusick 		} else
65544015Smckusick 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
65644015Smckusick 			       ep->ex_dirp);
65744015Smckusick 		cpopt = cpoptend;
65844015Smckusick 	}
65944015Smckusick }
66044015Smckusick 
66144015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
66244015Smckusick /*
66344015Smckusick  * Routines that maintain the remote mounttab
66444015Smckusick  */
66544015Smckusick void get_mountlist()
66644015Smckusick {
66744015Smckusick 	register struct mountlist *mlp, **mlpp;
66844015Smckusick 	register char *eos, *dirp;
66944015Smckusick 	int len;
67044015Smckusick 	char str[STRSIZ];
67144015Smckusick 	FILE *mlfile;
67244015Smckusick 
673*44338Smckusick 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
674*44338Smckusick 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
67544015Smckusick 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
67644015Smckusick 		return;
67744015Smckusick 	}
67844015Smckusick 	mlpp = &mlhead;
67944015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
68044015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
68144015Smckusick 		    (dirp = index(str, ' ')) == NULL)
68244015Smckusick 			continue;
68344015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
68444015Smckusick 		len = dirp-str;
68544015Smckusick 		if (len > RPCMNT_NAMELEN)
68644015Smckusick 			len = RPCMNT_NAMELEN;
68744015Smckusick 		bcopy(str, mlp->ml_host, len);
68844015Smckusick 		mlp->ml_host[len] = '\0';
68944015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
69044015Smckusick 			dirp++;
69144015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
69244015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
69344015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
69444015Smckusick 			len = strlen(dirp);
69544015Smckusick 		else
69644015Smckusick 			len = eos-dirp;
69744015Smckusick 		if (len > RPCMNT_PATHLEN)
69844015Smckusick 			len = RPCMNT_PATHLEN;
69944015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
70044015Smckusick 		mlp->ml_dirp[len] = '\0';
70144015Smckusick 		mlp->ml_next = (struct mountlist *)0;
70244015Smckusick 		*mlpp = mlp;
70344015Smckusick 		mlpp = &mlp->ml_next;
70444015Smckusick 	}
70544015Smckusick 	fclose(mlfile);
70644015Smckusick }
70744015Smckusick 
70844015Smckusick void del_mlist(hostp, dirp)
70944015Smckusick 	register char *hostp, *dirp;
71044015Smckusick {
71144015Smckusick 	register struct mountlist *mlp, **mlpp;
71244015Smckusick 	FILE *mlfile;
71344015Smckusick 	int fnd = 0;
71444015Smckusick 
71544015Smckusick 	mlpp = &mlhead;
71644015Smckusick 	mlp = mlhead;
71744015Smckusick 	while (mlp) {
71844015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
71944015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
72044015Smckusick 			fnd = 1;
72144015Smckusick 			*mlpp = mlp->ml_next;
72244015Smckusick 			free((caddr_t)mlp);
72339681Smckusick 		}
72444015Smckusick 		mlpp = &mlp->ml_next;
72544015Smckusick 		mlp = mlp->ml_next;
72639681Smckusick 	}
72744015Smckusick 	if (fnd) {
72844015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
72944015Smckusick 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
73044015Smckusick 			return;
73144015Smckusick 		}
73244015Smckusick 		mlp = mlhead;
73344015Smckusick 		while (mlp) {
73444015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
73544015Smckusick 			mlp = mlp->ml_next;
73644015Smckusick 		}
73744015Smckusick 		fclose(mlfile);
73844015Smckusick 	}
73939681Smckusick }
74044015Smckusick 
74144015Smckusick void add_mlist(hostp, dirp)
74244015Smckusick 	register char *hostp, *dirp;
74344015Smckusick {
74444015Smckusick 	register struct mountlist *mlp, **mlpp;
74544015Smckusick 	FILE *mlfile;
74644015Smckusick 
74744015Smckusick 	mlpp = &mlhead;
74844015Smckusick 	mlp = mlhead;
74944015Smckusick 	while (mlp) {
75044015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
75144015Smckusick 			return;
75244015Smckusick 		mlpp = &mlp->ml_next;
75344015Smckusick 		mlp = mlp->ml_next;
75444015Smckusick 	}
75544015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
75644015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
75744015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
75844015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
75944015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
76044015Smckusick 	mlp->ml_next = (struct mountlist *)0;
76144015Smckusick 	*mlpp = mlp;
76244015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
76344015Smckusick 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
76444015Smckusick 		return;
76544015Smckusick 	}
76644015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
76744015Smckusick 	fclose(mlfile);
76844015Smckusick }
76944015Smckusick 
77044015Smckusick /*
77144015Smckusick  * This function is called via. SIGTERM when the system is going down.
77244015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
77344015Smckusick  */
77444015Smckusick send_umntall()
77544015Smckusick {
77644015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
77744015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
77844015Smckusick 	exit();
77944015Smckusick }
78044015Smckusick 
78144015Smckusick umntall_each(resultsp, raddr)
78244015Smckusick 	caddr_t resultsp;
78344015Smckusick 	struct sockaddr_in *raddr;
78444015Smckusick {
78544015Smckusick 	return (1);
78644015Smckusick }
78744015Smckusick 
78844015Smckusick /*
78944015Smckusick  * Free up an exports list component
79044015Smckusick  */
79144015Smckusick free_exp(ep)
79244015Smckusick 	register struct exportlist *ep;
79344015Smckusick {
79444015Smckusick 	register struct grouplist *grp;
79544015Smckusick 	register char **addrp;
79644015Smckusick 	struct grouplist *grp2;
79744015Smckusick 
79844015Smckusick 	grp = ep->ex_groups;
79944015Smckusick 	while (grp != NULL) {
80044015Smckusick 		addrp = grp->gr_hp->h_addr_list;
80144015Smckusick 		while (*addrp)
80244015Smckusick 			free(*addrp++);
80344015Smckusick 		free((caddr_t)grp->gr_hp->h_addr_list);
80444015Smckusick 		free(grp->gr_hp->h_name);
80544015Smckusick 		free((caddr_t)grp->gr_hp);
80644015Smckusick 		grp2 = grp;
80744015Smckusick 		grp = grp->gr_next;
80844015Smckusick 		free((caddr_t)grp2);
80944015Smckusick 	}
81044015Smckusick 	free((caddr_t)ep);
81144015Smckusick }
812