Home | History | Annotate | Line # | Download | only in mountd
mountd.c revision 1.9
      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.9 1993/09/09 16:34:34 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 || (stb.st_mode&S_IFMT) !=
    245 			S_IFDIR) {
    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 	struct export_args args;
    458 	struct stat sb;
    459 	FILE *inf;
    460 	char *cp, *endcp;
    461 	char savedc;
    462 	int len, dirplen;
    463 	int rootuid, exflags, alldirflg;
    464 	u_long saddr;
    465 	struct exportlist *fep;
    466         static int first = 0;
    467         static struct stat last_exportstat;
    468 
    469         /*
    470          * Check if the file has changed
    471          */
    472         if (first++) {
    473                 if (stat(exname, &sb) < 0) {
    474                         syslog(LOG_ERR, "stat of export file %s failed. %m", exname);
    475                         ep = exphead.ex_next;
    476                         while (ep != NULL) {
    477                                 ep2 = ep;
    478                                 ep = ep->ex_next;
    479                                 free_exp(ep2);
    480                         }
    481                         return;
    482                 }
    483                 if (last_exportstat.st_mtime == sb.st_mtime)
    484                         return;
    485         }
    486 
    487 	/*
    488 	 * First, get rid of the old list
    489 	 */
    490 	ep = exphead.ex_next;
    491 	while (ep != NULL) {
    492 		ep2 = ep;
    493 		ep = ep->ex_next;
    494 		free_exp(ep2);
    495 	}
    496 
    497 	/*
    498 	 * Read in the exports file and build the list, calling
    499 	 * exportfs() as we go along
    500 	 */
    501 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
    502 	if ((inf = fopen(exname, "r")) == NULL) {
    503 		syslog(LOG_ERR, "Can't open %s", exname);
    504 		exit(2);
    505 	}
    506 	while (fgets(line, LINESIZ, inf)) {
    507 		exflags = MNT_EXPORTED;
    508 		rootuid = def_rootuid;
    509 		alldirflg = 0;
    510 		cp = line;
    511 		nextfield(&cp, &endcp);
    512 
    513 		/*
    514 		 * Get file system devno and see if an entry for this
    515 		 * file system already exists.
    516 		 */
    517 		savedc = *endcp;
    518 		*endcp = '\0';
    519 		if (stat(cp, &sb) < 0 || (sb.st_mode & S_IFMT) != S_IFDIR) {
    520 			syslog(LOG_ERR,
    521 			    "Bad Exports File, %s: %s, mountd Failed",
    522 			    cp, "Not a directory");
    523 			exit(2);
    524 		}
    525 		fep = (struct exportlist *)0;
    526 		ep = exphead.ex_next;
    527 		while (ep) {
    528 			if (ep->ex_dev == sb.st_dev) {
    529 				fep = ep;
    530 				break;
    531 			}
    532 			ep = ep->ex_next;
    533 		}
    534 		*endcp = savedc;
    535 
    536 		/*
    537 		 * Create new exports list entry
    538 		 */
    539 		len = endcp-cp;
    540 		if (len <= MNTPATHLEN && len > 0) {
    541 			ep = (struct exportlist *)malloc(sizeof(*ep));
    542 			if (ep == NULL)
    543 				goto err;
    544 			ep->ex_next = ep->ex_prev = (struct exportlist *)0;
    545 			ep->ex_groups = (struct grouplist *)0;
    546 			bcopy(cp, ep->ex_dirp, len);
    547 			ep->ex_dirp[len] = '\0';
    548 			dirplen = len;
    549 		} else {
    550 			syslog(LOG_ERR, "Bad Exports File, mountd Failed");
    551 			exit(2);
    552 		}
    553 		cp = endcp;
    554 		nextfield(&cp, &endcp);
    555 		len = endcp-cp;
    556 		while (len > 0) {
    557 			savedc = *endcp;
    558 			*endcp = '\0';
    559 			if (len > MNTNAMLEN)
    560 				goto more;
    561 			if (*cp == '-') {
    562 				do_opt(cp + 1, fep, ep, &exflags, &rootuid,
    563 					&alldirflg);
    564 				goto more;
    565 			}
    566 			if (isdigit(*cp)) {
    567 				saddr = inet_addr(cp);
    568 				if (saddr == -1 ||
    569 				    (hp = gethostbyaddr((caddr_t)&saddr,
    570 				     sizeof(saddr), AF_INET)) == NULL) {
    571 					syslog(LOG_ERR,
    572 					    "Bad Exports File, %s: %s", cp,
    573 					    "Gethostbyaddr failed, ignored");
    574 					goto more;
    575 				}
    576 			} else if ((hp = gethostbyname(cp)) == NULL) {
    577 				syslog(LOG_ERR, "Bad Exports File, %s: %s",
    578 				    cp, "Gethostbyname failed, ignored");
    579 				goto more;
    580 			}
    581 			grp = (struct grouplist *)
    582 				malloc(sizeof(struct grouplist));
    583 			if (grp == NULL)
    584 				goto err;
    585 			nhp = grp->gr_hp = (struct hostent *)
    586 				malloc(sizeof(struct hostent));
    587 			if (nhp == NULL)
    588 				goto err;
    589 			bcopy((caddr_t)hp, (caddr_t)nhp,
    590 				sizeof(struct hostent));
    591 			i = strlen(hp->h_name)+1;
    592 			nhp->h_name = (char *)malloc(i);
    593 			if (nhp->h_name == NULL)
    594 				goto err;
    595 			bcopy(hp->h_name, nhp->h_name, i);
    596 			addrp = hp->h_addr_list;
    597 			i = 1;
    598 			while (*addrp++)
    599 				i++;
    600 			naddrp = nhp->h_addr_list = (char **)
    601 				malloc(i*sizeof(char *));
    602 			if (naddrp == NULL)
    603 				goto err;
    604 			addrp = hp->h_addr_list;
    605 			while (*addrp) {
    606 				*naddrp = (char *)
    607 				    malloc(hp->h_length);
    608 				if (*naddrp == NULL)
    609 				    goto err;
    610 				bcopy(*addrp, *naddrp,
    611 					hp->h_length);
    612 				addrp++;
    613 				naddrp++;
    614 			}
    615 			*naddrp = (char *)0;
    616 			grp->gr_next = ep->ex_groups;
    617 			ep->ex_groups = grp;
    618 		more:
    619 			cp = endcp;
    620 			*cp = savedc;
    621 			nextfield(&cp, &endcp);
    622 			len = endcp - cp;
    623 		}
    624 		if (fep == NULL) {
    625 			args.exroot = rootuid;
    626 			cp = (char *)0;
    627 			while (statfs(ep->ex_dirp, &stfsbuf) < 0 ||
    628 			       mount(MOUNT_EXPORT, ep->ex_dirp,
    629 				     stfsbuf.f_flags|(MNT_UPDATE|exflags),
    630 				     &args) < 0) {
    631 /* 08 Sep 92*/			if (cp)
    632 					*cp-- = savedc;
    633 				else
    634 					cp = ep->ex_dirp + dirplen - 1;
    635 #ifdef OMIT
    636 				if (cp == NULL)
    637 					cp = ep->ex_dirp + dirplen - 1;
    638 				else
    639 					*cp = savedc;
    640 #endif	/* OMIT*/
    641 				/* back up over the last component */
    642 				while (*cp == '/' && cp > ep->ex_dirp)
    643 					cp--;
    644 /* 08 Sep 92*/			while (cp > ep->ex_dirp && *(cp - 1) != '/')
    645 					cp--;
    646 				if (cp == ep->ex_dirp) {
    647 					syslog(LOG_WARNING,
    648 					      "Can't export %s", ep->ex_dirp);
    649 					free_exp(ep);
    650 					goto nextline;
    651 				}
    652 				savedc = *cp;
    653 				*cp = '\0';
    654 			}
    655 			if (cp)
    656 				*cp = savedc;
    657 			ep->ex_rootuid = rootuid;
    658 			ep->ex_exflags = exflags;
    659 			ep->ex_alldirflg = alldirflg;
    660 		} else {
    661 			if (alldirflg || fep->ex_alldirflg) {
    662 				syslog(LOG_WARNING,
    663 				    "Can't export alldirs plus other exports");
    664 				free_exp(ep);
    665 				goto nextline;
    666 			}
    667 			ep->ex_rootuid = fep->ex_rootuid;
    668 			ep->ex_exflags = fep->ex_exflags;
    669 			ep->ex_alldirflg = 0;
    670 		}
    671 		ep->ex_dev = sb.st_dev;
    672 		ep->ex_next = exphead.ex_next;
    673 		ep->ex_prev = &exphead;
    674 		if (ep->ex_next != NULL)
    675 			ep->ex_next->ex_prev = ep;
    676 		exphead.ex_next = ep;
    677 nextline:
    678 		;
    679 	}
    680 	fclose(inf);
    681 	return;
    682 err:
    683 	syslog(LOG_ERR, "No more memory: mountd Failed");
    684 	exit(2);
    685 }
    686 
    687 /*
    688  * Parse out the next white space separated field
    689  */
    690 nextfield(cp, endcp)
    691 	char **cp;
    692 	char **endcp;
    693 {
    694 	register char *p;
    695 
    696 	p = *cp;
    697 	while (*p == ' ' || *p == '\t')
    698 		p++;
    699 	if (*p == '\n' || *p == '\0') {
    700 		*cp = *endcp = p;
    701 		return;
    702 	}
    703 	*cp = p++;
    704 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
    705 		p++;
    706 	*endcp = p;
    707 }
    708 
    709 /*
    710  * Parse the option string
    711  */
    712 do_opt(cpopt, fep, ep, exflagsp, rootuidp, alldirflgp)
    713 	register char *cpopt;
    714 	struct exportlist *fep, *ep;
    715 	int *exflagsp, *rootuidp, *alldirflgp;
    716 {
    717 	register char *cpoptarg, *cpoptend;
    718 
    719 	while (cpopt && *cpopt) {
    720 		if (cpoptend = index(cpopt, ','))
    721 			*cpoptend++ = '\0';
    722 		if (cpoptarg = index(cpopt, '='))
    723 			*cpoptarg++ = '\0';
    724 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
    725 			if (fep && (fep->ex_exflags & MNT_EXRDONLY) == 0)
    726 				syslog(LOG_WARNING, "ro failed for %s",
    727 				       ep->ex_dirp);
    728 			else
    729 				*exflagsp |= MNT_EXRDONLY;
    730 		} else if (!strcmp(cpopt, "root") || !strcmp(cpopt, "r")) {
    731 			if (cpoptarg && isdigit(*cpoptarg)) {
    732 				*rootuidp = atoi(cpoptarg);
    733 				if (fep && fep->ex_rootuid != *rootuidp)
    734 					syslog(LOG_WARNING,
    735 					       "uid failed for %s",
    736 					       ep->ex_dirp);
    737 			} else
    738 				syslog(LOG_WARNING,
    739 				       "uid failed for %s",
    740 				       ep->ex_dirp);
    741 		} else if (!strcmp(cpopt, "alldirs") || !strcmp(cpopt, "a")) {
    742 			*alldirflgp = 1;
    743 		} else
    744 			syslog(LOG_WARNING, "opt %s ignored for %s", cpopt,
    745 			       ep->ex_dirp);
    746 		cpopt = cpoptend;
    747 	}
    748 }
    749 
    750 #define	STRSIZ	(MNTNAMLEN+MNTPATHLEN+50)
    751 /*
    752  * Routines that maintain the remote mounttab
    753  */
    754 void get_mountlist()
    755 {
    756 	register struct mountlist *mlp, **mlpp;
    757 	register char *eos, *dirp;
    758 	int len;
    759 	char str[STRSIZ];
    760 	FILE *mlfile;
    761 
    762 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
    763 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
    764 		syslog(LOG_WARNING, "Can't open %s", _PATH_RMOUNTLIST);
    765 		return;
    766 	}
    767 	mlpp = &mlhead;
    768 	while (fgets(str, STRSIZ, mlfile) != NULL) {
    769 		if ((dirp = index(str, '\t')) == NULL &&
    770 		    (dirp = index(str, ' ')) == NULL)
    771 			continue;
    772 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
    773 		len = dirp-str;
    774 		if (len > MNTNAMLEN)
    775 			len = MNTNAMLEN;
    776 		bcopy(str, mlp->ml_host, len);
    777 		mlp->ml_host[len] = '\0';
    778 		while (*dirp == '\t' || *dirp == ' ')
    779 			dirp++;
    780 		if ((eos = index(dirp, '\t')) == NULL &&
    781 		    (eos = index(dirp, ' ')) == NULL &&
    782 		    (eos = index(dirp, '\n')) == NULL)
    783 			len = strlen(dirp);
    784 		else
    785 			len = eos-dirp;
    786 		if (len > MNTPATHLEN)
    787 			len = MNTPATHLEN;
    788 		bcopy(dirp, mlp->ml_dirp, len);
    789 		mlp->ml_dirp[len] = '\0';
    790 		mlp->ml_next = (struct mountlist *)0;
    791 		*mlpp = mlp;
    792 		mlpp = &mlp->ml_next;
    793 	}
    794 	fclose(mlfile);
    795 }
    796 
    797 void del_mlist(hostp, dirp)
    798 	register char *hostp, *dirp;
    799 {
    800 	register struct mountlist *mlp, **mlpp;
    801 	FILE *mlfile;
    802 	int fnd = 0;
    803 
    804 	mlpp = &mlhead;
    805 	mlp = mlhead;
    806 	while (mlp) {
    807 		if (!strcmp(mlp->ml_host, hostp) &&
    808 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
    809 			fnd = 1;
    810 			*mlpp = mlp->ml_next;
    811 			free((caddr_t)mlp);
    812 		}
    813 		mlpp = &mlp->ml_next;
    814 		mlp = mlp->ml_next;
    815 	}
    816 	if (fnd) {
    817 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
    818 			syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    819 			return;
    820 		}
    821 		mlp = mlhead;
    822 		while (mlp) {
    823 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    824 			mlp = mlp->ml_next;
    825 		}
    826 		fclose(mlfile);
    827 	}
    828 }
    829 
    830 void add_mlist(hostp, dirp)
    831 	register char *hostp, *dirp;
    832 {
    833 	register struct mountlist *mlp, **mlpp;
    834 	FILE *mlfile;
    835 
    836 	mlpp = &mlhead;
    837 	mlp = mlhead;
    838 	while (mlp) {
    839 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
    840 			return;
    841 		mlpp = &mlp->ml_next;
    842 		mlp = mlp->ml_next;
    843 	}
    844 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
    845 	strncpy(mlp->ml_host, hostp, MNTNAMLEN);
    846 	mlp->ml_host[MNTNAMLEN] = '\0';
    847 	strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
    848 	mlp->ml_dirp[MNTPATHLEN] = '\0';
    849 	mlp->ml_next = (struct mountlist *)0;
    850 	*mlpp = mlp;
    851 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
    852 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
    853 		return;
    854 	}
    855 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
    856 	fclose(mlfile);
    857 }
    858 
    859 /*
    860  * This function is called via. SIGTERM when the system is going down.
    861  * It sends a broadcast RPCMNT_UMNTALL.
    862  */
    863 void
    864 send_umntall()
    865 {
    866 	(void) clnt_broadcast(MOUNTPROG, MOUNTVERS, MOUNTPROC_UMNTALL,
    867 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
    868 	exit();
    869 }
    870 
    871 umntall_each(resultsp, raddr)
    872 	caddr_t resultsp;
    873 	struct sockaddr_in *raddr;
    874 {
    875 	return (1);
    876 }
    877 
    878 /*
    879  * Free up an exports list component
    880  */
    881 free_exp(ep)
    882 	register struct exportlist *ep;
    883 {
    884 	register struct grouplist *grp;
    885 	register char **addrp;
    886 	struct grouplist *grp2;
    887 
    888 	grp = ep->ex_groups;
    889 	while (grp != NULL) {
    890 		addrp = grp->gr_hp->h_addr_list;
    891 		while (*addrp)
    892 			free(*addrp++);
    893 		free((caddr_t)grp->gr_hp->h_addr_list);
    894 		free(grp->gr_hp->h_name);
    895 		free((caddr_t)grp->gr_hp);
    896 		grp2 = grp;
    897 		grp = grp->gr_next;
    898 		free((caddr_t)grp2);
    899 	}
    900 	free((caddr_t)ep);
    901 }
    902