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