xref: /csrg-svn/sbin/mountd/mountd.c (revision 51713)
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.18 (Berkeley) 11/14/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 MNT_HOST   0
50 #define MNT_GROUP  1
51 #define	MNT_ISO    2
52 
53 struct namelist {
54 	char name[RPCMNT_NAMELEN+1];
55 	struct namelist *next;
56 };
57 struct namegrp {
58 	char gname[RPCMNT_NAMELEN+1];
59 	struct namegrp *next;
60 	struct namelist *names;
61 };
62 /*
63  * Structures for keeping the mount list and export list
64  */
65 struct mountlist {
66 	struct mountlist *ml_next;
67 	char	ml_host[RPCMNT_NAMELEN+1];
68 	char	ml_dirp[RPCMNT_PATHLEN+1];
69 };
70 
71 struct exportlist {
72 	struct exportlist *ex_next;
73 	struct exportlist *ex_prev;
74 	struct grouplist *ex_groups;
75 	int	ex_defset;
76 	char	ex_dirp[RPCMNT_PATHLEN+1];
77 };
78 
79 union grouptypes {
80 	struct hostent *gt_hostent;
81 	struct groupnames *gt_grpname;
82 #ifdef ISO
83 	struct sockaddr_iso *gt_isoaddr;
84 #endif
85 };
86 
87 struct grouplist {
88 	int type;
89 	int exflags;
90 	struct ucred anoncr;
91 	union grouptypes gr_ptr;
92 	struct grouplist *gr_next;
93 };
94 
95 struct al_mnt {
96 	struct al_mnt *al_next;
97 	fsid_t	al_mnted;
98 };
99 
100 struct groupnames {
101 	char gn_name[RPCMNT_NAMELEN+1];
102 	struct grouplist *gn_glist;
103 	struct groupnames *gn_next;
104 };
105 
106 /* Global defs */
107 int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
108 void get_exportlist(), send_umntall(), nextfield(), do_opt();
109 void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
110 void get_group(), get_host(), do_group();
111 char *realpath();
112 #ifdef ISO
113 struct iso_addr *iso_addr();
114 #endif
115 struct exportlist exphead;
116 struct mountlist *mlhead;
117 struct groupnames *grpnames;
118 char exname[MAXPATHLEN];
119 struct ucred def_anon = {
120 	(u_short) 1,
121 	(uid_t) -2,
122 	1,
123 	(gid_t) -2,
124 };
125 int root_only = 1;
126 extern int errno;
127 struct al_mnt *al_head = (struct al_mnt *)0;
128 #ifdef DEBUG
129 int debug = 1;
130 void	SYSLOG __P((int, const char *, ...));
131 #define syslog SYSLOG
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 			tgrp->type = MNT_HOST;
686 			hpe->h_name = (char *)0;
687 			hpe->h_addrtype = AF_INET;
688 			hpe->h_length = sizeof (u_long);
689 			hpe->h_addr_list = (char **)0;
690 			tgrp->gr_ptr.gt_hostent = hpe;
691 			tgrp->gr_next = ep->ex_groups;
692 			ep->ex_groups = tgrp;
693 		    }
694 		}
695 		grp = ep->ex_groups;
696 		while (grp != NULL) {
697 			exflags = grp->exflags;
698 			anoncr = grp->anoncr;
699 			if (grp->type == MNT_GROUP) {
700 				tgrp = grp->gr_ptr.gt_grpname->gn_glist;
701 				while(tgrp != NULL) {
702 					if (do_mount(ep, tgrp, exflags, &anoncr,
703 					    dirplen) == FALSE)
704 						goto nextline;
705 					tgrp = tgrp->gr_next;
706 				}
707 			} else {
708 				if (do_mount(ep, grp, exflags, &anoncr, dirplen)
709 				    == FALSE)
710 					goto nextline;
711 			}
712 			grp = grp->gr_next;
713 		}
714 		if (cp)
715 			*cp = savedc;
716 		if (ep->ex_prev == (struct exportlist *)0) {
717 			ep->ex_next = exphead.ex_next;
718 			ep->ex_prev = &exphead;
719 			if (ep->ex_next != NULL)
720 				ep->ex_next->ex_prev = ep;
721 			exphead.ex_next = ep;
722 		}
723 nextline:
724 		;
725 	}
726 	fclose(inf);
727 	return;
728 err:
729 	syslog(LOG_ERR, "No more memory: mountd Failed");
730 	exit(2);
731 }
732 
733 do_mount(ep, grp, exflags, anoncrp, dirplen)
734 	struct exportlist *ep;
735 	struct grouplist *grp;
736 	int exflags, dirplen;
737 	struct ucred *anoncrp;
738 {
739 	int done, found;
740 	register u_long **addrp;
741 	struct sockaddr_in sin;
742 	struct statfs stfsbuf;
743 	struct ufs_args args, targs;
744 	struct al_mnt *al_mp;
745 	char *cp, savedc;
746 
747 	args.fspec = 0;
748 	args.exflags = exflags;
749 	args.anon = *anoncrp;
750 	sin.sin_family = AF_INET;
751 	sin.sin_port = 0;
752 	sin.sin_len = sizeof(sin);
753 	if (grp->type == MNT_HOST)
754 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
755 	done = FALSE;
756 	while(!done) {
757 		if (grp->type == MNT_HOST) {
758 			if (grp->gr_ptr.gt_hostent->h_name)
759 				sin.sin_addr.s_addr = **addrp;
760 			else
761 				sin.sin_addr.s_addr = INADDR_ANY;
762 			args.saddr = (struct sockaddr *)&sin;
763 			args.slen = sizeof(sin);
764 #ifdef ISO
765 		} else if (grp->type == MNT_ISO) {
766 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
767 			args.slen = sizeof (struct sockaddr_iso);
768 #endif	/* ISO */
769 		} else {
770 			syslog(LOG_ERR, "Bad grouptype");
771 			free_exp(ep);
772 			return (FALSE);
773 		}
774 		if (statfs(ep->ex_dirp, &stfsbuf) < 0) {
775 			if (debug) {
776 				fprintf(stderr,"statfs failed.\n");
777 			}
778 			syslog(LOG_ERR, "Invalid path: %s", ep->ex_dirp);
779 			free_exp(ep);
780 			return(FALSE);
781 		}
782 		found = FALSE;
783 		for (al_mp = al_head; al_mp && !found; al_mp = al_mp->al_next)
784 			if (al_mp->al_mnted.val[0] == stfsbuf.f_fsid.val[0] &&
785 			    al_mp->al_mnted.val[1] == stfsbuf.f_fsid.val[1])
786 				found = TRUE;
787 		if (!found) {
788 			/* first time for fs, so must send a MNT_DELEXPORT
789 			 * to clear the old export list held in the kernel
790 			 * for this fs.
791 			 */
792 			al_mp = (struct al_mnt *)malloc(sizeof (struct al_mnt));
793 			al_mp->al_mnted = stfsbuf.f_fsid;
794 			al_mp->al_next = al_head;
795 			al_head = al_mp;
796 			targs.fspec = 0;
797 			targs.exflags = MNT_DELEXPORT;
798 			cp = (char *)0;
799 			while (mount(MOUNT_UFS, ep->ex_dirp,
800 			       stfsbuf.f_flags | MNT_UPDATE, &targs) < 0) {
801 				if (debug) {
802 					fprintf(stderr,
803 					    "tried [%s][%d]\n",
804 					    ep->ex_dirp,errno);
805 				}
806 				if (cp == NULL)
807 					cp = ep->ex_dirp + dirplen - 1;
808 				else
809 					*cp = savedc;
810 				cp--;
811 				/* back up over the last component */
812 				while (*cp == '/' && cp > ep->ex_dirp)
813 					cp--;
814 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
815 					cp--;
816 				if (cp == ep->ex_dirp) {
817 					if (debug) {
818 						fprintf(stderr,"mnt unsucc\n");
819 					}
820 					syslog(LOG_ERR,
821 					    "Can't export %s", ep->ex_dirp);
822 					free_exp(ep);
823 					return(FALSE);
824 				}
825 				savedc = *cp;
826 				*cp = '\0';
827 			}
828 			if (cp != NULL) {
829 				*cp = savedc;
830 			}
831 		}
832 		cp = (char *)0;
833 		while (mount(MOUNT_UFS, ep->ex_dirp,
834 		       stfsbuf.f_flags | MNT_UPDATE, &args) < 0) {
835 			if (errno == EPERM) {
836 				syslog(LOG_ERR,
837 				     "Can't change attributes for %s.\n",
838 				     ep->ex_dirp);
839 				if (cp != NULL)
840 					*cp = savedc;
841 				break;
842 			}
843 			if (cp == NULL)
844 				cp = ep->ex_dirp + dirplen - 1;
845 			else
846 				*cp = savedc;
847 			cp--;
848 			/* back up over the last component */
849 			while (*cp == '/' && cp > ep->ex_dirp)
850 				cp--;
851 			while (*(cp - 1) != '/' && cp > ep->ex_dirp)
852 				cp--;
853 			if (cp == ep->ex_dirp) {
854 				if (debug) {
855 					fprintf(stderr,"mnt unsucc\n");
856 				}
857 				syslog(LOG_ERR, "Can't export %s", ep->ex_dirp);
858 				free_exp(ep);
859 				return(FALSE);
860 			}
861 			savedc = *cp;
862 			*cp = '\0';
863 		}
864 		if (addrp == NULL)
865 			done = TRUE;
866 		else {
867 			++addrp;
868 			if (*addrp == NULL)
869 				done = TRUE;
870 		}
871 		if (cp != NULL)
872 			*cp = savedc;
873 	}
874 	return(TRUE);
875 }
876 
877 
878 /*
879  * Parse out the next white space separated field
880  */
881 void
882 nextfield(cp, endcp)
883 	char **cp;
884 	char **endcp;
885 {
886 	register char *p;
887 
888 	p = *cp;
889 	while (*p == ' ' || *p == '\t')
890 		p++;
891 	if (*p == '\n' || *p == '\0') {
892 		*cp = *endcp = p;
893 		return;
894 	}
895 	*cp = p++;
896 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
897 		p++;
898 	*endcp = p;
899 }
900 
901 /*
902  * Parse the option string
903  */
904 void
905 do_opt(cpopt, ep, exflagsp, cr)
906 	register char *cpopt;
907 	struct exportlist *ep;
908 	int *exflagsp;
909 	struct ucred *cr;
910 {
911 	register char *cpoptarg, *cpoptend;
912 	int allflag = 1;
913 
914 	while (cpopt && *cpopt) {
915 		if (cpoptend = index(cpopt, ','))
916 			*cpoptend++ = '\0';
917 		if (cpoptarg = index(cpopt, '='))
918 			*cpoptarg++ = '\0';
919 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
920 			*exflagsp |= MNT_EXRDONLY;
921 		} else if ((!strcmp(cpopt, "root") || !strcmp(cpopt, "r") ||
922 		    !(allflag = strcmp(cpopt, "all"))) && cpoptarg) {
923 			parsecred(cpoptarg, cr);
924 			if (allflag == 0)
925 				*exflagsp |= MNT_EXPORTANON;
926 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
927 			*exflagsp |= MNT_EXKERB;
928 		} else
929 			syslog(LOG_ERR, "opt %s ignored for %s", cpopt,
930 			       ep->ex_dirp);
931 		cpopt = cpoptend;
932 	}
933 }
934 
935 /*
936  * Parse a description of a credential.
937  */
938 parsecred(namelist, cr)
939 	char *namelist;
940 	register struct ucred *cr;
941 {
942 	register char *name;
943 	register int cnt;
944 	char *names;
945 	struct passwd *pw;
946 	struct group *gr;
947 	int ngroups, groups[NGROUPS + 1];
948 
949 	/*
950 	 * Set up the unpriviledged user.
951 	 */
952 	cr->cr_ref = 1;
953 	cr->cr_uid = -2;
954 	cr->cr_groups[0] = -2;
955 	cr->cr_ngroups = 1;
956 	/*
957 	 * Get the user's password table entry.
958 	 */
959 	names = strsep(&namelist, " \t\n");
960 	name = strsep(&names, ":");
961 	if (isdigit(*name) || *name == '-')
962 		pw = getpwuid(atoi(name));
963 	else
964 		pw = getpwnam(name);
965 	/*
966 	 * Credentials specified as those of a user.
967 	 */
968 	if (names == NULL) {
969 		if (pw == NULL) {
970 			syslog(LOG_ERR, "Unknown user: %s\n", name);
971 			return;
972 		}
973 		cr->cr_uid = pw->pw_uid;
974 		ngroups = NGROUPS + 1;
975 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
976 			syslog(LOG_ERR, "Too many groups\n");
977 		/*
978 		 * Convert from int's to gid_t's and compress out duplicate
979 		 */
980 		cr->cr_ngroups = ngroups - 1;
981 		cr->cr_groups[0] = groups[0];
982 		for (cnt = 2; cnt < ngroups; cnt++)
983 			cr->cr_groups[cnt - 1] = groups[cnt];
984 		return;
985 	}
986 	/*
987 	 * Explicit credential specified as a colon separated list:
988 	 *	uid:gid:gid:...
989 	 */
990 	if (pw != NULL)
991 		cr->cr_uid = pw->pw_uid;
992 	else if (isdigit(*name) || *name == '-')
993 		cr->cr_uid = atoi(name);
994 	else {
995 		syslog(LOG_ERR, "Unknown user: %s\n", name);
996 		return;
997 	}
998 	cr->cr_ngroups = 0;
999 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1000 		name = strsep(&names, ":");
1001 		if (isdigit(*name) || *name == '-') {
1002 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1003 		} else {
1004 			if ((gr = getgrnam(name)) == NULL) {
1005 				syslog(LOG_ERR, "Unknown group: %s\n", name);
1006 				continue;
1007 			}
1008 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1009 		}
1010 	}
1011 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1012 		syslog(LOG_ERR, "Too many groups\n");
1013 }
1014 
1015 #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1016 /*
1017  * Routines that maintain the remote mounttab
1018  */
1019 void
1020 get_mountlist()
1021 {
1022 	register struct mountlist *mlp, **mlpp;
1023 	register char *eos, *dirp;
1024 	int len;
1025 	char str[STRSIZ];
1026 	FILE *mlfile;
1027 
1028 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1029 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1030 		return;
1031 	}
1032 	mlpp = &mlhead;
1033 	while (fgets(str, STRSIZ, mlfile) != NULL) {
1034 		if ((dirp = index(str, '\t')) == NULL &&
1035 		    (dirp = index(str, ' ')) == NULL)
1036 			continue;
1037 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1038 		len = dirp-str;
1039 		if (len > RPCMNT_NAMELEN)
1040 			len = RPCMNT_NAMELEN;
1041 		bcopy(str, mlp->ml_host, len);
1042 		mlp->ml_host[len] = '\0';
1043 		while (*dirp == '\t' || *dirp == ' ')
1044 			dirp++;
1045 		if ((eos = index(dirp, '\t')) == NULL &&
1046 		    (eos = index(dirp, ' ')) == NULL &&
1047 		    (eos = index(dirp, '\n')) == NULL)
1048 			len = strlen(dirp);
1049 		else
1050 			len = eos-dirp;
1051 		if (len > RPCMNT_PATHLEN)
1052 			len = RPCMNT_PATHLEN;
1053 		bcopy(dirp, mlp->ml_dirp, len);
1054 		mlp->ml_dirp[len] = '\0';
1055 		mlp->ml_next = (struct mountlist *)0;
1056 		*mlpp = mlp;
1057 		mlpp = &mlp->ml_next;
1058 	}
1059 	fclose(mlfile);
1060 }
1061 
1062 void
1063 del_mlist(hostp, dirp)
1064 	register char *hostp, *dirp;
1065 {
1066 	register struct mountlist *mlp, **mlpp;
1067 	struct mountlist *mlp2;
1068 	FILE *mlfile;
1069 	int fnd = 0;
1070 
1071 	mlpp = &mlhead;
1072 	mlp = mlhead;
1073 	while (mlp) {
1074 		if (!strcmp(mlp->ml_host, hostp) &&
1075 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1076 			fnd = 1;
1077 			mlp2 = mlp;
1078 			*mlpp = mlp = mlp->ml_next;
1079 			free((caddr_t)mlp2);
1080 		} else {
1081 			mlpp = &mlp->ml_next;
1082 			mlp = mlp->ml_next;
1083 		}
1084 	}
1085 	if (fnd) {
1086 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1087 			syslog(LOG_WARNING,"Can't update %s", _PATH_RMOUNTLIST);
1088 			return;
1089 		}
1090 		mlp = mlhead;
1091 		while (mlp) {
1092 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1093 			mlp = mlp->ml_next;
1094 		}
1095 		fclose(mlfile);
1096 	}
1097 }
1098 
1099 void
1100 add_mlist(hostp, dirp)
1101 	register char *hostp, *dirp;
1102 {
1103 	register struct mountlist *mlp, **mlpp;
1104 	FILE *mlfile;
1105 
1106 	mlpp = &mlhead;
1107 	mlp = mlhead;
1108 	while (mlp) {
1109 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1110 			return;
1111 		mlpp = &mlp->ml_next;
1112 		mlp = mlp->ml_next;
1113 	}
1114 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1115 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1116 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1117 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1118 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1119 	mlp->ml_next = (struct mountlist *)0;
1120 	*mlpp = mlp;
1121 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1122 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
1123 		return;
1124 	}
1125 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1126 	fclose(mlfile);
1127 }
1128 
1129 /*
1130  * This function is called via. SIGTERM when the system is going down.
1131  * It sends a broadcast RPCMNT_UMNTALL.
1132  */
1133 void
1134 send_umntall()
1135 {
1136 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1137 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1138 	exit(0);
1139 }
1140 
1141 umntall_each(resultsp, raddr)
1142 	caddr_t resultsp;
1143 	struct sockaddr_in *raddr;
1144 {
1145 	return (1);
1146 }
1147 
1148 /*
1149  * Free up an exports list component
1150  */
1151 void
1152 free_exp(ep)
1153 	register struct exportlist *ep;
1154 {
1155 	register struct grouplist *grp;
1156 	struct grouplist *grp2;
1157 
1158 	grp = ep->ex_groups;
1159 	while (grp != NULL) {
1160 		grp2 = grp;
1161 		grp = grp->gr_next;
1162 		free_grp(grp2);
1163 	}
1164 	free((caddr_t)ep);
1165 }
1166 
1167 /*
1168  * Free up a group list.
1169  */
1170 void
1171 free_grp(grp)
1172 	register struct grouplist *grp;
1173 {
1174 	register char **addrp;
1175 
1176 	if (grp->type == MNT_HOST) {
1177 		if (grp->gr_ptr.gt_hostent->h_name) {
1178 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1179 			while (addrp && *addrp)
1180 				free(*addrp++);
1181 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1182 			free(grp->gr_ptr.gt_hostent->h_name);
1183 		}
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 
1481 #ifdef DEBUG
1482 void
1483 SYSLOG(int pri, const char *fmt, ...)
1484 {
1485 	va_list ap;
1486 
1487 	va_start(ap, fmt);
1488 	vfprintf(stderr, fmt, ap);
1489 	va_end(ap);
1490 }
1491 #endif /* DEBUG */
1492