xref: /csrg-svn/sbin/mountd/mountd.c (revision 51667)
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  * Herb Hasler and Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif not lint
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)mountd.c	5.15 (Berkeley) 11/12/91";
19 #endif not lint
20 
21 #include <pwd.h>
22 #include <grp.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28 #include <sys/stat.h>
29 #include <sys/file.h>
30 #include <sys/ucred.h>
31 #include <sys/mount.h>
32 #include <sys/socket.h>
33 #include <sys/errno.h>
34 #include <sys/signal.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <syslog.h>
38 #include <netdb.h>
39 #include <rpc/rpc.h>
40 #include <rpc/pmap_clnt.h>
41 #include <rpc/pmap_prot.h>
42 #ifdef ISO
43 #include <netiso/iso.h>
44 #endif
45 #include <nfs/rpcv2.h>
46 #include <nfs/nfsv2.h>
47 #include "pathnames.h"
48 
49 #define DEF_NAME "default"
50 
51 #define MNT_HOST   0
52 #define MNT_GROUP  1
53 #define	MNT_ISO    2
54 
55 struct namelist {
56 	char name[RPCMNT_NAMELEN+1];
57 	struct namelist *next;
58 };
59 struct namegrp {
60 	char gname[RPCMNT_NAMELEN+1];
61 	struct namegrp *next;
62 	struct namelist *names;
63 };
64 /*
65  * Structures for keeping the mount list and export list
66  */
67 struct mountlist {
68 	struct mountlist *ml_next;
69 	char	ml_host[RPCMNT_NAMELEN+1];
70 	char	ml_dirp[RPCMNT_PATHLEN+1];
71 };
72 
73 struct exportlist {
74 	struct exportlist *ex_next;
75 	struct exportlist *ex_prev;
76 	struct grouplist *ex_groups;
77 	int	ex_defset;
78 	char	ex_dirp[RPCMNT_PATHLEN+1];
79 };
80 
81 union grouptypes {
82 	struct hostent *gt_hostent;
83 	struct groupnames *gt_grpname;
84 #ifdef ISO
85 	struct sockaddr_iso *gt_isoaddr;
86 #endif
87 };
88 
89 struct grouplist {
90 	int type;
91 	int exflags;
92 	struct ucred anoncr;
93 	union grouptypes gr_ptr;
94 	struct grouplist *gr_next;
95 };
96 
97 struct al_mnt {
98 	struct al_mnt *al_next;
99 	fsid_t	al_mnted;
100 };
101 
102 struct groupnames {
103 	char gn_name[RPCMNT_NAMELEN+1];
104 	struct grouplist *gn_glist;
105 	struct groupnames *gn_next;
106 };
107 
108 /* Global defs */
109 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
110 void get_exportlist(), send_umntall(), nextfield(), do_opt();
111 void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
112 void get_group(), get_host(), do_group();
113 char *realpath();
114 #ifdef ISO
115 struct iso_addr *iso_addr();
116 #endif
117 struct exportlist exphead;
118 struct mountlist *mlhead;
119 struct groupnames *grpnames;
120 char exname[MAXPATHLEN];
121 struct ucred def_anon = {
122 	(u_short) 1,
123 	(uid_t) -2,
124 	1,
125 	(gid_t) -2,
126 };
127 int root_only = 1;
128 extern int errno;
129 struct al_mnt *al_head = (struct al_mnt *)0;
130 #ifdef DEBUG
131 int debug = 1;
132 #else
133 int debug = 0;
134 #endif
135 
136 /*
137  * Mountd server for NFS mount protocol as described in:
138  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
139  * The optional arguments are the exports file name
140  * default: _PATH_EXPORTS
141  * and "-n" to allow nonroot mount.
142  */
143 main(argc, argv)
144 	int argc;
145 	char **argv;
146 {
147 	SVCXPRT *transp;
148 	int c;
149 	extern int optind;
150 	extern char *optarg;
151 
152 	while ((c = getopt(argc, argv, "n")) != EOF)
153 		switch (c) {
154 		case 'n':
155 			root_only = 0;
156 			break;
157 		default:
158 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
159 			exit(1);
160 		};
161 	argc -= optind;
162 	argv += optind;
163 	grpnames = (struct groupnames *)0;
164 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
165 	mlhead = (struct mountlist *)0;
166 	if (argc == 1) {
167 		strncpy(exname, *argv, MAXPATHLEN-1);
168 		exname[MAXPATHLEN-1] = '\0';
169 	} else
170 		strcpy(exname, _PATH_EXPORTS);
171 	openlog("mountd:", LOG_PID, LOG_DAEMON);
172 	if (debug)
173 		fprintf(stderr,"Getting export list.\n");
174 	get_exportlist();
175 	if (debug)
176 		fprintf(stderr,"Getting mount list.\n");
177 	get_mountlist();
178 	if (debug)
179 		fprintf(stderr,"Here we go.\n");
180 	if (debug == 0) {
181 		daemon(0, 0);
182 		signal(SIGINT, SIG_IGN);
183 		signal(SIGQUIT, SIG_IGN);
184 	}
185 	signal(SIGHUP, get_exportlist);
186 	signal(SIGTERM, send_umntall);
187 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
188 	  if (pidfile != NULL) {
189 		fprintf(pidfile, "%d\n", getpid());
190 		fclose(pidfile);
191 	  }
192 	}
193 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
194 		syslog(LOG_ERR, "Can't create socket");
195 		exit(1);
196 	}
197 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
198 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
199 	    IPPROTO_UDP)) {
200 		syslog(LOG_ERR, "Can't register mount");
201 		exit(1);
202 	}
203 	svc_run();
204 	syslog(LOG_ERR, "Mountd died");
205 	exit(1);
206 }
207 
208 /*
209  * The mount rpc service
210  */
211 mntsrv(rqstp, transp)
212 	register struct svc_req *rqstp;
213 	register SVCXPRT *transp;
214 {
215 	register struct grouplist *grp;
216 	register u_long **addrp;
217 	register struct exportlist *ep;
218 	nfsv2fh_t nfh;
219 	struct authunix_parms *ucr;
220 	struct stat stb;
221 	struct hostent *hp;
222 	u_long saddr;
223 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
224 	int bad = ENOENT;
225 	int found, matched;
226 	int omask;
227 	uid_t uid = -2;
228 
229 	/* Get authorization */
230 	switch (rqstp->rq_cred.oa_flavor) {
231 	case AUTH_UNIX:
232 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
233 		uid = ucr->aup_uid;
234 		break;
235 	case AUTH_NULL:
236 	default:
237 		break;
238 	}
239 
240 	saddr = transp->xp_raddr.sin_addr.s_addr;
241 	hp = (struct hostent *)0;
242 	switch (rqstp->rq_proc) {
243 	case NULLPROC:
244 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
245 			syslog(LOG_ERR, "Can't send reply");
246 		return;
247 	case RPCMNT_MOUNT:
248 		if ((uid != 0 && root_only) || uid == -2) {
249 			svcerr_weakauth(transp);
250 			return;
251 		}
252 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
253 			svcerr_decode(transp);
254 			return;
255 		}
256 
257 		/*
258 		 * Get the real pathname and make sure it is a directory
259 		 * that exists.
260 		 */
261 		if (realpath(rpcpath, dirpath) == 0 || stat(dirpath, &stb) < 0
262 			|| (stb.st_mode&S_IFMT) != S_IFDIR) {
263 			chdir("/");	/* Just in case realpath doesn't */
264 			if (debug)
265 				fprintf(stderr,"stat failed on %s\n",dirpath);
266 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
267 				syslog(LOG_ERR, "Can't send reply");
268 			return;
269 		}
270 
271 		/* Check in the exports list */
272 		omask = sigblock(sigmask(SIGHUP));
273 		ep = exphead.ex_next;
274 		found = FALSE;
275 		matched = FALSE;
276 		while (ep != NULL && !found && !matched) {
277 			struct grouplist *tgrp;
278 			if (debug)
279 			    fprintf(stderr,"dirp=[%s]\n",ep->ex_dirp);
280 			if (!strcmp(ep->ex_dirp, dirpath)) {
281 			    if (ep->ex_defset)
282 				grp = (struct grouplist *)0;
283 			    else
284 				grp = ep->ex_groups;
285 			    if (grp == NULL) {
286 				if (debug)
287 				    fprintf(stderr,"grp is null\n");
288 				found = TRUE;
289 			    }
290 			    while (grp && !found) {
291 				matched = TRUE;
292 				if (debug)
293 				    fprintf(stderr,"type = [%d]\n",grp->type);
294 				if (grp->type == MNT_GROUP) {
295 				    tgrp = grp->gr_ptr.gt_grpname->gn_glist;
296 				    if (tgrp)
297 					addrp = (u_long **)
298 					   tgrp->gr_ptr.gt_hostent->h_addr_list;
299 				    while(tgrp && !found) {
300 					if (debug)
301 					    fprintf(stderr, "cmp [%d] [%d]\n",
302 						**addrp,saddr);
303 					if (**addrp == saddr) {
304 					    found = TRUE;
305 					    hp = tgrp->gr_ptr.gt_hostent;
306 					    break;
307 					}
308 					if (*++addrp == NULL) {
309 					    tgrp = tgrp->gr_next;
310 					    if (tgrp == NULL)
311 						break;
312 					    addrp = (u_long **)tgrp->
313 						gr_ptr.gt_hostent->h_addr_list;
314 					}
315 				    }
316 				} else if (grp->type == MNT_HOST) {
317 				    addrp = (u_long **)
318 					grp->gr_ptr.gt_hostent->h_addr_list;
319 				    while (*addrp) {
320 					if (debug)
321 					    fprintf(stderr, "cmp [%d] [%d]\n",
322 						**addrp,saddr);
323 					if (**addrp == saddr) {
324 					    found = TRUE;
325 					    hp = grp->gr_ptr.gt_hostent;
326 					    break;
327 					}
328 					addrp++;
329 				    }
330 				}
331 				grp = grp->gr_next;
332 			    }
333 			}
334 			ep = ep->ex_next;
335 		}
336 		if (!found) {
337 			bad = EACCES;
338 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
339 				syslog(LOG_ERR, "Can't send reply");
340 			sigsetmask(omask);
341 			return;
342 		} else {
343 			/* Get the file handle */
344 			bzero((caddr_t)&nfh, sizeof(nfh));
345 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
346 				bad = errno;
347 				fprintf(stderr,
348 				    "Couldn't get file handle for %s.\n",
349 				    dirpath);
350 				if (!svc_sendreply(transp, xdr_long,
351 				    (caddr_t)&bad))
352 					syslog(LOG_ERR, "Can't send reply");
353 				sigsetmask(omask);
354 				return;
355 			}
356 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
357 				syslog(LOG_ERR, "Can't send reply");
358 			if (hp == NULL)
359 				hp = gethostbyaddr((caddr_t)&saddr,
360 				    sizeof(saddr), AF_INET);
361 			if (hp)
362 				add_mlist(hp->h_name, dirpath);
363 			else
364 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
365 					dirpath);
366 			if (debug)
367 				fprintf(stderr,"Mount successfull.\n");
368 		}
369 		sigsetmask(omask);
370 		return;
371 	case RPCMNT_DUMP:
372 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
373 			syslog(LOG_ERR, "Can't send reply");
374 		return;
375 	case RPCMNT_UMOUNT:
376 		if ((uid != 0 && root_only) || uid == -2) {
377 			svcerr_weakauth(transp);
378 			return;
379 		}
380 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
381 			svcerr_decode(transp);
382 			return;
383 		}
384 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
385 			syslog(LOG_ERR, "Can't send reply");
386 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
387 		if (hp)
388 			del_mlist(hp->h_name, dirpath);
389 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
390 		return;
391 	case RPCMNT_UMNTALL:
392 		if ((uid != 0 && root_only) || uid == -2) {
393 			svcerr_weakauth(transp);
394 			return;
395 		}
396 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
397 			syslog(LOG_ERR, "Can't send reply");
398 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
399 		if (hp)
400 			del_mlist(hp->h_name, (char *)0);
401 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
402 		return;
403 	case RPCMNT_EXPORT:
404 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
405 			syslog(LOG_ERR, "Can't send reply");
406 		return;
407 	default:
408 		svcerr_noproc(transp);
409 		return;
410 	}
411 }
412 
413 /*
414  * Xdr conversion for a dirpath string
415  */
416 xdr_dir(xdrsp, dirp)
417 	XDR *xdrsp;
418 	char *dirp;
419 {
420 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
421 }
422 
423 /*
424  * Xdr routine to generate fhstatus
425  */
426 xdr_fhs(xdrsp, nfh)
427 	XDR *xdrsp;
428 	nfsv2fh_t *nfh;
429 {
430 	int ok = 0;
431 
432 	if (!xdr_long(xdrsp, &ok))
433 		return (0);
434 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
435 }
436 
437 xdr_mlist(xdrsp, cp)
438 	XDR *xdrsp;
439 	caddr_t cp;
440 {
441 	register struct mountlist *mlp;
442 	int true = 1;
443 	int false = 0;
444 	char *strp;
445 
446 	mlp = mlhead;
447 	while (mlp) {
448 		if (!xdr_bool(xdrsp, &true))
449 			return (0);
450 		strp = &mlp->ml_host[0];
451 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
452 			return (0);
453 		strp = &mlp->ml_dirp[0];
454 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
455 			return (0);
456 		mlp = mlp->ml_next;
457 	}
458 	if (!xdr_bool(xdrsp, &false))
459 		return (0);
460 	return (1);
461 }
462 
463 /*
464  * Xdr conversion for export list
465  */
466 xdr_explist(xdrsp, cp)
467 	XDR *xdrsp;
468 	caddr_t cp;
469 {
470 	register struct exportlist *ep;
471 	register struct grouplist *grp, *tgrp;
472 	int true = 1;
473 	int false = 0;
474 	char *strp;
475 	int omask;
476 
477 	omask = sigblock(sigmask(SIGHUP));
478 	ep = exphead.ex_next;
479 	while (ep != NULL) {
480 		if (!xdr_bool(xdrsp, &true))
481 			goto errout;
482 		strp = &ep->ex_dirp[0];
483 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
484 			goto errout;
485 		grp = ep->ex_groups;
486 		while (grp != NULL) {
487 			if (grp->type == MNT_GROUP) {
488 				tgrp = grp->gr_ptr.gt_grpname->gn_glist;
489 				while (tgrp) {
490 					if (!xdr_bool(xdrsp, &true))
491 						goto errout;
492 					strp = tgrp->gr_ptr.gt_hostent->h_name;
493 					if (!xdr_string(xdrsp, &strp,
494 					    RPCMNT_NAMELEN))
495 						goto errout;
496 					tgrp = tgrp->gr_next;
497 				}
498 			} else if (grp->type == MNT_HOST) {
499 				if (!xdr_bool(xdrsp, &true))
500 					goto errout;
501 				strp = grp->gr_ptr.gt_hostent->h_name;
502 				if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
503 					goto errout;
504 			}
505 			grp = grp->gr_next;
506 		}
507 		if (!xdr_bool(xdrsp, &false))
508 			goto errout;
509 		ep = ep->ex_next;
510 	}
511 	sigsetmask(omask);
512 	if (!xdr_bool(xdrsp, &false))
513 		return (0);
514 	return (1);
515 errout:
516 	sigsetmask(omask);
517 	return (0);
518 }
519 
520 #define LINESIZ	10240
521 char line[LINESIZ];
522 
523 /*
524  * Get the export list
525  */
526 void
527 get_exportlist()
528 {
529 	struct grouplist *grp, *tgrp;
530 	struct al_mnt *al_mp, *t_almp;
531 	register struct exportlist *ep, *ep2;
532 	struct groupnames *t_gn, *t_gn2;
533 	struct ucred anoncr;
534 	FILE *inf;
535 	char *cp, *endcp;
536 	char savedc;
537 	int len, dirplen, def_set;
538 	int exflags;
539 
540 	/*
541 	 * First, get rid of the old list
542 	 */
543 	ep = exphead.ex_next;
544 	while (ep != NULL) {
545 		ep2 = ep;
546 		ep = ep->ex_next;
547 		free_exp(ep2);
548 	}
549 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
550 
551 	t_gn = grpnames;
552 	while(t_gn != NULL) {
553 		t_gn2 = t_gn;
554 		t_gn = t_gn->gn_next;
555 		free_grp(t_gn2);
556 	}
557 	grpnames = (struct groupnames *)0;
558 
559 	al_mp = al_head;
560 	while (al_mp) {
561 		t_almp = al_mp;
562 		al_mp = al_mp->al_next;
563 		free((caddr_t)t_almp);
564 	}
565 	al_head = (struct al_mnt *)0;
566 
567 	/*
568 	 * Read in the exports file and build the list, calling
569 	 * mount() as we go along to push the export rules into the kernel.
570 	 */
571 	if ((inf = fopen(exname, "r")) == NULL) {
572 		syslog(LOG_ERR, "Can't open %s", exname);
573 		exit(2);
574 	}
575 	while (fgets(line, LINESIZ, inf)) {
576 		def_set = TRUE;
577 		if (debug)
578 			fprintf(stderr,"Got line %s\n",line);
579 		cp = line;
580 		nextfield(&cp, &endcp);
581 		if (*cp == '#')
582 			goto nextline;
583 		if (*cp != '/') {
584 			/* create group listing of names */
585 			get_group(cp, ep);
586 			goto nextline;
587 		}
588 		exflags = MNT_EXPORTED;
589 		anoncr = def_anon;
590 
591 		/*
592 		 * Create new exports list entry
593 		 */
594 		len = endcp-cp;
595 		if (len <= RPCMNT_PATHLEN && len > 0) {
596 			/*
597 			 * See if this directory is already in the list.
598 			 */
599 			ep = exphead.ex_next;
600 			while (ep) {
601 				if (!strcmp(ep->ex_dirp, cp))
602 					break;
603 				ep = ep->ex_next;
604 			}
605 			if (ep == (struct exportlist *)0) {
606 				ep = (struct exportlist *)malloc(sizeof(*ep));
607 				if (ep == NULL)
608 					goto err;
609 				ep->ex_next = (struct exportlist *)0;
610 				ep->ex_prev = (struct exportlist *)0;
611 				ep->ex_groups = (struct grouplist *)0;
612 				ep->ex_defset = FALSE;
613 				bcopy(cp, ep->ex_dirp, len);
614 				ep->ex_dirp[len] = '\0';
615 			}
616 			dirplen = len;
617 			if (debug)
618 				fprintf(stderr, "Making new ep. [%s]\n",
619 				    ep->ex_dirp);
620 		} else {
621 			syslog(LOG_ERR, "Bad Exports File line: %s\n", line);
622 			goto nextline;
623 		}
624 		cp = endcp;
625 		nextfield(&cp, &endcp);
626 		len = endcp-cp;
627 		while (len > 0) {
628 			savedc = *endcp;
629 			*endcp = '\0';
630 			if (len > RPCMNT_NAMELEN)
631 				goto more;
632 			if (*cp == '-') {
633 				do_opt(cp + 1, ep, &exflags, &anoncr);
634 				exflags |= MNT_EXPORTED;
635 				def_set = TRUE;
636 				if (debug)
637 					fprintf(stderr, "got r=%d, ex=%d\n",
638 					    anoncr.cr_uid,exflags);
639 				goto more;
640 			} else {
641 				def_set = FALSE;
642 				if (*cp == '$') {
643 					do_group(cp + 1, endcp, &grp);
644 					grp->type = MNT_GROUP;
645 				} else {
646 					get_host(cp, endcp, ep, &grp);
647 				}
648 				if (grp != NULL) {
649 					grp->exflags = exflags;
650 					grp->anoncr = anoncr;
651 					grp->gr_next = ep->ex_groups;
652 					ep->ex_groups = grp;
653 				}
654 			}
655 		more:
656 			cp = endcp;
657 			*cp = savedc;
658 			nextfield(&cp, &endcp);
659 			len = endcp - cp;
660 		}
661 		if (def_set == TRUE) {
662 		    if (ep->ex_defset == TRUE)
663 			syslog(LOG_ERR, "Default specified again dir:%s\n",
664 				ep->ex_dirp);
665 		    else {
666 			struct hostent *hpe;
667 
668 			ep->ex_defset = TRUE;
669 			if (debug)
670 				fprintf(stderr,"Adding a default entry\n");
671 			/* add a default group and make the grp list NULL */
672 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
673 			if (hpe == NULL) {
674 				syslog(LOG_ERR,"No more memory: mountd Failed");
675 				exit(2);
676 			}
677 			tgrp = (struct grouplist *)
678 			    malloc(sizeof(struct grouplist));
679 			if (tgrp == NULL) {
680 				syslog(LOG_ERR,"No more memory: mountd Failed");
681 				exit(2);
682 			}
683 			tgrp->anoncr = anoncr;
684 			tgrp->exflags = exflags;
685 			hpe->h_name = (char *)malloc(sizeof(DEF_NAME)+1);
686 			if (hpe->h_name == NULL) {
687 				syslog(LOG_ERR,"No more memory: mountd Failed");
688 				exit(2);
689 			}
690 			strcpy(hpe->h_name,DEF_NAME);
691 			hpe->h_addrtype = AF_INET;
692 			hpe->h_length = sizeof (u_long);
693 			hpe->h_addr_list = INADDR_ANY;
694 			tgrp->gr_ptr.gt_hostent = hpe;
695 			tgrp->gr_next = ep->ex_groups;
696 			ep->ex_groups = tgrp;
697 		    }
698 		}
699 		grp = ep->ex_groups;
700 		while (grp != NULL) {
701 			exflags = grp->exflags;
702 			anoncr = grp->anoncr;
703 			if (grp->type == MNT_GROUP) {
704 				tgrp = grp->gr_ptr.gt_grpname->gn_glist;
705 				while(tgrp != NULL) {
706 					if (do_mount(ep, tgrp, exflags, &anoncr,
707 					    dirplen) == FALSE)
708 						goto nextline;
709 					tgrp = tgrp->gr_next;
710 				}
711 			} else {
712 				if (do_mount(ep, grp, exflags, &anoncr, dirplen)
713 				    == FALSE)
714 					goto nextline;
715 			}
716 			grp = grp->gr_next;
717 		}
718 		if (cp)
719 			*cp = savedc;
720 		if (ep->ex_prev == (struct exportlist *)0) {
721 			ep->ex_next = exphead.ex_next;
722 			ep->ex_prev = &exphead;
723 			if (ep->ex_next != NULL)
724 				ep->ex_next->ex_prev = ep;
725 			exphead.ex_next = ep;
726 		}
727 nextline:
728 		;
729 	}
730 	fclose(inf);
731 	return;
732 err:
733 	syslog(LOG_ERR, "No more memory: mountd Failed");
734 	exit(2);
735 }
736 
737 do_mount(ep, grp, exflags, anoncrp, dirplen)
738 	struct exportlist *ep;
739 	struct grouplist *grp;
740 	int exflags, dirplen;
741 	struct ucred *anoncrp;
742 {
743 	int done, found;
744 	register u_long **addrp;
745 	struct sockaddr_in sin;
746 	struct statfs stfsbuf;
747 	struct ufs_args args, targs;
748 	struct al_mnt *al_mp;
749 	char *cp, savedc;
750 
751 	args.fspec = 0;
752 	args.exflags = exflags;
753 	args.anon = *anoncrp;
754 	sin.sin_family = AF_INET;
755 	sin.sin_port = 0;
756 	sin.sin_len = sizeof(sin);
757 	if (grp->type == MNT_HOST)
758 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
759 	done = FALSE;
760 	while(!done) {
761 		if (grp->type == MNT_HOST) {
762 			if (!strcmp(grp->gr_ptr.gt_hostent->h_name, DEF_NAME))
763 				sin.sin_addr.s_addr = INADDR_ANY;
764 			else
765 				sin.sin_addr.s_addr = **addrp;
766 			args.saddr = (struct sockaddr *)&sin;
767 			args.slen = sizeof(sin);
768 #ifdef ISO
769 		} else if (grp->type == MNT_ISO) {
770 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
771 			args.slen = sizeof (struct sockaddr_iso);
772 #endif	/* ISO */
773 		} else {
774 			syslog(LOG_ERR, "Bad grouptype");
775 			free_exp(ep);
776 			return (FALSE);
777 		}
778 		if (statfs(ep->ex_dirp, &stfsbuf) < 0) {
779 			if (debug) {
780 				fprintf(stderr,"statfs failed.\n");
781 			}
782 			syslog(LOG_ERR, "Invalid path: %s", ep->ex_dirp);
783 			free_exp(ep);
784 			return(FALSE);
785 		}
786 		found = FALSE;
787 		for (al_mp = al_head; al_mp && !found; al_mp = al_mp->al_next)
788 			if (al_mp->al_mnted.val[0] == stfsbuf.f_fsid.val[0] &&
789 			    al_mp->al_mnted.val[1] == stfsbuf.f_fsid.val[1])
790 				found = TRUE;
791 		if (!found) {
792 			/* first time for fs, so must send a MNT_DELEXPORT
793 			 * to clear the old export list held in the kernel
794 			 * for this fs.
795 			 */
796 			al_mp = (struct al_mnt *)malloc(sizeof (struct al_mnt));
797 			al_mp->al_mnted = stfsbuf.f_fsid;
798 			al_mp->al_next = al_head;
799 			al_head = al_mp;
800 			targs.fspec = 0;
801 			targs.exflags = MNT_DELEXPORT;
802 			cp = (char *)0;
803 			while (mount(MOUNT_UFS, ep->ex_dirp,
804 			       stfsbuf.f_flags | MNT_UPDATE, &targs) < 0) {
805 				if (debug) {
806 					fprintf(stderr,
807 					    "tried [%s][%d]\n",
808 					    ep->ex_dirp,errno);
809 				}
810 				if (cp == NULL)
811 					cp = ep->ex_dirp + dirplen - 1;
812 				else
813 					*cp = savedc;
814 				cp--;
815 				/* back up over the last component */
816 				while (*cp == '/' && cp > ep->ex_dirp)
817 					cp--;
818 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
819 					cp--;
820 				if (cp == ep->ex_dirp) {
821 					if (debug) {
822 						fprintf(stderr,"mnt unsucc\n");
823 					}
824 					syslog(LOG_ERR,
825 					    "Can't export %s", ep->ex_dirp);
826 					free_exp(ep);
827 					return(FALSE);
828 				}
829 				savedc = *cp;
830 				*cp = '\0';
831 			}
832 			if (cp != NULL) {
833 				*cp = savedc;
834 			}
835 		}
836 		cp = (char *)0;
837 		while (mount(MOUNT_UFS, ep->ex_dirp,
838 		       stfsbuf.f_flags | MNT_UPDATE, &args) < 0) {
839 			if (errno == EPERM) {
840 				syslog(LOG_ERR,
841 				     "Can't change attributes for %s.\n",
842 				     ep->ex_dirp);
843 				if (cp != NULL)
844 					*cp = savedc;
845 				break;
846 			}
847 			if (cp == NULL)
848 				cp = ep->ex_dirp + dirplen - 1;
849 			else
850 				*cp = savedc;
851 			cp--;
852 			/* back up over the last component */
853 			while (*cp == '/' && cp > ep->ex_dirp)
854 				cp--;
855 			while (*(cp - 1) != '/' && cp > ep->ex_dirp)
856 				cp--;
857 			if (cp == ep->ex_dirp) {
858 				if (debug) {
859 					fprintf(stderr,"mnt unsucc\n");
860 				}
861 				syslog(LOG_ERR, "Can't export %s", ep->ex_dirp);
862 				free_exp(ep);
863 				return(FALSE);
864 			}
865 			savedc = *cp;
866 			*cp = '\0';
867 		}
868 		if (addrp == NULL)
869 			done = TRUE;
870 		else {
871 			++addrp;
872 			if (*addrp == NULL)
873 				done = TRUE;
874 		}
875 		if (cp != NULL)
876 			*cp = savedc;
877 	}
878 	return(TRUE);
879 }
880 
881 
882 /*
883  * Parse out the next white space separated field
884  */
885 void
886 nextfield(cp, endcp)
887 	char **cp;
888 	char **endcp;
889 {
890 	register char *p;
891 
892 	p = *cp;
893 	while (*p == ' ' || *p == '\t')
894 		p++;
895 	if (*p == '\n' || *p == '\0') {
896 		*cp = *endcp = p;
897 		return;
898 	}
899 	*cp = p++;
900 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
901 		p++;
902 	*endcp = p;
903 }
904 
905 /*
906  * Parse the option string
907  */
908 void
909 do_opt(cpopt, ep, exflagsp, cr)
910 	register char *cpopt;
911 	struct exportlist *ep;
912 	int *exflagsp;
913 	struct ucred *cr;
914 {
915 	register char *cpoptarg, *cpoptend;
916 	int allflag;
917 
918 	while (cpopt && *cpopt) {
919 		if (cpoptend = index(cpopt, ','))
920 			*cpoptend++ = '\0';
921 		if (cpoptarg = index(cpopt, '='))
922 			*cpoptarg++ = '\0';
923 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
924 			*exflagsp |= MNT_EXRDONLY;
925 		} else if ((!strcmp(cpopt, "root") || !strcmp(cpopt, "r") ||
926 		    !(allflag = strcmp(cpopt, "allanon"))) && cpoptarg) {
927 			parsecred(cpoptarg, cr);
928 			if (allflag == 0)
929 				*exflagsp |= MNT_EXPORTANON;
930 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
931 			*exflagsp |= MNT_EXKERB;
932 		} else
933 			syslog(LOG_ERR, "opt %s ignored for %s", cpopt,
934 			       ep->ex_dirp);
935 		cpopt = cpoptend;
936 	}
937 }
938 
939 /*
940  * Parse a description of a credential.
941  */
942 parsecred(namelist, cr)
943 	char *namelist;
944 	register struct ucred *cr;
945 {
946 	register char *name;
947 	register int cnt;
948 	char *names;
949 	struct passwd *pw;
950 	struct group *gr;
951 	int ngroups, groups[NGROUPS + 1];
952 
953 	/*
954 	 * Set up the unpriviledged user.
955 	 */
956 	cr->cr_ref = 1;
957 	cr->cr_uid = -2;
958 	cr->cr_groups[0] = -2;
959 	cr->cr_ngroups = 1;
960 	/*
961 	 * Get the user's password table entry.
962 	 */
963 	names = strsep(&namelist, " \t\n");
964 	name = strsep(&names, ":");
965 	if (isdigit(*name) || *name == '-')
966 		pw = getpwuid(atoi(name));
967 	else
968 		pw = getpwnam(name);
969 	/*
970 	 * Credentials specified as those of a user.
971 	 */
972 	if (names == NULL) {
973 		if (pw == NULL) {
974 			syslog(LOG_ERR, "Unknown user: %s\n", name);
975 			return;
976 		}
977 		cr->cr_uid = pw->pw_uid;
978 		ngroups = NGROUPS + 1;
979 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
980 			syslog(LOG_ERR, "Too many groups\n");
981 		/*
982 		 * Convert from int's to gid_t's and compress out duplicate
983 		 */
984 		cr->cr_ngroups = ngroups - 1;
985 		cr->cr_groups[0] = groups[0];
986 		for (cnt = 2; cnt < ngroups; cnt++)
987 			cr->cr_groups[cnt - 1] = groups[cnt];
988 		return;
989 	}
990 	/*
991 	 * Explicit credential specified as a colon separated list:
992 	 *	uid:gid:gid:...
993 	 */
994 	if (pw != NULL)
995 		cr->cr_uid = pw->pw_uid;
996 	else if (isdigit(*name) || *name == '-')
997 		cr->cr_uid = atoi(name);
998 	else {
999 		syslog(LOG_ERR, "Unknown user: %s\n", name);
1000 		return;
1001 	}
1002 	cr->cr_ngroups = 0;
1003 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1004 		name = strsep(&names, ":");
1005 		if (isdigit(*name) || *name == '-') {
1006 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1007 		} else {
1008 			if ((gr = getgrnam(name)) == NULL) {
1009 				syslog(LOG_ERR, "Unknown group: %s\n", name);
1010 				continue;
1011 			}
1012 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1013 		}
1014 	}
1015 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1016 		syslog(LOG_ERR, "Too many groups\n");
1017 }
1018 
1019 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1020 /*
1021  * Routines that maintain the remote mounttab
1022  */
1023 void
1024 get_mountlist()
1025 {
1026 	register struct mountlist *mlp, **mlpp;
1027 	register char *eos, *dirp;
1028 	int len;
1029 	char str[STRSIZ];
1030 	FILE *mlfile;
1031 
1032 	if (((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) &&
1033 	    ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL)) {
1034 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1035 		return;
1036 	}
1037 	mlpp = &mlhead;
1038 	while (fgets(str, STRSIZ, mlfile) != NULL) {
1039 		if ((dirp = index(str, '\t')) == NULL &&
1040 		    (dirp = index(str, ' ')) == NULL)
1041 			continue;
1042 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1043 		len = dirp-str;
1044 		if (len > RPCMNT_NAMELEN)
1045 			len = RPCMNT_NAMELEN;
1046 		bcopy(str, mlp->ml_host, len);
1047 		mlp->ml_host[len] = '\0';
1048 		while (*dirp == '\t' || *dirp == ' ')
1049 			dirp++;
1050 		if ((eos = index(dirp, '\t')) == NULL &&
1051 		    (eos = index(dirp, ' ')) == NULL &&
1052 		    (eos = index(dirp, '\n')) == NULL)
1053 			len = strlen(dirp);
1054 		else
1055 			len = eos-dirp;
1056 		if (len > RPCMNT_PATHLEN)
1057 			len = RPCMNT_PATHLEN;
1058 		bcopy(dirp, mlp->ml_dirp, len);
1059 		mlp->ml_dirp[len] = '\0';
1060 		mlp->ml_next = (struct mountlist *)0;
1061 		*mlpp = mlp;
1062 		mlpp = &mlp->ml_next;
1063 	}
1064 	fclose(mlfile);
1065 }
1066 
1067 void
1068 del_mlist(hostp, dirp)
1069 	register char *hostp, *dirp;
1070 {
1071 	register struct mountlist *mlp, **mlpp;
1072 	FILE *mlfile;
1073 	int fnd = 0;
1074 
1075 	mlpp = &mlhead;
1076 	mlp = mlhead;
1077 	while (mlp) {
1078 		if (!strcmp(mlp->ml_host, hostp) &&
1079 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1080 			fnd = 1;
1081 			*mlpp = mlp->ml_next;
1082 			free((caddr_t)mlp);
1083 		}
1084 		mlpp = &mlp->ml_next;
1085 		mlp = mlp->ml_next;
1086 	}
1087 	if (fnd) {
1088 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1089 			syslog(LOG_WARNING,"Can't update %s", _PATH_RMOUNTLIST);
1090 			return;
1091 		}
1092 		mlp = mlhead;
1093 		while (mlp) {
1094 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1095 			mlp = mlp->ml_next;
1096 		}
1097 		fclose(mlfile);
1098 	}
1099 }
1100 
1101 void
1102 add_mlist(hostp, dirp)
1103 	register char *hostp, *dirp;
1104 {
1105 	register struct mountlist *mlp, **mlpp;
1106 	FILE *mlfile;
1107 
1108 	mlpp = &mlhead;
1109 	mlp = mlhead;
1110 	while (mlp) {
1111 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1112 			return;
1113 		mlpp = &mlp->ml_next;
1114 		mlp = mlp->ml_next;
1115 	}
1116 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1117 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1118 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1119 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1120 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1121 	mlp->ml_next = (struct mountlist *)0;
1122 	*mlpp = mlp;
1123 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1124 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
1125 		return;
1126 	}
1127 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1128 	fclose(mlfile);
1129 }
1130 
1131 /*
1132  * This function is called via. SIGTERM when the system is going down.
1133  * It sends a broadcast RPCMNT_UMNTALL.
1134  */
1135 void
1136 send_umntall()
1137 {
1138 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1139 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1140 	exit(0);
1141 }
1142 
1143 umntall_each(resultsp, raddr)
1144 	caddr_t resultsp;
1145 	struct sockaddr_in *raddr;
1146 {
1147 	return (1);
1148 }
1149 
1150 /*
1151  * Free up an exports list component
1152  */
1153 void
1154 free_exp(ep)
1155 	register struct exportlist *ep;
1156 {
1157 	register struct grouplist *grp;
1158 	struct grouplist *grp2;
1159 
1160 	grp = ep->ex_groups;
1161 	while (grp != NULL) {
1162 		grp2 = grp;
1163 		grp = grp->gr_next;
1164 		free_grp(grp2);
1165 	}
1166 	free((caddr_t)ep);
1167 }
1168 
1169 /*
1170  * Free up a group list.
1171  */
1172 void
1173 free_grp(grp)
1174 	register struct grouplist *grp;
1175 {
1176 	register char **addrp;
1177 
1178 	if (grp->type == MNT_HOST) {
1179 		addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1180 		while (addrp && *addrp)
1181 			free(*addrp++);
1182 		free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1183 		free(grp->gr_ptr.gt_hostent->h_name);
1184 		free((caddr_t)grp->gr_ptr.gt_hostent);
1185 	}
1186 #ifdef ISO
1187 	else if (grp->type == MNT_ISO)
1188 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
1189 #endif
1190 	free((caddr_t)grp);
1191 }
1192 
1193 void
1194 get_group(line, ep)
1195 	char *line;
1196 	struct export_list *ep;
1197 {
1198 	int done;
1199 	struct grouplist *grp;
1200 	struct groupnames *t_gn;
1201 	char *cp, *endcp, savedc;
1202 
1203 	cp = line;
1204 	nextfield(&cp, &endcp);
1205 	savedc = *endcp;
1206 	*endcp = NULL;
1207 	if (*(endcp-1) == '=') {
1208 		*(endcp-1) = NULL;
1209 	}
1210 	/* check to see if this group exists already */
1211 	t_gn = grpnames;
1212 	while(t_gn != NULL) {
1213 		if (strcmp(t_gn->gn_name,cp) == 0) {
1214 			syslog(LOG_ERR,"Group redifined, second ignored.");
1215 			return;
1216 		}
1217 		t_gn = t_gn->gn_next;
1218 	}
1219 
1220 	/* make a new group list entry */
1221 	t_gn = (struct groupnames *)malloc(sizeof(struct groupnames));
1222 	if (t_gn == NULL) {
1223 		syslog(LOG_ERR,"Group: Couldn't Malloc.");
1224 		exit(2);
1225 	}
1226 	strcpy(t_gn->gn_name,cp);
1227 	t_gn->gn_next = grpnames;
1228 	grpnames = t_gn;
1229 	t_gn->gn_glist = NULL;
1230 	*endcp = savedc;
1231 	cp = endcp;
1232 	done = FALSE;
1233 	while(!done) {
1234 		nextfield(&cp, &endcp);
1235 		if (cp == endcp)
1236 			done = TRUE;
1237 		else {
1238 			savedc = *endcp;
1239 			*endcp = NULL;
1240 			if (strcmp(cp, "=")) {
1241 				/* add to group list */
1242 				get_host(cp, endcp, ep, &grp);
1243 				if (grp != NULL) {
1244 					grp->gr_next = t_gn->gn_glist;
1245 					t_gn->gn_glist = grp;
1246 				}
1247 			}
1248 			*endcp = savedc;
1249 			cp = endcp;
1250 		}
1251 	}
1252 }
1253 
1254 void
1255 get_host(cp, endcp, ep, gp)
1256 	char *cp, *endcp;
1257 	struct exportlist *ep;
1258 	struct grouplist **gp;
1259 {
1260 	register struct hostent *hp, *nhp;
1261 	register struct grouplist *grp;
1262 	register char **addrp, **naddrp;
1263 	struct hostent t_host;
1264 	int i;
1265 	u_long saddr;
1266 	char *aptr[2];
1267 #ifdef ISO
1268 	struct iso_addr *isop;
1269 	struct sockaddr_iso *isoaddr;
1270 #endif
1271 
1272 	if (isdigit(*cp)) {
1273 		saddr = inet_addr(cp);
1274 		if (saddr == -1) {
1275 			syslog(LOG_ERR,
1276 			    "Bad Exports File, %s: %s", cp,
1277 			    "inet_addr failed, ignored");
1278 			*gp = NULL;
1279 			return;
1280 		}
1281 		hp = &t_host;
1282 		hp->h_name = cp;
1283 		hp->h_addrtype = AF_INET;
1284 		hp->h_length = sizeof (u_long);
1285 		hp->h_addr_list = aptr;
1286 		aptr[0] = (char *)&saddr;
1287 		aptr[1] = (char *)0;
1288 #ifdef ISO
1289 	} else if (!strncmp(cp, "iso=", 4)) {
1290 		if ((isop = iso_addr(cp + 4)) == NULL) {
1291 			syslog(LOG_ERR,
1292 			    "Bad Exports File, %s: %s", cp,
1293 			    "iso_addr failed, ignored");
1294 			*gp = NULL;
1295 			return;
1296 		}
1297 		isoaddr = (struct sockaddr_iso *)
1298 		    malloc(sizeof (struct sockaddr_iso));
1299 		if (isoaddr == NULL)
1300 			goto err1;
1301 		bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
1302 		bcopy((caddr_t)isop, (caddr_t)isoaddr->siso_addr,
1303 			sizeof (struct iso_addr));
1304 		isoaddr->siso_len = sizeof (struct sockaddr_iso);
1305 		isoaddr->siso_family = AF_ISO;
1306 		grp = (struct grouplist *)
1307 			malloc(sizeof(struct grouplist));
1308 		if (grp == NULL)
1309 			goto err1;
1310 		grp->type = MNT_ISO;
1311 		grp->gr_ptr.gt_isoaddr = isoaddr;
1312 		*gp = grp;
1313 		return;
1314 #endif	/* ISO */
1315 	} else if ((hp = gethostbyname(cp)) == NULL) {
1316 		syslog(LOG_ERR, "Bad Exports File, %s: %s",
1317 		    cp, "Gethostbyname failed, ignored");
1318 		*gp = NULL;
1319 		return;
1320 	}
1321 	grp = (struct grouplist *)
1322 		malloc(sizeof(struct grouplist));
1323 	if (grp == NULL)
1324 		goto err1;
1325 	grp->type = MNT_HOST;
1326 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1327 		malloc(sizeof(struct hostent));
1328 	if (nhp == NULL)
1329 		goto err1;
1330 	bcopy((caddr_t)hp, (caddr_t)nhp,
1331 		sizeof(struct hostent));
1332 	i = strlen(hp->h_name)+1;
1333 	nhp->h_name = (char *)malloc(i);
1334 	if (nhp->h_name == NULL)
1335 		goto err1;
1336 	bcopy(hp->h_name, nhp->h_name, i);
1337 	addrp = hp->h_addr_list;
1338 	i = 1;
1339 	while (*addrp++)
1340 		i++;
1341 	naddrp = nhp->h_addr_list = (char **)
1342 		malloc(i*sizeof(char *));
1343 	if (naddrp == NULL)
1344 		goto err1;
1345 	addrp = hp->h_addr_list;
1346 	while (*addrp) {
1347 		*naddrp = (char *)
1348 		    malloc(hp->h_length);
1349 		if (*naddrp == NULL)
1350 		    goto err1;
1351 		bcopy(*addrp, *naddrp,
1352 			hp->h_length);
1353 		addrp++;
1354 		naddrp++;
1355 	}
1356 	*naddrp = (char *)0;
1357 	*gp = grp;
1358 	return;
1359 err1:
1360 	syslog(LOG_ERR, "No more memory: mountd Failed");
1361 	exit(2);
1362 }
1363 
1364 void
1365 do_group(cp, endcp, gp)
1366 	char *cp, *endcp;
1367 	struct grouplist **gp;
1368 {
1369 	int found;
1370 	struct groupnames *t_gn;
1371 
1372 	t_gn = grpnames;
1373 	found = FALSE;
1374 	while((t_gn != NULL) && !found) {
1375 		if(strcmp(t_gn->gn_name,cp) == 0) {
1376 			found = TRUE;
1377 			*gp = (struct grouplist *)
1378 			    malloc(sizeof(struct grouplist));
1379 			if (*gp == NULL) {
1380 				syslog(LOG_ERR,"No more memory: mountd Failed");
1381 				exit(2);
1382 			}
1383 			(*gp)->gr_ptr.gt_grpname = (struct groupnames *)
1384 			    malloc(sizeof(struct groupnames));
1385 			if ((*gp)->gr_ptr.gt_grpname == NULL) {
1386 				syslog(LOG_ERR,"No more memory: mountd Failed");
1387 				exit(2);
1388 			}
1389 			(*gp)->gr_ptr.gt_grpname->gn_glist = t_gn->gn_glist;
1390 			return;
1391 		}
1392 		t_gn = t_gn->gn_next;
1393 	}
1394 	*gp = NULL;
1395 }
1396 
1397 /*
1398  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
1399  *
1400  * find the real name of path, by removing all ".", ".."
1401  * and symlink components.
1402  *
1403  * Jan-Simon Pendry, September 1991.
1404  */
1405 char *
1406 realpath(path, resolved)
1407 	char *path;
1408 	char resolved[MAXPATHLEN];
1409 {
1410 	int d = open(".", O_RDONLY);
1411 	int rootd = 0;
1412 	char *p, *q;
1413 	struct stat stb;
1414 	char wbuf[MAXPATHLEN];
1415 
1416 	strcpy(resolved, path);
1417 
1418 	if (d < 0)
1419 		return 0;
1420 
1421 loop:;
1422 	q = strrchr(resolved, '/');
1423 	if (q) {
1424 		p = q + 1;
1425 		if (q == resolved)
1426 			q = "/";
1427 		else {
1428 			do
1429 				--q;
1430 			while (q > resolved && *q == '/');
1431 			q[1] = '\0';
1432 			q = resolved;
1433 		}
1434 		if (chdir(q) < 0)
1435 			goto out;
1436 	} else
1437 		p = resolved;
1438 
1439 	if (lstat(p, &stb) == 0) {
1440 		if (S_ISLNK(stb.st_mode)) {
1441 			int n = readlink(p, resolved, MAXPATHLEN);
1442 			if (n < 0)
1443 				goto out;
1444 			resolved[n] = '\0';
1445 			goto loop;
1446 		}
1447 		if (S_ISDIR(stb.st_mode)) {
1448 			if (chdir(p) < 0)
1449 				goto out;
1450 			p = "";
1451 		}
1452 	}
1453 
1454 	strcpy(wbuf, p);
1455 	if (getcwd(resolved, MAXPATHLEN) == 0)
1456 		goto out;
1457 	if (resolved[0] == '/' && resolved[1] == '\0')
1458 		rootd = 1;
1459 
1460 	if (*wbuf) {
1461 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
1462 			errno = ENAMETOOLONG;
1463 			goto out;
1464 		}
1465 		if (rootd == 0)
1466 			strcat(resolved, "/");
1467 		strcat(resolved, wbuf);
1468 	}
1469 
1470 	if (fchdir(d) < 0)
1471 		goto out;
1472 	(void) close(d);
1473 
1474 	return resolved;
1475 
1476 out:;
1477 	(void) close(d);
1478 	return 0;
1479 }
1480