xref: /csrg-svn/sbin/mountd/mountd.c (revision 44015)
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*44015Smckusick static char sccsid[] = "@(#)mountd.c	5.9 (Berkeley) 06/25/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 {
49*44015Smckusick 	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;
60*44015Smckusick 	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();
71*44015Smckusick int mntsrv(), get_exportlist(), send_umntall(), umntall_each();
72*44015Smckusick void get_mountlist(), add_mlist(), del_mlist();
7338460Smckusick struct exportlist exphead;
74*44015Smckusick struct mountlist *mlhead;
7538460Smckusick char exname[MAXPATHLEN];
7638460Smckusick int def_rootuid = -2;
77*44015Smckusick 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
88*44015Smckusick  * The optional arguments are the exports file name
8939681Smckusick  * default: _PATH_EXPORTS
90*44015Smckusick  * and "-n" to allow nonroot mount.
9138460Smckusick  */
9238460Smckusick main(argc, argv)
9338460Smckusick 	int argc;
94*44015Smckusick 	char **argv;
9538460Smckusick {
9638460Smckusick 	SVCXPRT *transp;
97*44015Smckusick 	int c;
98*44015Smckusick 	extern int optind;
99*44015Smckusick 	extern char *optarg;
10038460Smckusick 
101*44015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
102*44015Smckusick 		switch (c) {
103*44015Smckusick 		case 'n':
104*44015Smckusick 			root_only = 0;
105*44015Smckusick 			break;
106*44015Smckusick 		default:
107*44015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
108*44015Smckusick 			exit(1);
109*44015Smckusick 		};
110*44015Smckusick 	argc -= optind;
111*44015Smckusick 	argv += optind;
112*44015Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
113*44015Smckusick 	mlhead = (struct mountlist *)0;
114*44015Smckusick 	if (argc == 1) {
115*44015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
116*44015Smckusick 		exname[MAXPATHLEN-1] = '\0';
117*44015Smckusick 	} else
118*44015Smckusick 		strcpy(exname, _PATH_EXPORTS);
119*44015Smckusick 	get_exportlist();
120*44015Smckusick 	get_mountlist();
12138460Smckusick 	if (debug == 0) {
12238460Smckusick 		if (fork())
12338460Smckusick 			exit(0);
12438460Smckusick 		{ int s;
12538460Smckusick 		for (s = 0; s < 10; s++)
12638460Smckusick 			(void) close(s);
12738460Smckusick 		}
12838460Smckusick 		(void) open("/", O_RDONLY);
12938460Smckusick 		(void) dup2(0, 1);
13038460Smckusick 		(void) dup2(0, 2);
13138460Smckusick 		{ int tt = open("/dev/tty", O_RDWR);
13238460Smckusick 		  if (tt > 0) {
13338460Smckusick 			ioctl(tt, TIOCNOTTY, (char *)0);
13438460Smckusick 			close(tt);
13538460Smckusick 		  }
13638460Smckusick 		}
13738460Smckusick 		(void) setpgrp(0, 0);
13838460Smckusick 		signal(SIGTSTP, SIG_IGN);
13938460Smckusick 		signal(SIGTTIN, SIG_IGN);
14038460Smckusick 		signal(SIGTTOU, SIG_IGN);
14138460Smckusick 		signal(SIGINT, SIG_IGN);
14238460Smckusick 		signal(SIGQUIT, SIG_IGN);
14338460Smckusick 	}
14438460Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
14538460Smckusick 	signal(SIGHUP, get_exportlist);
146*44015Smckusick 	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:
205*44015Smckusick 		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);
273*44015Smckusick 		if (hp)
274*44015Smckusick 			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:
281*44015Smckusick 		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");
291*44015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
292*44015Smckusick 		if (hp)
293*44015Smckusick 			del_mlist(hp->h_name, dirpath);
29438460Smckusick 		return;
29538460Smckusick 	case RPCMNT_UMNTALL:
296*44015Smckusick 		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");
302*44015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
303*44015Smckusick 		if (hp)
304*44015Smckusick 			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 {
344*44015Smckusick 	register struct mountlist *mlp;
34538460Smckusick 	int true = 1;
34638460Smckusick 	int false = 0;
34738460Smckusick 	char *strp;
34838460Smckusick 
349*44015Smckusick 	mlp = mlhead;
350*44015Smckusick 	while (mlp) {
351*44015Smckusick 		if (!xdr_bool(xdrsp, &true))
352*44015Smckusick 			return (0);
353*44015Smckusick 		strp = &mlp->ml_host[0];
354*44015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
355*44015Smckusick 			return (0);
356*44015Smckusick 		strp = &mlp->ml_dirp[0];
357*44015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
358*44015Smckusick 			return (0);
359*44015Smckusick 		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;
421*44015Smckusick 	register struct grouplist *grp;
42238460Smckusick 	register struct exportlist *ep, *ep2;
42340368Smckusick 	struct ufs_args args;
424*44015Smckusick 	struct stat sb;
42538460Smckusick 	FILE *inf;
42638460Smckusick 	char *cp, *endcp;
42739681Smckusick 	char savedc;
428*44015Smckusick 	int len, dirplen;
42938460Smckusick 	int rootuid, exflags;
430*44015Smckusick 	u_long saddr;
431*44015Smckusick 	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;
440*44015Smckusick 		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);
457*44015Smckusick 
458*44015Smckusick 		/*
459*44015Smckusick 		 * Get file system devno and see if an entry for this
460*44015Smckusick 		 * file system already exists.
461*44015Smckusick 		 */
462*44015Smckusick 		savedc = *endcp;
463*44015Smckusick 		*endcp = '\0';
464*44015Smckusick 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR)
465*44015Smckusick 			goto err;
466*44015Smckusick 		fep = (struct exportlist *)0;
467*44015Smckusick 		ep = exphead.ex_next;
468*44015Smckusick 		while (ep) {
469*44015Smckusick 			if (ep->ex_dev == sb.st_dev) {
470*44015Smckusick 				fep = ep;
471*44015Smckusick 				break;
472*44015Smckusick 			}
473*44015Smckusick 			ep = ep->ex_next;
474*44015Smckusick 		}
475*44015Smckusick 		*endcp = savedc;
476*44015Smckusick 
477*44015Smckusick 		/*
478*44015Smckusick 		 * Create new exports list entry
479*44015Smckusick 		 */
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';
487*44015Smckusick 			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 == '-') {
498*44015Smckusick 				    do_opt(cp+1, fep, ep, &exflags, &rootuid);
499*44015Smckusick 				} else {
500*44015Smckusick 				    if (isdigit(*cp)) {
501*44015Smckusick 					saddr = inet_addr(cp);
502*44015Smckusick 					if (saddr == -1 ||
503*44015Smckusick 					    (hp = gethostbyaddr((caddr_t)&saddr,
504*44015Smckusick 					     sizeof(saddr), AF_INET)) == NULL)
50538460Smckusick 						goto err;
506*44015Smckusick 				    } else if ((hp = gethostbyname(cp)) == NULL)
507*44015Smckusick 					goto err;
508*44015Smckusick 				    grp = (struct grouplist *)
509*44015Smckusick 					    malloc(sizeof(struct grouplist));
510*44015Smckusick 				    if (grp == NULL)
511*44015Smckusick 					    goto err;
512*44015Smckusick 				    nhp = grp->gr_hp = (struct hostent *)
513*44015Smckusick 					    malloc(sizeof(struct hostent));
514*44015Smckusick 				    if (nhp == NULL)
515*44015Smckusick 					    goto err;
516*44015Smckusick 				    bcopy((caddr_t)hp, (caddr_t)nhp,
517*44015Smckusick 					    sizeof(struct hostent));
518*44015Smckusick 				    i = strlen(hp->h_name)+1;
519*44015Smckusick 				    nhp->h_name = (char *)malloc(i);
520*44015Smckusick 				    if (nhp->h_name == NULL)
521*44015Smckusick 					    goto err;
522*44015Smckusick 				    bcopy(hp->h_name, nhp->h_name, i);
523*44015Smckusick 				    addrp = hp->h_addr_list;
524*44015Smckusick 				    i = 1;
525*44015Smckusick 				    while (*addrp++)
526*44015Smckusick 					    i++;
527*44015Smckusick 				    naddrp = nhp->h_addr_list = (char **)
528*44015Smckusick 					    malloc(i*sizeof(char *));
529*44015Smckusick 				    if (naddrp == NULL)
530*44015Smckusick 					    goto err;
531*44015Smckusick 				    addrp = hp->h_addr_list;
532*44015Smckusick 				    while (*addrp) {
533*44015Smckusick 					    *naddrp = (char *)
534*44015Smckusick 					        malloc(hp->h_length);
535*44015Smckusick 					    if (*naddrp == NULL)
53639681Smckusick 						goto err;
537*44015Smckusick 					    bcopy(*addrp, *naddrp,
538*44015Smckusick 						    hp->h_length);
539*44015Smckusick 					    addrp++;
540*44015Smckusick 					    naddrp++;
541*44015Smckusick 				    }
542*44015Smckusick 				    *naddrp = (char *)0;
543*44015Smckusick 				    grp->gr_next = ep->ex_groups;
544*44015Smckusick 				    ep->ex_groups = grp;
54538460Smckusick 				}
54638460Smckusick 			}
54738460Smckusick 			cp = endcp;
54839681Smckusick 			*cp = savedc;
54938460Smckusick 			nextfield(&cp, &endcp);
55038460Smckusick 			len = endcp-cp;
55138460Smckusick 		}
552*44015Smckusick 		if (fep == NULL) {
553*44015Smckusick 			args.fspec = 0;
554*44015Smckusick 			args.exflags = exflags;
555*44015Smckusick 			args.exroot = rootuid;
556*44015Smckusick 			cp = (char *)0;
557*44015Smckusick 			while (mount(MOUNT_UFS, ep->ex_dirp, MNT_UPDATE, &args) < 0) {
558*44015Smckusick 				if (cp == NULL)
559*44015Smckusick 					cp = ep->ex_dirp + dirplen - 1;
560*44015Smckusick 				else
561*44015Smckusick 					*cp = savedc;
562*44015Smckusick 				/* back up over the last component */
563*44015Smckusick 				while (*cp == '/' && cp > ep->ex_dirp)
564*44015Smckusick 					cp--;
565*44015Smckusick 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
566*44015Smckusick 					cp--;
567*44015Smckusick 				if (cp == ep->ex_dirp) {
568*44015Smckusick 					syslog(LOG_WARNING,
569*44015Smckusick 					      "Can't export %s", ep->ex_dirp);
570*44015Smckusick 					free_exp(ep);
571*44015Smckusick 					goto nextline;
572*44015Smckusick 				}
573*44015Smckusick 				savedc = *cp;
574*44015Smckusick 				*cp = '\0';
575*44015Smckusick 			}
576*44015Smckusick 			if (cp)
577*44015Smckusick 				*cp = savedc;
57838460Smckusick 			ep->ex_rootuid = rootuid;
57938460Smckusick 			ep->ex_exflags = exflags;
580*44015Smckusick 		} else {
581*44015Smckusick 			ep->ex_rootuid = fep->ex_rootuid;
582*44015Smckusick 			ep->ex_exflags = fep->ex_exflags;
58338460Smckusick 		}
584*44015Smckusick 		ep->ex_dev = sb.st_dev;
585*44015Smckusick 		ep->ex_next = exphead.ex_next;
586*44015Smckusick 		ep->ex_prev = &exphead;
587*44015Smckusick 		if (ep->ex_next != NULL)
588*44015Smckusick 			ep->ex_next->ex_prev = ep;
589*44015Smckusick 		exphead.ex_next = ep;
590*44015Smckusick nextline:
591*44015Smckusick 		;
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 /*
623*44015Smckusick  * Parse the option string
62439681Smckusick  */
625*44015Smckusick do_opt(cpopt, fep, ep, exflagsp, rootuidp)
626*44015Smckusick 	register char *cpopt;
627*44015Smckusick 	struct exportlist *fep, *ep;
628*44015Smckusick 	int *exflagsp, *rootuidp;
62939681Smckusick {
630*44015Smckusick 	register char *cpoptarg, *cpoptend;
63139681Smckusick 
632*44015Smckusick 	while (cpopt && *cpopt) {
633*44015Smckusick 		if (cpoptend = index(cpopt, ','))
634*44015Smckusick 			*cpoptend++ = '\0';
635*44015Smckusick 		if (cpoptarg = index(cpopt, '='))
636*44015Smckusick 			*cpoptarg++ = '\0';
637*44015Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
638*44015Smckusick 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
639*44015Smckusick 				syslog(LOG_WARNING, "ro failed for %s",
640*44015Smckusick 				       ep->ex_dirp);
641*44015Smckusick 			else
642*44015Smckusick 				*exflagsp |= MNT_EXRDONLY;
643*44015Smckusick 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
644*44015Smckusick 			if (cpoptarg && isdigit(*cpoptarg)) {
645*44015Smckusick 				*rootuidp = atoi(cpoptarg);
646*44015Smckusick 				if (fep && fep->ex_rootuid != *rootuidp)
647*44015Smckusick 					syslog(LOG_WARNING,
648*44015Smckusick 					       "uid failed for %s",
649*44015Smckusick 					       ep->ex_dirp);
650*44015Smckusick 			} else
651*44015Smckusick 				syslog(LOG_WARNING,
652*44015Smckusick 				       "uid failed for %s",
653*44015Smckusick 				       ep->ex_dirp);
654*44015Smckusick 		} else
655*44015Smckusick 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
656*44015Smckusick 			       ep->ex_dirp);
657*44015Smckusick 		cpopt = cpoptend;
658*44015Smckusick 	}
659*44015Smckusick }
660*44015Smckusick 
661*44015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
662*44015Smckusick /*
663*44015Smckusick  * Routines that maintain the remote mounttab
664*44015Smckusick  */
665*44015Smckusick void get_mountlist()
666*44015Smckusick {
667*44015Smckusick 	register struct mountlist *mlp, **mlpp;
668*44015Smckusick 	register char *eos, *dirp;
669*44015Smckusick 	int len;
670*44015Smckusick 	char str[STRSIZ];
671*44015Smckusick 	FILE *mlfile;
672*44015Smckusick 
673*44015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
674*44015Smckusick 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
675*44015Smckusick 		return;
676*44015Smckusick 	}
677*44015Smckusick 	mlpp = &mlhead;
678*44015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
679*44015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
680*44015Smckusick 		    (dirp = index(str, ' ')) == NULL)
681*44015Smckusick 			continue;
682*44015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
683*44015Smckusick 		len = dirp-str;
684*44015Smckusick 		if (len > RPCMNT_NAMELEN)
685*44015Smckusick 			len = RPCMNT_NAMELEN;
686*44015Smckusick 		bcopy(str, mlp->ml_host, len);
687*44015Smckusick 		mlp->ml_host[len] = '\0';
688*44015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
689*44015Smckusick 			dirp++;
690*44015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
691*44015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
692*44015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
693*44015Smckusick 			len = strlen(dirp);
694*44015Smckusick 		else
695*44015Smckusick 			len = eos-dirp;
696*44015Smckusick 		if (len > RPCMNT_PATHLEN)
697*44015Smckusick 			len = RPCMNT_PATHLEN;
698*44015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
699*44015Smckusick 		mlp->ml_dirp[len] = '\0';
700*44015Smckusick 		mlp->ml_next = (struct mountlist *)0;
701*44015Smckusick 		*mlpp = mlp;
702*44015Smckusick 		mlpp = &mlp->ml_next;
703*44015Smckusick 	}
704*44015Smckusick 	fclose(mlfile);
705*44015Smckusick }
706*44015Smckusick 
707*44015Smckusick void del_mlist(hostp, dirp)
708*44015Smckusick 	register char *hostp, *dirp;
709*44015Smckusick {
710*44015Smckusick 	register struct mountlist *mlp, **mlpp;
711*44015Smckusick 	FILE *mlfile;
712*44015Smckusick 	int fnd = 0;
713*44015Smckusick 
714*44015Smckusick 	mlpp = &mlhead;
715*44015Smckusick 	mlp = mlhead;
716*44015Smckusick 	while (mlp) {
717*44015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
718*44015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
719*44015Smckusick 			fnd = 1;
720*44015Smckusick 			*mlpp = mlp->ml_next;
721*44015Smckusick 			free((caddr_t)mlp);
72239681Smckusick 		}
723*44015Smckusick 		mlpp = &mlp->ml_next;
724*44015Smckusick 		mlp = mlp->ml_next;
72539681Smckusick 	}
726*44015Smckusick 	if (fnd) {
727*44015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
728*44015Smckusick 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
729*44015Smckusick 			return;
730*44015Smckusick 		}
731*44015Smckusick 		mlp = mlhead;
732*44015Smckusick 		while (mlp) {
733*44015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
734*44015Smckusick 			mlp = mlp->ml_next;
735*44015Smckusick 		}
736*44015Smckusick 		fclose(mlfile);
737*44015Smckusick 	}
73839681Smckusick }
739*44015Smckusick 
740*44015Smckusick void add_mlist(hostp, dirp)
741*44015Smckusick 	register char *hostp, *dirp;
742*44015Smckusick {
743*44015Smckusick 	register struct mountlist *mlp, **mlpp;
744*44015Smckusick 	FILE *mlfile;
745*44015Smckusick 
746*44015Smckusick 	mlpp = &mlhead;
747*44015Smckusick 	mlp = mlhead;
748*44015Smckusick 	while (mlp) {
749*44015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
750*44015Smckusick 			return;
751*44015Smckusick 		mlpp = &mlp->ml_next;
752*44015Smckusick 		mlp = mlp->ml_next;
753*44015Smckusick 	}
754*44015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
755*44015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
756*44015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
757*44015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
758*44015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
759*44015Smckusick 	mlp->ml_next = (struct mountlist *)0;
760*44015Smckusick 	*mlpp = mlp;
761*44015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
762*44015Smckusick 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
763*44015Smckusick 		return;
764*44015Smckusick 	}
765*44015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
766*44015Smckusick 	fclose(mlfile);
767*44015Smckusick }
768*44015Smckusick 
769*44015Smckusick /*
770*44015Smckusick  * This function is called via. SIGTERM when the system is going down.
771*44015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
772*44015Smckusick  */
773*44015Smckusick send_umntall()
774*44015Smckusick {
775*44015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
776*44015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
777*44015Smckusick 	exit();
778*44015Smckusick }
779*44015Smckusick 
780*44015Smckusick umntall_each(resultsp, raddr)
781*44015Smckusick 	caddr_t resultsp;
782*44015Smckusick 	struct sockaddr_in *raddr;
783*44015Smckusick {
784*44015Smckusick 	return (1);
785*44015Smckusick }
786*44015Smckusick 
787*44015Smckusick /*
788*44015Smckusick  * Free up an exports list component
789*44015Smckusick  */
790*44015Smckusick free_exp(ep)
791*44015Smckusick 	register struct exportlist *ep;
792*44015Smckusick {
793*44015Smckusick 	register struct grouplist *grp;
794*44015Smckusick 	register char **addrp;
795*44015Smckusick 	struct grouplist *grp2;
796*44015Smckusick 
797*44015Smckusick 	grp = ep->ex_groups;
798*44015Smckusick 	while (grp != NULL) {
799*44015Smckusick 		addrp = grp->gr_hp->h_addr_list;
800*44015Smckusick 		while (*addrp)
801*44015Smckusick 			free(*addrp++);
802*44015Smckusick 		free((caddr_t)grp->gr_hp->h_addr_list);
803*44015Smckusick 		free(grp->gr_hp->h_name);
804*44015Smckusick 		free((caddr_t)grp->gr_hp);
805*44015Smckusick 		grp2 = grp;
806*44015Smckusick 		grp = grp->gr_next;
807*44015Smckusick 		free((caddr_t)grp2);
808*44015Smckusick 	}
809*44015Smckusick 	free((caddr_t)ep);
810*44015Smckusick }
811