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