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