xref: /csrg-svn/sbin/mountd/mountd.c (revision 45271)
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*45271Smckusick static char sccsid[] = "@(#)mountd.c	5.13 (Berkeley) 09/30/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);
11944338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
12044015Smckusick 	get_exportlist();
12144015Smckusick 	get_mountlist();
12238460Smckusick 	if (debug == 0) {
12344690Skarels 		daemon(0, 0);
12438460Smckusick 		signal(SIGINT, SIG_IGN);
12538460Smckusick 		signal(SIGQUIT, SIG_IGN);
12638460Smckusick 	}
12738460Smckusick 	signal(SIGHUP, get_exportlist);
12844015Smckusick 	signal(SIGTERM, send_umntall);
12940494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
13040494Smckusick 	  if (pidfile != NULL) {
13140494Smckusick 		fprintf(pidfile, "%d\n", getpid());
13240494Smckusick 		fclose(pidfile);
13340494Smckusick 	  }
13440494Smckusick 	}
13538460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
13638460Smckusick 		syslog(LOG_ERR, "Can't create socket");
13738460Smckusick 		exit(1);
13838460Smckusick 	}
13938460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
14038460Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, IPPROTO_UDP)) {
14138460Smckusick 		syslog(LOG_ERR, "Can't register mount");
14238460Smckusick 		exit(1);
14338460Smckusick 	}
14438460Smckusick 	svc_run();
14538460Smckusick 	syslog(LOG_ERR, "Mountd died");
14644690Skarels 	exit(1);
14738460Smckusick }
14838460Smckusick 
14938460Smckusick /*
15038460Smckusick  * The mount rpc service
15138460Smckusick  */
15238460Smckusick mntsrv(rqstp, transp)
15338460Smckusick 	register struct svc_req *rqstp;
15438460Smckusick 	register SVCXPRT *transp;
15538460Smckusick {
15639681Smckusick 	register struct grouplist *grp;
15739681Smckusick 	register u_long **addrp;
15838460Smckusick 	register struct exportlist *ep;
15938460Smckusick 	nfsv2fh_t nfh;
16038460Smckusick 	struct authunix_parms *ucr;
16138460Smckusick 	struct stat stb;
16238460Smckusick 	struct hostent *hp;
16339681Smckusick 	u_long saddr;
16438460Smckusick 	char dirpath[RPCMNT_PATHLEN+1];
16538460Smckusick 	int bad = ENOENT;
16638460Smckusick 	int omask;
16739681Smckusick 	uid_t uid = -2;
16838460Smckusick 
16938460Smckusick 	/* Get authorization */
17038460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
17138460Smckusick 	case AUTH_UNIX:
17238460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
17339681Smckusick 		uid = ucr->aup_uid;
17439681Smckusick 		break;
17538460Smckusick 	case AUTH_NULL:
17638460Smckusick 	default:
17739681Smckusick 		break;
17838460Smckusick 	}
17938460Smckusick 
18039681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
18139681Smckusick 	hp = (struct hostent *)0;
18238460Smckusick 	switch (rqstp->rq_proc) {
18339681Smckusick 	case NULLPROC:
18439681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
18539681Smckusick 			syslog(LOG_ERR, "Can't send reply");
18639681Smckusick 		return;
18738460Smckusick 	case RPCMNT_MOUNT:
18844015Smckusick 		if (uid != 0 && root_only) {
18939681Smckusick 			svcerr_weakauth(transp);
19039681Smckusick 			return;
19139681Smckusick 		}
19238460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
19338460Smckusick 			svcerr_decode(transp);
19438460Smckusick 			return;
19538460Smckusick 		}
19638460Smckusick 
19738460Smckusick 		/* Check to see if it's a valid dirpath */
19838460Smckusick 		if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
19938460Smckusick 			S_IFDIR) {
20038460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
20138460Smckusick 				syslog(LOG_ERR, "Can't send reply");
20238460Smckusick 			return;
20338460Smckusick 		}
20438460Smckusick 
20538460Smckusick 		/* Check in the exports list */
20638460Smckusick 		omask = sigblock(sigmask(SIGHUP));
20738460Smckusick 		ep = exphead.ex_next;
20838460Smckusick 		while (ep != NULL) {
20938460Smckusick 			if (!strcmp(ep->ex_dirp, dirpath)) {
21038460Smckusick 				grp = ep->ex_groups;
21138460Smckusick 				if (grp == NULL)
21238460Smckusick 					break;
21339681Smckusick 
21439681Smckusick 				/* Check for a host match */
21539681Smckusick 				addrp = (u_long **)grp->gr_hp->h_addr_list;
21639681Smckusick 				for (;;) {
21739681Smckusick 					if (**addrp == saddr)
21838460Smckusick 						break;
21939681Smckusick 					if (*++addrp == NULL)
22039681Smckusick 						if (grp = grp->gr_next) {
22139681Smckusick 							addrp = (u_long **)
22239681Smckusick 								grp->gr_hp->h_addr_list;
22339681Smckusick 						} else {
22439681Smckusick 							bad = EACCES;
22539681Smckusick 							if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
22639681Smckusick 								syslog(LOG_ERR, "Can't send reply");
22739681Smckusick 							sigsetmask(omask);
22839681Smckusick 							return;
22939681Smckusick 						}
23038460Smckusick 				}
23139681Smckusick 				hp = grp->gr_hp;
23239681Smckusick 				break;
23338460Smckusick 			}
23438460Smckusick 			ep = ep->ex_next;
23538460Smckusick 		}
23638460Smckusick 		sigsetmask(omask);
23738460Smckusick 		if (ep == NULL) {
23838460Smckusick 			bad = EACCES;
23938460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
24038460Smckusick 				syslog(LOG_ERR, "Can't send reply");
24138460Smckusick 			return;
24238460Smckusick 		}
24338460Smckusick 
24438460Smckusick 		/* Get the file handle */
24538460Smckusick 		bzero((caddr_t)&nfh, sizeof(nfh));
24638460Smckusick 		if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
24738460Smckusick 			bad = errno;
24838460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
24938460Smckusick 				syslog(LOG_ERR, "Can't send reply");
25038460Smckusick 			return;
25138460Smckusick 		}
25238460Smckusick 		if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
25338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
25439681Smckusick 		if (hp == NULL)
25539681Smckusick 			hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
25644015Smckusick 		if (hp)
25744015Smckusick 			add_mlist(hp->h_name, dirpath);
25838460Smckusick 		return;
25938460Smckusick 	case RPCMNT_DUMP:
26038460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
26138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
26238460Smckusick 		return;
26338460Smckusick 	case RPCMNT_UMOUNT:
26444015Smckusick 		if (uid != 0 && root_only) {
26539681Smckusick 			svcerr_weakauth(transp);
26639681Smckusick 			return;
26739681Smckusick 		}
26838460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
26938460Smckusick 			svcerr_decode(transp);
27038460Smckusick 			return;
27138460Smckusick 		}
27238460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
27338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
27444015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
27544015Smckusick 		if (hp)
27644015Smckusick 			del_mlist(hp->h_name, dirpath);
27738460Smckusick 		return;
27838460Smckusick 	case RPCMNT_UMNTALL:
27944015Smckusick 		if (uid != 0 && root_only) {
28039681Smckusick 			svcerr_weakauth(transp);
28139681Smckusick 			return;
28239681Smckusick 		}
28338460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
28438460Smckusick 			syslog(LOG_ERR, "Can't send reply");
28544015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
28644015Smckusick 		if (hp)
28744015Smckusick 			del_mlist(hp->h_name, (char *)0);
28838460Smckusick 		return;
28938460Smckusick 	case RPCMNT_EXPORT:
29038460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
29138460Smckusick 			syslog(LOG_ERR, "Can't send reply");
29238460Smckusick 		return;
29338460Smckusick 	default:
29438460Smckusick 		svcerr_noproc(transp);
29538460Smckusick 		return;
29638460Smckusick 	}
29738460Smckusick }
29838460Smckusick 
29938460Smckusick /*
30038460Smckusick  * Xdr conversion for a dirpath string
30138460Smckusick  */
30238460Smckusick xdr_dir(xdrsp, dirp)
30338460Smckusick 	XDR *xdrsp;
30438460Smckusick 	char *dirp;
30538460Smckusick {
30638460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
30738460Smckusick }
30838460Smckusick 
30938460Smckusick /*
31038460Smckusick  * Xdr routine to generate fhstatus
31138460Smckusick  */
31238460Smckusick xdr_fhs(xdrsp, nfh)
31338460Smckusick 	XDR *xdrsp;
31438460Smckusick 	nfsv2fh_t *nfh;
31538460Smckusick {
31638460Smckusick 	int ok = 0;
31738460Smckusick 
31838460Smckusick 	if (!xdr_long(xdrsp, &ok))
31938460Smckusick 		return (0);
32038460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
32138460Smckusick }
32238460Smckusick 
32338460Smckusick xdr_mlist(xdrsp, cp)
32438460Smckusick 	XDR *xdrsp;
32538460Smckusick 	caddr_t cp;
32638460Smckusick {
32744015Smckusick 	register struct mountlist *mlp;
32838460Smckusick 	int true = 1;
32938460Smckusick 	int false = 0;
33038460Smckusick 	char *strp;
33138460Smckusick 
33244015Smckusick 	mlp = mlhead;
33344015Smckusick 	while (mlp) {
33444015Smckusick 		if (!xdr_bool(xdrsp, &true))
33544015Smckusick 			return (0);
33644015Smckusick 		strp = &mlp->ml_host[0];
33744015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
33844015Smckusick 			return (0);
33944015Smckusick 		strp = &mlp->ml_dirp[0];
34044015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
34144015Smckusick 			return (0);
34244015Smckusick 		mlp = mlp->ml_next;
34338460Smckusick 	}
34438460Smckusick 	if (!xdr_bool(xdrsp, &false))
34538460Smckusick 		return (0);
34638460Smckusick 	return (1);
34738460Smckusick }
34838460Smckusick 
34938460Smckusick /*
35038460Smckusick  * Xdr conversion for export list
35138460Smckusick  */
35238460Smckusick xdr_explist(xdrsp, cp)
35338460Smckusick 	XDR *xdrsp;
35438460Smckusick 	caddr_t cp;
35538460Smckusick {
35638460Smckusick 	register struct exportlist *ep;
35738460Smckusick 	register struct grouplist *grp;
35838460Smckusick 	int true = 1;
35938460Smckusick 	int false = 0;
36038460Smckusick 	char *strp;
36138460Smckusick 	int omask;
36238460Smckusick 
36338460Smckusick 	omask = sigblock(sigmask(SIGHUP));
36438460Smckusick 	ep = exphead.ex_next;
36538460Smckusick 	while (ep != NULL) {
36638460Smckusick 		if (!xdr_bool(xdrsp, &true))
36738460Smckusick 			goto errout;
36838460Smckusick 		strp = &ep->ex_dirp[0];
36938460Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
37038460Smckusick 			goto errout;
37138460Smckusick 		grp = ep->ex_groups;
37238460Smckusick 		while (grp != NULL) {
37338460Smckusick 			if (!xdr_bool(xdrsp, &true))
37438460Smckusick 				goto errout;
37539681Smckusick 			strp = grp->gr_hp->h_name;
37638460Smckusick 			if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
37738460Smckusick 				goto errout;
37838460Smckusick 			grp = grp->gr_next;
37938460Smckusick 		}
38038460Smckusick 		if (!xdr_bool(xdrsp, &false))
38138460Smckusick 			goto errout;
38238460Smckusick 		ep = ep->ex_next;
38338460Smckusick 	}
38438460Smckusick 	sigsetmask(omask);
38538460Smckusick 	if (!xdr_bool(xdrsp, &false))
38638460Smckusick 		return (0);
38738460Smckusick 	return (1);
38838460Smckusick errout:
38938460Smckusick 	sigsetmask(omask);
39038460Smckusick 	return (0);
39138460Smckusick }
39238460Smckusick 
39338460Smckusick #define LINESIZ	10240
39438460Smckusick char line[LINESIZ];
39538460Smckusick 
39638460Smckusick /*
39738460Smckusick  * Get the export list
39838460Smckusick  */
39938460Smckusick get_exportlist()
40038460Smckusick {
40139681Smckusick 	register struct hostent *hp, *nhp;
40239681Smckusick 	register char **addrp, **naddrp;
40339681Smckusick 	register int i;
40444015Smckusick 	register struct grouplist *grp;
40538460Smckusick 	register struct exportlist *ep, *ep2;
40645168Smckusick 	struct statfs stfsbuf;
40740368Smckusick 	struct ufs_args args;
40844015Smckusick 	struct stat sb;
40938460Smckusick 	FILE *inf;
41038460Smckusick 	char *cp, *endcp;
41139681Smckusick 	char savedc;
41244015Smckusick 	int len, dirplen;
41338460Smckusick 	int rootuid, exflags;
41444015Smckusick 	u_long saddr;
41544015Smckusick 	struct exportlist *fep;
41638460Smckusick 
41738460Smckusick 	/*
41838460Smckusick 	 * First, get rid of the old list
41938460Smckusick 	 */
42038460Smckusick 	ep = exphead.ex_next;
42138460Smckusick 	while (ep != NULL) {
42238460Smckusick 		ep2 = ep;
42338460Smckusick 		ep = ep->ex_next;
42444015Smckusick 		free_exp(ep2);
42538460Smckusick 	}
42638460Smckusick 
42738460Smckusick 	/*
42838460Smckusick 	 * Read in the exports file and build the list, calling
42938460Smckusick 	 * exportfs() as we go along
43038460Smckusick 	 */
43138460Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
43238460Smckusick 	if ((inf = fopen(exname, "r")) == NULL) {
43338460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
43438460Smckusick 		exit(2);
43538460Smckusick 	}
43638460Smckusick 	while (fgets(line, LINESIZ, inf)) {
43741404Smckusick 		exflags = MNT_EXPORTED;
43838460Smckusick 		rootuid = def_rootuid;
43938460Smckusick 		cp = line;
44038460Smckusick 		nextfield(&cp, &endcp);
44144015Smckusick 
44244015Smckusick 		/*
44344015Smckusick 		 * Get file system devno and see if an entry for this
44444015Smckusick 		 * file system already exists.
44544015Smckusick 		 */
44644015Smckusick 		savedc = *endcp;
44744015Smckusick 		*endcp = '\0';
448*45271Smckusick 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
449*45271Smckusick 			syslog(LOG_ERR,
450*45271Smckusick 			    "Bad Exports File, %s: %s, mountd Failed",
451*45271Smckusick 			    cp, "Not a directory");
452*45271Smckusick 			exit(2);
453*45271Smckusick 		}
45444015Smckusick 		fep = (struct exportlist *)0;
45544015Smckusick 		ep = exphead.ex_next;
45644015Smckusick 		while (ep) {
45744015Smckusick 			if (ep->ex_dev == sb.st_dev) {
45844015Smckusick 				fep = ep;
45944015Smckusick 				break;
46044015Smckusick 			}
46144015Smckusick 			ep = ep->ex_next;
46244015Smckusick 		}
46344015Smckusick 		*endcp = savedc;
46444015Smckusick 
46544015Smckusick 		/*
46644015Smckusick 		 * Create new exports list entry
46744015Smckusick 		 */
46838460Smckusick 		len = endcp-cp;
46938460Smckusick 		if (len <= RPCMNT_PATHLEN && len > 0) {
47038460Smckusick 			ep = (struct exportlist *)malloc(sizeof(*ep));
471*45271Smckusick 			if (ep == NULL)
472*45271Smckusick 				goto err;
47338460Smckusick 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
47438460Smckusick 			ep->ex_groups = (struct grouplist *)0;
47538460Smckusick 			bcopy(cp, ep->ex_dirp, len);
47638460Smckusick 			ep->ex_dirp[len] = '\0';
47744015Smckusick 			dirplen = len;
478*45271Smckusick 		} else {
479*45271Smckusick 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
480*45271Smckusick 			exit(2);
481*45271Smckusick 		}
48238460Smckusick 		cp = endcp;
48338460Smckusick 		nextfield(&cp, &endcp);
48438460Smckusick 		len = endcp-cp;
48538460Smckusick 		while (len > 0) {
48639681Smckusick 			savedc = *endcp;
48739681Smckusick 			*endcp = '\0';
488*45271Smckusick 			if (len > RPCMNT_NAMELEN)
489*45271Smckusick 				goto more;
490*45271Smckusick 			if (*cp == '-') {
491*45271Smckusick 				do_opt(cp + 1, fep, ep, &exflags, &rootuid);
492*45271Smckusick 				goto more;
493*45271Smckusick 			}
494*45271Smckusick 			if (isdigit(*cp)) {
495*45271Smckusick 				saddr = inet_addr(cp);
496*45271Smckusick 				if (saddr == -1 ||
497*45271Smckusick 				    (hp = gethostbyaddr((caddr_t)&saddr,
498*45271Smckusick 				     sizeof(saddr), AF_INET)) == NULL) {
499*45271Smckusick 					syslog(LOG_ERR,
500*45271Smckusick 					    "Bad Exports File, %s: %s", cp,
501*45271Smckusick 					    "Gethostbyaddr failed, ignored");
502*45271Smckusick 					goto more;
50338460Smckusick 				}
504*45271Smckusick 			} else if ((hp = gethostbyname(cp)) == NULL) {
505*45271Smckusick 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
506*45271Smckusick 				    cp, "Gethostbyname failed, ignored");
507*45271Smckusick 				goto more;
50838460Smckusick 			}
509*45271Smckusick 			grp = (struct grouplist *)
510*45271Smckusick 				malloc(sizeof(struct grouplist));
511*45271Smckusick 			if (grp == NULL)
512*45271Smckusick 				goto err;
513*45271Smckusick 			nhp = grp->gr_hp = (struct hostent *)
514*45271Smckusick 				malloc(sizeof(struct hostent));
515*45271Smckusick 			if (nhp == NULL)
516*45271Smckusick 				goto err;
517*45271Smckusick 			bcopy((caddr_t)hp, (caddr_t)nhp,
518*45271Smckusick 				sizeof(struct hostent));
519*45271Smckusick 			i = strlen(hp->h_name)+1;
520*45271Smckusick 			nhp->h_name = (char *)malloc(i);
521*45271Smckusick 			if (nhp->h_name == NULL)
522*45271Smckusick 				goto err;
523*45271Smckusick 			bcopy(hp->h_name, nhp->h_name, i);
524*45271Smckusick 			addrp = hp->h_addr_list;
525*45271Smckusick 			i = 1;
526*45271Smckusick 			while (*addrp++)
527*45271Smckusick 				i++;
528*45271Smckusick 			naddrp = nhp->h_addr_list = (char **)
529*45271Smckusick 				malloc(i*sizeof(char *));
530*45271Smckusick 			if (naddrp == NULL)
531*45271Smckusick 				goto err;
532*45271Smckusick 			addrp = hp->h_addr_list;
533*45271Smckusick 			while (*addrp) {
534*45271Smckusick 				*naddrp = (char *)
535*45271Smckusick 				    malloc(hp->h_length);
536*45271Smckusick 				if (*naddrp == NULL)
537*45271Smckusick 				    goto err;
538*45271Smckusick 				bcopy(*addrp, *naddrp,
539*45271Smckusick 					hp->h_length);
540*45271Smckusick 				addrp++;
541*45271Smckusick 				naddrp++;
542*45271Smckusick 			}
543*45271Smckusick 			*naddrp = (char *)0;
544*45271Smckusick 			grp->gr_next = ep->ex_groups;
545*45271Smckusick 			ep->ex_groups = grp;
546*45271Smckusick 		more:
54738460Smckusick 			cp = endcp;
54839681Smckusick 			*cp = savedc;
54938460Smckusick 			nextfield(&cp, &endcp);
550*45271Smckusick 			len = endcp - cp;
55138460Smckusick 		}
55244015Smckusick 		if (fep == NULL) {
55344015Smckusick 			args.fspec = 0;
55444015Smckusick 			args.exflags = exflags;
55544015Smckusick 			args.exroot = rootuid;
55644015Smckusick 			cp = (char *)0;
55745168Smckusick 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
55845168Smckusick 			       mount(MOUNT_UFS, ep->ex_dirp,
55945168Smckusick 				     stfsbuf.f_flags|MNT_UPDATE, &args) < 0) {
56044015Smckusick 				if (cp == NULL)
56144015Smckusick 					cp = ep->ex_dirp + dirplen - 1;
56244015Smckusick 				else
56344015Smckusick 					*cp = savedc;
56444015Smckusick 				/* back up over the last component */
56544015Smckusick 				while (*cp == '/' && cp > ep->ex_dirp)
56644015Smckusick 					cp--;
56744015Smckusick 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
56844015Smckusick 					cp--;
56944015Smckusick 				if (cp == ep->ex_dirp) {
57044015Smckusick 					syslog(LOG_WARNING,
57144015Smckusick 					      "Can't export %s", ep->ex_dirp);
57244015Smckusick 					free_exp(ep);
57344015Smckusick 					goto nextline;
57444015Smckusick 				}
57544015Smckusick 				savedc = *cp;
57644015Smckusick 				*cp = '\0';
57744015Smckusick 			}
57844015Smckusick 			if (cp)
57944015Smckusick 				*cp = savedc;
58038460Smckusick 			ep->ex_rootuid = rootuid;
58138460Smckusick 			ep->ex_exflags = exflags;
58244015Smckusick 		} else {
58344015Smckusick 			ep->ex_rootuid = fep->ex_rootuid;
58444015Smckusick 			ep->ex_exflags = fep->ex_exflags;
58538460Smckusick 		}
58644015Smckusick 		ep->ex_dev = sb.st_dev;
58744015Smckusick 		ep->ex_next = exphead.ex_next;
58844015Smckusick 		ep->ex_prev = &exphead;
58944015Smckusick 		if (ep->ex_next != NULL)
59044015Smckusick 			ep->ex_next->ex_prev = ep;
59144015Smckusick 		exphead.ex_next = ep;
59244015Smckusick nextline:
59344015Smckusick 		;
59438460Smckusick 	}
59538460Smckusick 	fclose(inf);
59638460Smckusick 	return;
59738460Smckusick err:
598*45271Smckusick 	syslog(LOG_ERR, "No more memory: mountd Failed");
59938460Smckusick 	exit(2);
60038460Smckusick }
60138460Smckusick 
60238460Smckusick /*
60338460Smckusick  * Parse out the next white space separated field
60438460Smckusick  */
60538460Smckusick nextfield(cp, endcp)
60638460Smckusick 	char **cp;
60738460Smckusick 	char **endcp;
60838460Smckusick {
60938460Smckusick 	register char *p;
61038460Smckusick 
61138460Smckusick 	p = *cp;
61238460Smckusick 	while (*p == ' ' || *p == '\t')
61338460Smckusick 		p++;
61438460Smckusick 	if (*p == '\n' || *p == '\0') {
61538460Smckusick 		*cp = *endcp = p;
61638460Smckusick 		return;
61738460Smckusick 	}
61838460Smckusick 	*cp = p++;
61938460Smckusick 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
62038460Smckusick 		p++;
62138460Smckusick 	*endcp = p;
62238460Smckusick }
62339681Smckusick 
62439681Smckusick /*
62544015Smckusick  * Parse the option string
62639681Smckusick  */
62744015Smckusick do_opt(cpopt, fep, ep, exflagsp, rootuidp)
62844015Smckusick 	register char *cpopt;
62944015Smckusick 	struct exportlist *fep, *ep;
63044015Smckusick 	int *exflagsp, *rootuidp;
63139681Smckusick {
63244015Smckusick 	register char *cpoptarg, *cpoptend;
63339681Smckusick 
63444015Smckusick 	while (cpopt && *cpopt) {
63544015Smckusick 		if (cpoptend = index(cpopt, ','))
63644015Smckusick 			*cpoptend++ = '\0';
63744015Smckusick 		if (cpoptarg = index(cpopt, '='))
63844015Smckusick 			*cpoptarg++ = '\0';
63944015Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
64044015Smckusick 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
64144015Smckusick 				syslog(LOG_WARNING, "ro failed for %s",
64244015Smckusick 				       ep->ex_dirp);
64344015Smckusick 			else
64444015Smckusick 				*exflagsp |= MNT_EXRDONLY;
64544015Smckusick 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
64644015Smckusick 			if (cpoptarg && isdigit(*cpoptarg)) {
64744015Smckusick 				*rootuidp = atoi(cpoptarg);
64844015Smckusick 				if (fep && fep->ex_rootuid != *rootuidp)
64944015Smckusick 					syslog(LOG_WARNING,
65044015Smckusick 					       "uid failed for %s",
65144015Smckusick 					       ep->ex_dirp);
65244015Smckusick 			} else
65344015Smckusick 				syslog(LOG_WARNING,
65444015Smckusick 				       "uid failed for %s",
65544015Smckusick 				       ep->ex_dirp);
65644015Smckusick 		} else
65744015Smckusick 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
65844015Smckusick 			       ep->ex_dirp);
65944015Smckusick 		cpopt = cpoptend;
66044015Smckusick 	}
66144015Smckusick }
66244015Smckusick 
66344015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
66444015Smckusick /*
66544015Smckusick  * Routines that maintain the remote mounttab
66644015Smckusick  */
66744015Smckusick void get_mountlist()
66844015Smckusick {
66944015Smckusick 	register struct mountlist *mlp, **mlpp;
67044015Smckusick 	register char *eos, *dirp;
67144015Smckusick 	int len;
67244015Smckusick 	char str[STRSIZ];
67344015Smckusick 	FILE *mlfile;
67444015Smckusick 
67544338Smckusick 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
67644338Smckusick 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
67744015Smckusick 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
67844015Smckusick 		return;
67944015Smckusick 	}
68044015Smckusick 	mlpp = &mlhead;
68144015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
68244015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
68344015Smckusick 		    (dirp = index(str, ' ')) == NULL)
68444015Smckusick 			continue;
68544015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
68644015Smckusick 		len = dirp-str;
68744015Smckusick 		if (len > RPCMNT_NAMELEN)
68844015Smckusick 			len = RPCMNT_NAMELEN;
68944015Smckusick 		bcopy(str, mlp->ml_host, len);
69044015Smckusick 		mlp->ml_host[len] = '\0';
69144015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
69244015Smckusick 			dirp++;
69344015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
69444015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
69544015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
69644015Smckusick 			len = strlen(dirp);
69744015Smckusick 		else
69844015Smckusick 			len = eos-dirp;
69944015Smckusick 		if (len > RPCMNT_PATHLEN)
70044015Smckusick 			len = RPCMNT_PATHLEN;
70144015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
70244015Smckusick 		mlp->ml_dirp[len] = '\0';
70344015Smckusick 		mlp->ml_next = (struct mountlist *)0;
70444015Smckusick 		*mlpp = mlp;
70544015Smckusick 		mlpp = &mlp->ml_next;
70644015Smckusick 	}
70744015Smckusick 	fclose(mlfile);
70844015Smckusick }
70944015Smckusick 
71044015Smckusick void del_mlist(hostp, dirp)
71144015Smckusick 	register char *hostp, *dirp;
71244015Smckusick {
71344015Smckusick 	register struct mountlist *mlp, **mlpp;
71444015Smckusick 	FILE *mlfile;
71544015Smckusick 	int fnd = 0;
71644015Smckusick 
71744015Smckusick 	mlpp = &mlhead;
71844015Smckusick 	mlp = mlhead;
71944015Smckusick 	while (mlp) {
72044015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
72144015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
72244015Smckusick 			fnd = 1;
72344015Smckusick 			*mlpp = mlp->ml_next;
72444015Smckusick 			free((caddr_t)mlp);
72539681Smckusick 		}
72644015Smckusick 		mlpp = &mlp->ml_next;
72744015Smckusick 		mlp = mlp->ml_next;
72839681Smckusick 	}
72944015Smckusick 	if (fnd) {
73044015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
73144015Smckusick 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
73244015Smckusick 			return;
73344015Smckusick 		}
73444015Smckusick 		mlp = mlhead;
73544015Smckusick 		while (mlp) {
73644015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
73744015Smckusick 			mlp = mlp->ml_next;
73844015Smckusick 		}
73944015Smckusick 		fclose(mlfile);
74044015Smckusick 	}
74139681Smckusick }
74244015Smckusick 
74344015Smckusick void add_mlist(hostp, dirp)
74444015Smckusick 	register char *hostp, *dirp;
74544015Smckusick {
74644015Smckusick 	register struct mountlist *mlp, **mlpp;
74744015Smckusick 	FILE *mlfile;
74844015Smckusick 
74944015Smckusick 	mlpp = &mlhead;
75044015Smckusick 	mlp = mlhead;
75144015Smckusick 	while (mlp) {
75244015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
75344015Smckusick 			return;
75444015Smckusick 		mlpp = &mlp->ml_next;
75544015Smckusick 		mlp = mlp->ml_next;
75644015Smckusick 	}
75744015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
75844015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
75944015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
76044015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
76144015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
76244015Smckusick 	mlp->ml_next = (struct mountlist *)0;
76344015Smckusick 	*mlpp = mlp;
76444015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
76544015Smckusick 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
76644015Smckusick 		return;
76744015Smckusick 	}
76844015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
76944015Smckusick 	fclose(mlfile);
77044015Smckusick }
77144015Smckusick 
77244015Smckusick /*
77344015Smckusick  * This function is called via. SIGTERM when the system is going down.
77444015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
77544015Smckusick  */
77644015Smckusick send_umntall()
77744015Smckusick {
77844015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
77944015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
78044015Smckusick 	exit();
78144015Smckusick }
78244015Smckusick 
78344015Smckusick umntall_each(resultsp, raddr)
78444015Smckusick 	caddr_t resultsp;
78544015Smckusick 	struct sockaddr_in *raddr;
78644015Smckusick {
78744015Smckusick 	return (1);
78844015Smckusick }
78944015Smckusick 
79044015Smckusick /*
79144015Smckusick  * Free up an exports list component
79244015Smckusick  */
79344015Smckusick free_exp(ep)
79444015Smckusick 	register struct exportlist *ep;
79544015Smckusick {
79644015Smckusick 	register struct grouplist *grp;
79744015Smckusick 	register char **addrp;
79844015Smckusick 	struct grouplist *grp2;
79944015Smckusick 
80044015Smckusick 	grp = ep->ex_groups;
80144015Smckusick 	while (grp != NULL) {
80244015Smckusick 		addrp = grp->gr_hp->h_addr_list;
80344015Smckusick 		while (*addrp)
80444015Smckusick 			free(*addrp++);
80544015Smckusick 		free((caddr_t)grp->gr_hp->h_addr_list);
80644015Smckusick 		free(grp->gr_hp->h_name);
80744015Smckusick 		free((caddr_t)grp->gr_hp);
80844015Smckusick 		grp2 = grp;
80944015Smckusick 		grp = grp->gr_next;
81044015Smckusick 		free((caddr_t)grp2);
81144015Smckusick 	}
81244015Smckusick 	free((caddr_t)ep);
81344015Smckusick }
814