Home | History | Annotate | Line # | Download | only in mountd
mountd.c revision 1.8
      1 /*
      2  * Copyright (c) 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Rick Macklem at The University of Guelph.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 char copyright[] =
     39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
     40  All rights reserved.\n";
     41 #endif not lint
     42 
     43 #ifndef lint
     44 /*static char sccsid[] = "from: @(#)mountd.c	5.14 (Berkeley) 2/26/91";*/
     45 static char rcsid[] = "$Id: mountd.c,v 1.8 1993/09/07 15:40:37 ws Exp $";
     46 #endif not lint
     47 
     48 #include <sys/param.h>
     49 #include <sys/ioctl.h>
     50 #include <sys/stat.h>
     51 #include <sys/file.h>
     52 #include <sys/mount.h>
     53 #include <sys/socket.h>
     54 #include <sys/errno.h>
     55 #include <sys/signal.h>
     56 #include <stdio.h>
     57 #include <string.h>
     58 #include <syslog.h>
     59 #include <netdb.h>
     60 #include <rpc/rpc.h>
     61 #include <rpc/pmap_clnt.h>
     62 #include <rpc/pmap_prot.h>
     63 #include <nfs/nfsv2.h>
     64 #include <rpcsvc/mount.h>
     65 #include "pathnames.h"
     66 
     67 struct ufid {
     68 	u_short	ufid_len;
     69 	ino_t	ufid_ino;
     70 	long	ufid_gen;
     71 };
     72 /*
     73  * Structures for keeping the mount list and export list
     74  */
     75 struct mountlist {
     76 	struct mountlist *ml_next;
     77 	char	ml_host[MNTNAMLEN+1];
     78 	char	ml_dirp[MNTPATHLEN+1];
     79 };
     80 
     81 struct exportlist {
     82 	struct exportlist *ex_next;
     83 	struct exportlist *ex_prev;
     84 	struct grouplist *ex_groups;
     85 	int	ex_rootuid;
     86 	int	ex_exflags;
     87 	dev_t	ex_dev;
     88 	char	ex_dirp[MNTPATHLEN+1];
     89 };
     90 
     91 struct grouplist {
     92 	struct grouplist *gr_next;
     93 	struct hostent *gr_hp;
     94 };
     95 
     96 /* Global defs */
     97 void mntsrv();
     98 int umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
     99 void add_mlist(), del_mlist(), get_exportlist(), get_mountlist();
    100 void send_umntall();
    101 struct exportlist exphead;
    102 struct mountlist *mlhead;
    103 char exname[MAXPATHLEN];
    104 int def_rootuid = -2;
    105 int root_only = 1;
    106 extern int errno;
    107 
    108 /*
    109  * Mountd server for NFS mount protocol as described in:
    110  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
    111  * The optional arguments are the exports file name
    112  * default: _PATH_EXPORTS
    113  * and "-n" to allow nonroot mount.
    114  */
    115 main(argc, argv)
    116 	int argc;
    117 	char **argv;
    118 {
    119         FILE *pidfile;
    120 	extern int optind;
    121 	extern char *optarg;
    122         SVCXPRT *transp;
    123 	int c;
    124         int sock = 0;
    125         int proto = 0;
    126         int from_inetd = 1;
    127 	struct sockaddr_in from;
    128 	int fromlen;
    129 
    130 	while ((c = getopt(argc, argv, "n")) != EOF)
    131 		switch (c) {
    132 		case 'n':
    133 			root_only = 0;
    134 			break;
    135 		default:
    136 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
    137 			exit(1);
    138 		};
    139 	argc -= optind;
    140 	argv += optind;
    141 
    142 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
    143 	mlhead = (struct mountlist *)0;
    144 
    145 	if (argc == 1) {
    146 		strncpy(exname, *argv, MAXPATHLEN-1);
    147 		exname[MAXPATHLEN-1] = '\0';
    148 	} else
    149 		strcpy(exname, _PATH_EXPORTS);
    150 
    151         if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
    152                 from_inetd = 0;
    153                 sock = RPC_ANYSOCK;
    154                 proto = IPPROTO_UDP;
    155         }
    156 
    157         if (!from_inetd) {
    158 		daemon(0, 0);
    159                 pmap_unset(MOUNTPROG, MOUNTVERS);
    160 		signal(SIGINT, SIG_IGN);
    161 		signal(SIGQUIT, SIG_IGN);
    162 	}
    163 
    164 	openlog("mountd", LOG_PID, LOG_DAEMON);
    165 
    166 	if ((transp = svcudp_create(sock)) == NULL) {
    167 		syslog(LOG_ERR, "Can't create socket: %m");
    168 		exit(1);
    169 	}
    170 
    171 	if (!svc_register(transp, MOUNTPROG, MOUNTVERS, mntsrv, proto)) {
    172 		syslog(LOG_ERR, "Can't register mount");
    173 		exit(1);
    174 	}
    175 
    176 	get_exportlist();
    177 	get_mountlist();
    178 
    179 	signal(SIGHUP, get_exportlist);
    180 	signal(SIGTERM, send_umntall);
    181 
    182         pidfile = fopen(_PATH_MOUNTDPID, "w");
    183         if (pidfile != NULL) {
    184 		fprintf(pidfile, "%d\n", getpid());
    185 		fclose(pidfile);
    186         }
    187 
    188 	svc_run();
    189 	syslog(LOG_ERR, "Mountd died");
    190 	exit(1);
    191 }
    192 
    193 /*
    194  * The mount rpc service
    195  */
    196 void
    197 mntsrv(rqstp, transp)
    198 	register struct svc_req *rqstp;
    199 	register SVCXPRT *transp;
    200 {
    201 	register struct grouplist *grp;
    202 	register u_long **addrp;
    203 	register struct exportlist *ep;
    204 	nfsv2fh_t nfh;
    205 	struct authunix_parms *ucr;
    206 	struct stat stb;
    207 	struct hostent *hp;
    208 	u_long saddr;
    209 	char dirpath[MNTPATHLEN+1];
    210 	int bad = ENOENT;
    211 	int omask;
    212 	uid_t uid = -2;
    213 
    214 	/* Get authorization */
    215 	switch (rqstp->rq_cred.oa_flavor) {
    216 	case AUTH_UNIX:
    217 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
    218 		uid = ucr->aup_uid;
    219 		break;
    220 	case AUTH_NULL:
    221 	default:
    222 		break;
    223 	}
    224 
    225 	saddr = transp->xp_raddr.sin_addr.s_addr;
    226 	hp = (struct hostent *)0;
    227 	switch (rqstp->rq_proc) {
    228 	case NULLPROC:
    229 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    230 			syslog(LOG_ERR, "Can't send reply");
    231 		return;
    232 	case MOUNTPROC_MNT:
    233 		if (uid != 0 && root_only) {
    234 			svcerr_weakauth(transp);
    235 			return;
    236 		}
    237 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
    238 			svcerr_decode(transp);
    239 			return;
    240 		}
    241 
    242 		/* Check to see if it's a valid dirpath */
    243 		if (stat(dirpath, &stb) < 0 || (stb.st_mode&S_IFMT) !=
    244 			S_IFDIR) {
    245 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    246 				syslog(LOG_ERR, "Can't send reply");
    247 			return;
    248 		}
    249 
    250 		/* Check in the exports list */
    251 		omask = sigblock(sigmask(SIGHUP));
    252 		ep = exphead.ex_next;
    253 		while (ep != NULL) {
    254 			if (!strcmp(ep->ex_dirp, dirpath)) {
    255 				grp = ep->ex_groups;
    256 				if (grp == NULL)
    257 					break;
    258 
    259 				/* Check for a host match */
    260 				addrp = (u_long **)grp->gr_hp->h_addr_list;
    261 				for (;;) {
    262 					if (**addrp == saddr)
    263 						break;
    264 					if (*++addrp == NULL)
    265 						if (grp = grp->gr_next) {
    266 							addrp = (u_long **)
    267 								grp->gr_hp->h_addr_list;
    268 						} else {
    269 							bad = EACCES;
    270 							if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    271 								syslog(LOG_ERR, "Can't send reply");
    272 							sigsetmask(omask);
    273 							return;
    274 						}
    275 				}
    276 				hp = grp->gr_hp;
    277 				break;
    278 			}
    279 			ep = ep->ex_next;
    280 		}
    281 		sigsetmask(omask);
    282 		if (ep == NULL) {
    283 			bad = EACCES;
    284 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    285 				syslog(LOG_ERR, "Can't send reply");
    286 			return;
    287 		}
    288 
    289 		/* Get the file handle */
    290 		bzero((caddr_t)&nfh, sizeof(nfh));
    291 		if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
    292 			bad = errno;
    293 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
    294 				syslog(LOG_ERR, "Can't send reply");
    295 			return;
    296 		}
    297 		if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
    298 			syslog(LOG_ERR, "Can't send reply");
    299 		if (hp == NULL)
    300 			hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    301 		if (hp)
    302 			add_mlist(hp->h_name, dirpath);
    303 		return;
    304 	case MOUNTPROC_DUMP:
    305 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
    306 			syslog(LOG_ERR, "Can't send reply");
    307 		return;
    308 	case MOUNTPROC_UMNT:
    309 		if (uid != 0 && root_only) {
    310 			svcerr_weakauth(transp);
    311 			return;
    312 		}
    313 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
    314 			svcerr_decode(transp);
    315 			return;
    316 		}
    317 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    318 			syslog(LOG_ERR, "Can't send reply");
    319 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    320 		if (hp)
    321 			del_mlist(hp->h_name, dirpath);
    322 		return;
    323 	case MOUNTPROC_UMNTALL:
    324 		if (uid != 0 && root_only) {
    325 			svcerr_weakauth(transp);
    326 			return;
    327 		}
    328 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
    329 			syslog(LOG_ERR, "Can't send reply");
    330 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
    331 		if (hp)
    332 			del_mlist(hp->h_name, (char *)0);
    333 		return;
    334 	case MOUNTPROC_EXPORT:
    335         case MOUNTPROC_EXPORTALL:
    336                 get_exportlist();
    337 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)exphead.ex_next))
    338 			syslog(LOG_ERR, "Can't send reply");
    339 		return;
    340 	default:
    341 		svcerr_noproc(transp);
    342 		return;
    343 	}
    344 }
    345 
    346 /*
    347  * Xdr conversion for a dirpath string
    348  */
    349 xdr_dir(xdrsp, dirp)
    350 	XDR *xdrsp;
    351 	char *dirp;
    352 {
    353 	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
    354 }
    355 
    356 /*
    357  * Xdr routine to generate fhstatus
    358  */
    359 xdr_fhs(xdrsp, nfh)
    360 	XDR *xdrsp;
    361 	nfsv2fh_t *nfh;
    362 {
    363 	long ok = 0;
    364 
    365 	if (!xdr_long(xdrsp, &ok))
    366 		return (0);
    367 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
    368 }
    369 
    370 xdr_mlist(xdrsp, cp)
    371 	XDR *xdrsp;
    372 	caddr_t cp;
    373 {
    374 	register struct mountlist *mlp;
    375 	int true = 1;
    376 	int false = 0;
    377 	char *strp;
    378 
    379 	mlp = mlhead;
    380 	while (mlp) {
    381 		if (!xdr_bool(xdrsp, &true))
    382 			return (0);
    383 		strp = &mlp->ml_host[0];
    384 		if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
    385 			return (0);
    386 		strp = &mlp->ml_dirp[0];
    387 		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
    388 			return (0);
    389 		mlp = mlp->ml_next;
    390 	}
    391 	if (!xdr_bool(xdrsp, &false))
    392 		return (0);
    393 	return (1);
    394 }
    395 
    396 /*
    397  * Xdr conversion for export list
    398  */
    399 xdr_explist(xdrsp, cp)
    400 	XDR *xdrsp;
    401 	caddr_t cp;
    402 {
    403 	register struct exportlist *ep = (struct exportlist *)cp;
    404 	register struct grouplist *grp;
    405 	int true = 1;
    406 	int false = 0;
    407 	char *strp;
    408 	int omask;
    409 
    410 	omask = sigblock(sigmask(SIGHUP));
    411 	while (ep != NULL) {
    412 		if (!xdr_bool(xdrsp, &true))
    413 			goto errout;
    414 		strp = &ep->ex_dirp[0];
    415 		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
    416 			goto errout;
    417 		grp = ep->ex_groups;
    418 		while (grp != NULL) {
    419 			if (!xdr_bool(xdrsp, &true))
    420 				goto errout;
    421 			strp = grp->gr_hp->h_name;
    422 			if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
    423 				goto errout;
    424 			grp = grp->gr_next;
    425 		}
    426 		if (!xdr_bool(xdrsp, &false))
    427 			goto errout;
    428 		ep = ep->ex_next;
    429 	}
    430 	sigsetmask(omask);
    431 	if (!xdr_bool(xdrsp, &false))
    432 		return (0);
    433 	return (1);
    434 errout:
    435 	sigsetmask(omask);
    436 	return (0);
    437 }
    438 
    439 #define LINESIZ	10240
    440 char line[LINESIZ];
    441 
    442 /*
    443  * Get the export list
    444  */
    445 
    446 void
    447 get_exportlist()
    448 {
    449 	register struct hostent *hp, *nhp;
    450 	register char **addrp, **naddrp;
    451 	register int i;
    452 	register struct grouplist *grp;
    453 	register struct exportlist *ep, *ep2;
    454 	struct statfs stfsbuf;
    455 	struct export_args args;
    456 	struct stat sb;
    457 	FILE *inf;
    458 	char *cp, *endcp;
    459 	char savedc;
    460 	int len, dirplen;
    461 	int rootuid, exflags;
    462 	u_long saddr;
    463 	struct exportlist *fep;
    464         static int first = 0;
    465         static struct stat last_exportstat;
    466 
    467         /*
    468          * Check if the file has changed
    469          */
    470         if (first++) {
    471                 if (stat(exname, &sb) < 0) {
    472                         syslog(LOG_ERR, "stat of export file %s failed. %m", exname);
    473                         ep = exphead.ex_next;
    474                         while (ep != NULL) {
    475                                 ep2 = ep;
    476                                 ep = ep->ex_next;
    477                                 free_exp(ep2);
    478                         }
    479                         return;
    480                 }
    481                 if (last_exportstat.st_mtime == sb.st_mtime)
    482                         return;
    483         }
    484 
    485 	/*
    486 	 * First, get rid of the old list
    487 	 */
    488 	ep = exphead.ex_next;
    489 	while (ep != NULL) {
    490 		ep2 = ep;
    491 		ep = ep->ex_next;
    492 		free_exp(ep2);
    493 	}
    494 
    495 	/*
    496 	 * Read in the exports file and build the list, calling
    497 	 * exportfs() as we go along
    498 	 */
    499 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
    500 	if ((inf = fopen(exname, "r")) == NULL) {
    501 		syslog(LOG_ERR, "Can't open %s", exname);
    502 		exit(2);
    503 	}
    504 	while (fgets(line, LINESIZ, inf)) {
    505 		exflags = MNT_EXPORTED;
    506 		rootuid = def_rootuid;
    507 		cp = line;
    508 		nextfield(&cp, &endcp);
    509 
    510 		/*
    511 		 * Get file system devno and see if an entry for this
    512 		 * file system already exists.
    513 		 */
    514 		savedc = *endcp;
    515 		*endcp = '\0';
    516 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
    517 			syslog(LOG_ERR,
    518 			    "Bad Exports File, %s: %s, mountd Failed",
    519 			    cp, "Not a directory");
    520 			exit(2);
    521 		}
    522 		fep = (struct exportlist *)0;
    523 		ep = exphead.ex_next;
    524 		while (ep) {
    525 			if (ep->ex_dev == sb.st_dev) {
    526 				fep = ep;
    527 				break;
    528 			}
    529 			ep = ep->ex_next;
    530 		}
    531 		*endcp = savedc;
    532 
    533 		/*
    534 		 * Create new exports list entry
    535 		 */
    536 		len = endcp-cp;
    537 		if (len <= MNTPATHLEN && len > 0) {
    538 			ep = (struct exportlist *)malloc(sizeof(*ep));
    539 			if (ep == NULL)
    540 				goto err;
    541 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
    542 			ep->ex_groups = (struct grouplist *)0;
    543 			bcopy(cp, ep->ex_dirp, len);
    544 			ep->ex_dirp[len] = '\0';
    545 			dirplen = len;
    546 		} else {
    547 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
    548 			exit(2);
    549 		}
    550 		cp = endcp;
    551 		nextfield(&cp, &endcp);
    552 		len = endcp-cp;
    553 		while (len > 0) {
    554 			savedc = *endcp;
    555 			*endcp = '\0';
    556 			if (len > MNTNAMLEN)
    557 				goto more;
    558 			if (*cp == '-') {
    559 				do_opt(cp + 1, fep, ep, &exflags, &rootuid);
    560 				goto more;
    561 			}
    562 			if (isdigit(*cp)) {
    563 				saddr = inet_addr(cp);
    564 				if (saddr == -1 ||
    565 				    (hp = gethostbyaddr((caddr_t)&saddr,
    566 				     sizeof(saddr), AF_INET)) == NULL) {
    567 					syslog(LOG_ERR,
    568 					    "Bad Exports File, %s: %s", cp,
    569 					    "Gethostbyaddr failed, ignored");
    570 					goto more;
    571 				}
    572 			} else if ((hp = gethostbyname(cp)) == NULL) {
    573 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
    574 				    cp, "Gethostbyname failed, ignored");
    575 				goto more;
    576 			}
    577 			grp = (struct grouplist *)
    578 				malloc(sizeof(struct grouplist));
    579 			if (grp == NULL)
    580 				goto err;
    581 			nhp = grp->gr_hp = (struct hostent *)
    582 				malloc(sizeof(struct hostent));
    583 			if (nhp == NULL)
    584 				goto err;
    585 			bcopy((caddr_t)hp, (caddr_t)nhp,
    586 				sizeof(struct hostent));
    587 			i = strlen(hp->h_name)+1;
    588 			nhp->h_name = (char *)malloc(i);
    589 			if (nhp->h_name == NULL)
    590 				goto err;
    591 			bcopy(hp->h_name, nhp->h_name, i);
    592 			addrp = hp->h_addr_list;
    593 			i = 1;
    594 			while (*addrp++)
    595 				i++;
    596 			naddrp = nhp->h_addr_list = (char **)
    597 				malloc(i*sizeof(char *));
    598 			if (naddrp == NULL)
    599 				goto err;
    600 			addrp = hp->h_addr_list;
    601 			while (*addrp) {
    602 				*naddrp = (char *)
    603 				    malloc(hp->h_length);
    604 				if (*naddrp == NULL)
    605 				    goto err;
    606 				bcopy(*addrp, *naddrp,
    607 					hp->h_length);
    608 				addrp++;
    609 				naddrp++;
    610 			}
    611 			*naddrp = (char *)0;
    612 			grp->gr_next = ep->ex_groups;
    613 			ep->ex_groups = grp;
    614 		more:
    615 			cp = endcp;
    616 			*cp = savedc;
    617 			nextfield(&cp, &endcp);
    618 			len = endcp - cp;
    619 		}
    620 		if (fep == NULL) {
    621 			args.exroot = rootuid;
    622 			cp = (char *)0;
    623 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
    624 			       mount(MOUNT_EXPORT, ep->ex_dirp,
    625 				     stfsbuf.f_flags|(MNT_UPDATE|exflags),
    626 				     &args) < 0) {
    627 /* 08 Sep 92*/			if (cp)
    628 					*cp-- = savedc;
    629 				else
    630 					cp = ep->ex_dirp + dirplen - 1;
    631 #ifdef OMIT
    632 				if (cp == NULL)
    633 					cp = ep->ex_dirp + dirplen - 1;
    634 				else
    635 					*cp = savedc;
    636 #endif	/* OMIT*/
    637 				/* back up over the last component */
    638 				while (*cp == '/' && cp > ep->ex_dirp)
    639 					cp--;
    640 /* 08 Sep 92*/			while (cp > ep->ex_dirp && *(cp - 1) != '/')
    641 					cp--;
    642 				if (cp == ep->ex_dirp) {
    643 					syslog(LOG_WARNING,
    644 					      "Can't export %s", ep->ex_dirp);
    645 					free_exp(ep);
    646 					goto nextline;
    647 				}
    648 				savedc = *cp;
    649 				*cp = '\0';
    650 			}
    651 			if (cp)
    652 				*cp = savedc;
    653 			ep->ex_rootuid = rootuid;
    654 			ep->ex_exflags = exflags;
    655 		} else {
    656 			ep->ex_rootuid = fep->ex_rootuid;
    657 			ep->ex_exflags = fep->ex_exflags;
    658 		}
    659 		ep->ex_dev = sb.st_dev;
    660 		ep->ex_next = exphead.ex_next;
    661 		ep->ex_prev = &exphead;
    662 		if (ep->ex_next != NULL)
    663 			ep->ex_next->ex_prev = ep;
    664 		exphead.ex_next = ep;
    665 nextline:
    666 		;
    667 	}
    668 	fclose(inf);
    669 	return;
    670 err:
    671 	syslog(LOG_ERR, "No more memory: mountd Failed");
    672 	exit(2);
    673 }
    674 
    675 /*
    676  * Parse out the next white space separated field
    677  */
    678 nextfield(cp, endcp)
    679 	char **cp;
    680 	char **endcp;
    681 {
    682 	register char *p;
    683 
    684 	p = *cp;
    685 	while (*p == ' ' || *p == '\t')
    686 		p++;
    687 	if (*p == '\n' || *p == '\0') {
    688 		*cp = *endcp = p;
    689 		return;
    690 	}
    691 	*cp = p++;
    692 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
    693 		p++;
    694 	*endcp = p;
    695 }
    696 
    697 /*
    698  * Parse the option string
    699  */
    700 do_opt(cpopt, fep, ep, exflagsp, rootuidp)
    701 	register char *cpopt;
    702 	struct exportlist *fep, *ep;
    703 	int *exflagsp, *rootuidp;
    704 {
    705 	register char *cpoptarg, *cpoptend;
    706 
    707 	while (cpopt && *cpopt) {
    708 		if (cpoptend = index(cpopt, ','))
    709 			*cpoptend++ = '\0';
    710 		if (cpoptarg = index(cpopt, '='))
    711 			*cpoptarg++ = '\0';
    712 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
    713 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
    714 				syslog(LOG_WARNING, "ro failed for %s",
    715 				       ep->ex_dirp);
    716 			else
    717 				*exflagsp |= MNT_EXRDONLY;
    718 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
    719 			if (cpoptarg && isdigit(*cpoptarg)) {
    720 				*rootuidp = atoi(cpoptarg);
    721 				if (fep && fep->ex_rootuid != *rootuidp)
    722 					syslog(LOG_WARNING,
    723 					       "uid failed for %s",
    724 					       ep->ex_dirp);
    725 			} else
    726 				syslog(LOG_WARNING,
    727 				       "uid failed for %s",
    728 				       ep->ex_dirp);
    729 		} else
    730 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
    731 			       ep->ex_dirp);
    732 		cpopt = cpoptend;
    733 	}
    734 }
    735 
    736 #define	STRSIZ	(MNTNAMLEN+MNTPATHLEN+50)
    737 /*
    738  * Routines that maintain the remote mounttab
    739  */
    740 void get_mountlist()
    741 {
    742 	register struct mountlist *mlp, **mlpp;
    743 	register char *eos, *dirp;
    744 	int len;
    745 	char str[STRSIZ];
    746 	FILE *mlfile;
    747 
    748 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
    749 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
    750 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
    751 		return;
    752 	}
    753 	mlpp = &mlhead;
    754 	while (fgets(str, STRSIZ, mlfile) != NULL) {
    755 		if ((dirp = index(str, '\t')) == NULL &&
    756 		    (dirp = index(str, ' ')) == NULL)
    757 			continue;
    758 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
    759 		len = dirp-str;
    760 		if (len > MNTNAMLEN)
    761 			len = MNTNAMLEN;
    762 		bcopy(str, mlp->ml_host, len);
    763 		mlp->ml_host[len] = '\0';
    764 		while (*dirp == '\t' || *dirp == ' ')
    765 			dirp++;
    766 		if ((eos = index(dirp, '\t')) == NULL &&
    767 		    (eos = index(dirp, ' ')) == NULL &&
    768 		    (eos = index(dirp, '\n')) == NULL)
    769 			len = strlen(dirp);
    770 		else
    771 			len = eos-dirp;
    772 		if (len > MNTPATHLEN)
    773 			len = MNTPATHLEN;
    774 		bcopy(dirp, mlp->ml_dirp, len);
    775 		mlp->ml_dirp[len] = '\0';
    776 		mlp->ml_next = (struct mountlist *)0;
    777 		*mlpp = mlp;
    778 		mlpp = &mlp->ml_next;
    779 	}
    780 	fclose(mlfile);
    781 }
    782 
    783 void del_mlist(hostp, dirp)
    784 	register char *hostp, *dirp;
    785 {
    786 	register struct mountlist *mlp, **mlpp;
    787 	FILE *mlfile;
    788 	int fnd = 0;
    789 
    790 	mlpp = &mlhead;
    791 	mlp = mlhead;
    792 	while (mlp) {
    793 		if (!strcmp(mlp->ml_host, hostp) &&
    794 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
    795 			fnd = 1;
    796 			*mlpp = mlp->ml_next;
    797 			free((caddr_t)mlp);
    798 		}
    799 		mlpp = &mlp->ml_next;
    800 		mlp = mlp->ml_next;
    801 	}
    802 	if (fnd) {
    803 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
    804 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    805 			return;
    806 		}
    807 		mlp = mlhead;
    808 		while (mlp) {
    809 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    810 			mlp = mlp->ml_next;
    811 		}
    812 		fclose(mlfile);
    813 	}
    814 }
    815 
    816 void add_mlist(hostp, dirp)
    817 	register char *hostp, *dirp;
    818 {
    819 	register struct mountlist *mlp, **mlpp;
    820 	FILE *mlfile;
    821 
    822 	mlpp = &mlhead;
    823 	mlp = mlhead;
    824 	while (mlp) {
    825 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
    826 			return;
    827 		mlpp = &mlp->ml_next;
    828 		mlp = mlp->ml_next;
    829 	}
    830 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
    831 	strncpy(mlp->ml_host, hostp, MNTNAMLEN);
    832 	mlp->ml_host[MNTNAMLEN] = '\0';
    833 	strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
    834 	mlp->ml_dirp[MNTPATHLEN] = '\0';
    835 	mlp->ml_next = (struct mountlist *)0;
    836 	*mlpp = mlp;
    837 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
    838 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    839 		return;
    840 	}
    841 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    842 	fclose(mlfile);
    843 }
    844 
    845 /*
    846  * This function is called via. SIGTERM when the system is going down.
    847  * It sends a broadcast RPCMNT_UMNTALL.
    848  */
    849 void
    850 send_umntall()
    851 {
    852 	(void) clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL,
    853 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
    854 	exit();
    855 }
    856 
    857 umntall_each(resultsp, raddr)
    858 	caddr_t resultsp;
    859 	struct sockaddr_in *raddr;
    860 {
    861 	return (1);
    862 }
    863 
    864 /*
    865  * Free up an exports list component
    866  */
    867 free_exp(ep)
    868 	register struct exportlist *ep;
    869 {
    870 	register struct grouplist *grp;
    871 	register char **addrp;
    872 	struct grouplist *grp2;
    873 
    874 	grp = ep->ex_groups;
    875 	while (grp != NULL) {
    876 		addrp = grp->gr_hp->h_addr_list;
    877 		while (*addrp)
    878 			free(*addrp++);
    879 		free((caddr_t)grp->gr_hp->h_addr_list);
    880 		free(grp->gr_hp->h_name);
    881 		free((caddr_t)grp->gr_hp);
    882 		grp2 = grp;
    883 		grp = grp->gr_next;
    884 		free((caddr_t)grp2);
    885 	}
    886 	free((caddr_t)ep);
    887 }
    888