xref: /csrg-svn/sbin/mountd/mountd.c (revision 51712)
138460Smckusick /*
238460Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338460Smckusick  * All rights reserved.
438460Smckusick  *
538460Smckusick  * This code is derived from software contributed to Berkeley by
651667Smckusick  * Herb Hasler and Rick Macklem at The University of Guelph.
738460Smckusick  *
842703Sbostic  * %sccs.include.redist.c%
938460Smckusick  */
1038460Smckusick 
1138460Smckusick #ifndef lint
1238460Smckusick char copyright[] =
1338460Smckusick "@(#) Copyright (c) 1989 Regents of the University of California.\n\
1438460Smckusick  All rights reserved.\n";
1538460Smckusick #endif not lint
1638460Smckusick 
1738460Smckusick #ifndef lint
18*51712Smckusick static char sccsid[] = "@(#)mountd.c	5.17 (Berkeley) 11/14/91";
1938460Smckusick #endif not lint
2038460Smckusick 
2151667Smckusick #include <pwd.h>
2251667Smckusick #include <grp.h>
2351667Smckusick #include <unistd.h>
2451667Smckusick #include <stdlib.h>
2551667Smckusick #include <fcntl.h>
2638460Smckusick #include <sys/param.h>
2738460Smckusick #include <sys/ioctl.h>
2838460Smckusick #include <sys/stat.h>
2939681Smckusick #include <sys/file.h>
3051667Smckusick #include <sys/ucred.h>
3138460Smckusick #include <sys/mount.h>
3238460Smckusick #include <sys/socket.h>
3338460Smckusick #include <sys/errno.h>
3442038Sbostic #include <sys/signal.h>
3542038Sbostic #include <stdio.h>
3642038Sbostic #include <string.h>
3742038Sbostic #include <syslog.h>
3838460Smckusick #include <netdb.h>
3938460Smckusick #include <rpc/rpc.h>
4038460Smckusick #include <rpc/pmap_clnt.h>
4138460Smckusick #include <rpc/pmap_prot.h>
4251667Smckusick #ifdef ISO
4351667Smckusick #include <netiso/iso.h>
4451667Smckusick #endif
4538460Smckusick #include <nfs/rpcv2.h>
4638460Smckusick #include <nfs/nfsv2.h>
4739681Smckusick #include "pathnames.h"
4838460Smckusick 
4951667Smckusick #define MNT_HOST   0
5051667Smckusick #define MNT_GROUP  1
5151667Smckusick #define	MNT_ISO    2
5251667Smckusick 
5351667Smckusick struct namelist {
5451667Smckusick 	char name[RPCMNT_NAMELEN+1];
5551667Smckusick 	struct namelist *next;
5638460Smckusick };
5751667Smckusick struct namegrp {
5851667Smckusick 	char gname[RPCMNT_NAMELEN+1];
5951667Smckusick 	struct namegrp *next;
6051667Smckusick 	struct namelist *names;
6151667Smckusick };
6238460Smckusick /*
6338460Smckusick  * Structures for keeping the mount list and export list
6438460Smckusick  */
6538460Smckusick struct mountlist {
6644015Smckusick 	struct mountlist *ml_next;
6738460Smckusick 	char	ml_host[RPCMNT_NAMELEN+1];
6838460Smckusick 	char	ml_dirp[RPCMNT_PATHLEN+1];
6938460Smckusick };
7038460Smckusick 
7138460Smckusick struct exportlist {
7238460Smckusick 	struct exportlist *ex_next;
7338460Smckusick 	struct exportlist *ex_prev;
7438460Smckusick 	struct grouplist *ex_groups;
7551667Smckusick 	int	ex_defset;
7638460Smckusick 	char	ex_dirp[RPCMNT_PATHLEN+1];
7738460Smckusick };
7838460Smckusick 
7951667Smckusick union grouptypes {
8051667Smckusick 	struct hostent *gt_hostent;
8151667Smckusick 	struct groupnames *gt_grpname;
8251667Smckusick #ifdef ISO
8351667Smckusick 	struct sockaddr_iso *gt_isoaddr;
8451667Smckusick #endif
8551667Smckusick };
8651667Smckusick 
8738460Smckusick struct grouplist {
8851667Smckusick 	int type;
8951667Smckusick 	int exflags;
9051667Smckusick 	struct ucred anoncr;
9151667Smckusick 	union grouptypes gr_ptr;
9238460Smckusick 	struct grouplist *gr_next;
9338460Smckusick };
9438460Smckusick 
9551667Smckusick struct al_mnt {
9651667Smckusick 	struct al_mnt *al_next;
9751667Smckusick 	fsid_t	al_mnted;
9851667Smckusick };
9951667Smckusick 
10051667Smckusick struct groupnames {
10151667Smckusick 	char gn_name[RPCMNT_NAMELEN+1];
10251667Smckusick 	struct grouplist *gn_glist;
10351667Smckusick 	struct groupnames *gn_next;
10451667Smckusick };
10551667Smckusick 
10638460Smckusick /* Global defs */
10746709Sbostic int mntsrv(), umntall_each(), xdr_fhs(), xdr_mlist(), xdr_dir(), xdr_explist();
10851667Smckusick void get_exportlist(), send_umntall(), nextfield(), do_opt();
10951667Smckusick void get_mountlist(), add_mlist(), del_mlist(), free_exp(), free_grp();
11051667Smckusick void get_group(), get_host(), do_group();
11151667Smckusick char *realpath();
11251667Smckusick #ifdef ISO
11351667Smckusick struct iso_addr *iso_addr();
11451667Smckusick #endif
11538460Smckusick struct exportlist exphead;
11644015Smckusick struct mountlist *mlhead;
11751667Smckusick struct groupnames *grpnames;
11838460Smckusick char exname[MAXPATHLEN];
11951667Smckusick struct ucred def_anon = {
12051667Smckusick 	(u_short) 1,
12151667Smckusick 	(uid_t) -2,
12251667Smckusick 	1,
12351667Smckusick 	(gid_t) -2,
12451667Smckusick };
12544015Smckusick int root_only = 1;
12638460Smckusick extern int errno;
12751667Smckusick struct al_mnt *al_head = (struct al_mnt *)0;
12838460Smckusick #ifdef DEBUG
12938460Smckusick int debug = 1;
13051711Smckusick void	SYSLOG __P((int, const char *, ...));
13151711Smckusick #define syslog SYSLOG
13238460Smckusick #else
13338460Smckusick int debug = 0;
13438460Smckusick #endif
13538460Smckusick 
13638460Smckusick /*
13738460Smckusick  * Mountd server for NFS mount protocol as described in:
13839681Smckusick  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
13944015Smckusick  * The optional arguments are the exports file name
14039681Smckusick  * default: _PATH_EXPORTS
14144015Smckusick  * and "-n" to allow nonroot mount.
14238460Smckusick  */
14338460Smckusick main(argc, argv)
14438460Smckusick 	int argc;
14544015Smckusick 	char **argv;
14638460Smckusick {
14738460Smckusick 	SVCXPRT *transp;
14844015Smckusick 	int c;
14944015Smckusick 	extern int optind;
15044015Smckusick 	extern char *optarg;
15138460Smckusick 
15244015Smckusick 	while ((c = getopt(argc, argv, "n")) != EOF)
15344015Smckusick 		switch (c) {
15444015Smckusick 		case 'n':
15544015Smckusick 			root_only = 0;
15644015Smckusick 			break;
15744015Smckusick 		default:
15844015Smckusick 			fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
15944015Smckusick 			exit(1);
16044015Smckusick 		};
16144015Smckusick 	argc -= optind;
16244015Smckusick 	argv += optind;
16351667Smckusick 	grpnames = (struct groupnames *)0;
16444015Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
16544015Smckusick 	mlhead = (struct mountlist *)0;
16644015Smckusick 	if (argc == 1) {
16744015Smckusick 		strncpy(exname, *argv, MAXPATHLEN-1);
16844015Smckusick 		exname[MAXPATHLEN-1] = '\0';
16944015Smckusick 	} else
17044015Smckusick 		strcpy(exname, _PATH_EXPORTS);
17144338Smckusick 	openlog("mountd:", LOG_PID, LOG_DAEMON);
17251667Smckusick 	if (debug)
17351667Smckusick 		fprintf(stderr,"Getting export list.\n");
17444015Smckusick 	get_exportlist();
17551667Smckusick 	if (debug)
17651667Smckusick 		fprintf(stderr,"Getting mount list.\n");
17744015Smckusick 	get_mountlist();
17851667Smckusick 	if (debug)
17951667Smckusick 		fprintf(stderr,"Here we go.\n");
18038460Smckusick 	if (debug == 0) {
18144690Skarels 		daemon(0, 0);
18238460Smckusick 		signal(SIGINT, SIG_IGN);
18338460Smckusick 		signal(SIGQUIT, SIG_IGN);
18438460Smckusick 	}
18538460Smckusick 	signal(SIGHUP, get_exportlist);
18644015Smckusick 	signal(SIGTERM, send_umntall);
18740494Smckusick 	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
18840494Smckusick 	  if (pidfile != NULL) {
18940494Smckusick 		fprintf(pidfile, "%d\n", getpid());
19040494Smckusick 		fclose(pidfile);
19140494Smckusick 	  }
19240494Smckusick 	}
19338460Smckusick 	if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
19438460Smckusick 		syslog(LOG_ERR, "Can't create socket");
19538460Smckusick 		exit(1);
19638460Smckusick 	}
19738460Smckusick 	pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
19851667Smckusick 	if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
19951667Smckusick 	    IPPROTO_UDP)) {
20038460Smckusick 		syslog(LOG_ERR, "Can't register mount");
20138460Smckusick 		exit(1);
20238460Smckusick 	}
20338460Smckusick 	svc_run();
20438460Smckusick 	syslog(LOG_ERR, "Mountd died");
20544690Skarels 	exit(1);
20638460Smckusick }
20738460Smckusick 
20838460Smckusick /*
20938460Smckusick  * The mount rpc service
21038460Smckusick  */
21138460Smckusick mntsrv(rqstp, transp)
21238460Smckusick 	register struct svc_req *rqstp;
21338460Smckusick 	register SVCXPRT *transp;
21438460Smckusick {
21539681Smckusick 	register struct grouplist *grp;
21639681Smckusick 	register u_long **addrp;
21738460Smckusick 	register struct exportlist *ep;
21838460Smckusick 	nfsv2fh_t nfh;
21938460Smckusick 	struct authunix_parms *ucr;
22038460Smckusick 	struct stat stb;
22138460Smckusick 	struct hostent *hp;
22239681Smckusick 	u_long saddr;
22351667Smckusick 	char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
22438460Smckusick 	int bad = ENOENT;
22551667Smckusick 	int found, matched;
22638460Smckusick 	int omask;
22739681Smckusick 	uid_t uid = -2;
22838460Smckusick 
22938460Smckusick 	/* Get authorization */
23038460Smckusick 	switch (rqstp->rq_cred.oa_flavor) {
23138460Smckusick 	case AUTH_UNIX:
23238460Smckusick 		ucr = (struct authunix_parms *)rqstp->rq_clntcred;
23339681Smckusick 		uid = ucr->aup_uid;
23439681Smckusick 		break;
23538460Smckusick 	case AUTH_NULL:
23638460Smckusick 	default:
23739681Smckusick 		break;
23838460Smckusick 	}
23938460Smckusick 
24039681Smckusick 	saddr = transp->xp_raddr.sin_addr.s_addr;
24139681Smckusick 	hp = (struct hostent *)0;
24238460Smckusick 	switch (rqstp->rq_proc) {
24339681Smckusick 	case NULLPROC:
24439681Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
24539681Smckusick 			syslog(LOG_ERR, "Can't send reply");
24639681Smckusick 		return;
24738460Smckusick 	case RPCMNT_MOUNT:
24851667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
24939681Smckusick 			svcerr_weakauth(transp);
25039681Smckusick 			return;
25139681Smckusick 		}
25251667Smckusick 		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
25338460Smckusick 			svcerr_decode(transp);
25438460Smckusick 			return;
25538460Smckusick 		}
25638460Smckusick 
25751667Smckusick 		/*
25851667Smckusick 		 * Get the real pathname and make sure it is a directory
25951667Smckusick 		 * that exists.
26051667Smckusick 		 */
26151667Smckusick 		if (realpath(rpcpath, dirpath) == 0 || stat(dirpath, &stb) < 0
26251667Smckusick 			|| (stb.st_mode&S_IFMT) != S_IFDIR) {
26351667Smckusick 			chdir("/");	/* Just in case realpath doesn't */
26451667Smckusick 			if (debug)
26551667Smckusick 				fprintf(stderr,"stat failed on %s\n",dirpath);
26638460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
26738460Smckusick 				syslog(LOG_ERR, "Can't send reply");
26838460Smckusick 			return;
26938460Smckusick 		}
27038460Smckusick 
27138460Smckusick 		/* Check in the exports list */
27238460Smckusick 		omask = sigblock(sigmask(SIGHUP));
27338460Smckusick 		ep = exphead.ex_next;
27451667Smckusick 		found = FALSE;
27551667Smckusick 		matched = FALSE;
27651667Smckusick 		while (ep != NULL && !found && !matched) {
27751667Smckusick 			struct grouplist *tgrp;
27851667Smckusick 			if (debug)
27951667Smckusick 			    fprintf(stderr,"dirp=[%s]\n",ep->ex_dirp);
28038460Smckusick 			if (!strcmp(ep->ex_dirp, dirpath)) {
28151667Smckusick 			    if (ep->ex_defset)
28251667Smckusick 				grp = (struct grouplist *)0;
28351667Smckusick 			    else
28438460Smckusick 				grp = ep->ex_groups;
28551667Smckusick 			    if (grp == NULL) {
28651667Smckusick 				if (debug)
28751667Smckusick 				    fprintf(stderr,"grp is null\n");
28851667Smckusick 				found = TRUE;
28951667Smckusick 			    }
29051667Smckusick 			    while (grp && !found) {
29151667Smckusick 				matched = TRUE;
29251667Smckusick 				if (debug)
29351667Smckusick 				    fprintf(stderr,"type = [%d]\n",grp->type);
29451667Smckusick 				if (grp->type == MNT_GROUP) {
29551667Smckusick 				    tgrp = grp->gr_ptr.gt_grpname->gn_glist;
29651667Smckusick 				    if (tgrp)
29751667Smckusick 					addrp = (u_long **)
29851667Smckusick 					   tgrp->gr_ptr.gt_hostent->h_addr_list;
29951667Smckusick 				    while(tgrp && !found) {
30051667Smckusick 					if (debug)
30151667Smckusick 					    fprintf(stderr, "cmp [%d] [%d]\n",
30251667Smckusick 						**addrp,saddr);
30351667Smckusick 					if (**addrp == saddr) {
30451667Smckusick 					    found = TRUE;
30551667Smckusick 					    hp = tgrp->gr_ptr.gt_hostent;
30651667Smckusick 					    break;
30751667Smckusick 					}
30851667Smckusick 					if (*++addrp == NULL) {
30951667Smckusick 					    tgrp = tgrp->gr_next;
31051667Smckusick 					    if (tgrp == NULL)
31138460Smckusick 						break;
31251667Smckusick 					    addrp = (u_long **)tgrp->
31351667Smckusick 						gr_ptr.gt_hostent->h_addr_list;
31451667Smckusick 					}
31551667Smckusick 				    }
31651667Smckusick 				} else if (grp->type == MNT_HOST) {
31751667Smckusick 				    addrp = (u_long **)
31851667Smckusick 					grp->gr_ptr.gt_hostent->h_addr_list;
31951667Smckusick 				    while (*addrp) {
32051667Smckusick 					if (debug)
32151667Smckusick 					    fprintf(stderr, "cmp [%d] [%d]\n",
32251667Smckusick 						**addrp,saddr);
32351667Smckusick 					if (**addrp == saddr) {
32451667Smckusick 					    found = TRUE;
32551667Smckusick 					    hp = grp->gr_ptr.gt_hostent;
32651667Smckusick 					    break;
32751667Smckusick 					}
32851667Smckusick 					addrp++;
32951667Smckusick 				    }
33038460Smckusick 				}
33151667Smckusick 				grp = grp->gr_next;
33251667Smckusick 			    }
33338460Smckusick 			}
33438460Smckusick 			ep = ep->ex_next;
33538460Smckusick 		}
33651667Smckusick 		if (!found) {
33738460Smckusick 			bad = EACCES;
33838460Smckusick 			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
33938460Smckusick 				syslog(LOG_ERR, "Can't send reply");
34051667Smckusick 			sigsetmask(omask);
34138460Smckusick 			return;
34251667Smckusick 		} else {
34351667Smckusick 			/* Get the file handle */
34451667Smckusick 			bzero((caddr_t)&nfh, sizeof(nfh));
34551667Smckusick 			if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
34651667Smckusick 				bad = errno;
34751667Smckusick 				fprintf(stderr,
34851667Smckusick 				    "Couldn't get file handle for %s.\n",
34951667Smckusick 				    dirpath);
35051667Smckusick 				if (!svc_sendreply(transp, xdr_long,
35151667Smckusick 				    (caddr_t)&bad))
35251667Smckusick 					syslog(LOG_ERR, "Can't send reply");
35351667Smckusick 				sigsetmask(omask);
35451667Smckusick 				return;
35551667Smckusick 			}
35651667Smckusick 			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
35738460Smckusick 				syslog(LOG_ERR, "Can't send reply");
35851667Smckusick 			if (hp == NULL)
35951667Smckusick 				hp = gethostbyaddr((caddr_t)&saddr,
36051667Smckusick 				    sizeof(saddr), AF_INET);
36151667Smckusick 			if (hp)
36251667Smckusick 				add_mlist(hp->h_name, dirpath);
36351667Smckusick 			else
36451667Smckusick 				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
36551667Smckusick 					dirpath);
36651667Smckusick 			if (debug)
36751667Smckusick 				fprintf(stderr,"Mount successfull.\n");
36838460Smckusick 		}
36951667Smckusick 		sigsetmask(omask);
37038460Smckusick 		return;
37138460Smckusick 	case RPCMNT_DUMP:
37238460Smckusick 		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)0))
37338460Smckusick 			syslog(LOG_ERR, "Can't send reply");
37438460Smckusick 		return;
37538460Smckusick 	case RPCMNT_UMOUNT:
37651667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
37739681Smckusick 			svcerr_weakauth(transp);
37839681Smckusick 			return;
37939681Smckusick 		}
38038460Smckusick 		if (!svc_getargs(transp, xdr_dir, dirpath)) {
38138460Smckusick 			svcerr_decode(transp);
38238460Smckusick 			return;
38338460Smckusick 		}
38438460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
38538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
38644015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
38744015Smckusick 		if (hp)
38844015Smckusick 			del_mlist(hp->h_name, dirpath);
38951667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
39038460Smckusick 		return;
39138460Smckusick 	case RPCMNT_UMNTALL:
39251667Smckusick 		if ((uid != 0 && root_only) || uid == -2) {
39339681Smckusick 			svcerr_weakauth(transp);
39439681Smckusick 			return;
39539681Smckusick 		}
39638460Smckusick 		if (!svc_sendreply(transp, xdr_void, (caddr_t)0))
39738460Smckusick 			syslog(LOG_ERR, "Can't send reply");
39844015Smckusick 		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
39944015Smckusick 		if (hp)
40044015Smckusick 			del_mlist(hp->h_name, (char *)0);
40151667Smckusick 		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)0);
40238460Smckusick 		return;
40338460Smckusick 	case RPCMNT_EXPORT:
40438460Smckusick 		if (!svc_sendreply(transp, xdr_explist, (caddr_t)0))
40538460Smckusick 			syslog(LOG_ERR, "Can't send reply");
40638460Smckusick 		return;
40738460Smckusick 	default:
40838460Smckusick 		svcerr_noproc(transp);
40938460Smckusick 		return;
41038460Smckusick 	}
41138460Smckusick }
41238460Smckusick 
41338460Smckusick /*
41438460Smckusick  * Xdr conversion for a dirpath string
41538460Smckusick  */
41638460Smckusick xdr_dir(xdrsp, dirp)
41738460Smckusick 	XDR *xdrsp;
41838460Smckusick 	char *dirp;
41938460Smckusick {
42038460Smckusick 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
42138460Smckusick }
42238460Smckusick 
42338460Smckusick /*
42438460Smckusick  * Xdr routine to generate fhstatus
42538460Smckusick  */
42638460Smckusick xdr_fhs(xdrsp, nfh)
42738460Smckusick 	XDR *xdrsp;
42838460Smckusick 	nfsv2fh_t *nfh;
42938460Smckusick {
43038460Smckusick 	int ok = 0;
43138460Smckusick 
43238460Smckusick 	if (!xdr_long(xdrsp, &ok))
43338460Smckusick 		return (0);
43438460Smckusick 	return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
43538460Smckusick }
43638460Smckusick 
43738460Smckusick xdr_mlist(xdrsp, cp)
43838460Smckusick 	XDR *xdrsp;
43938460Smckusick 	caddr_t cp;
44038460Smckusick {
44144015Smckusick 	register struct mountlist *mlp;
44238460Smckusick 	int true = 1;
44338460Smckusick 	int false = 0;
44438460Smckusick 	char *strp;
44538460Smckusick 
44644015Smckusick 	mlp = mlhead;
44744015Smckusick 	while (mlp) {
44844015Smckusick 		if (!xdr_bool(xdrsp, &true))
44944015Smckusick 			return (0);
45044015Smckusick 		strp = &mlp->ml_host[0];
45144015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
45244015Smckusick 			return (0);
45344015Smckusick 		strp = &mlp->ml_dirp[0];
45444015Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
45544015Smckusick 			return (0);
45644015Smckusick 		mlp = mlp->ml_next;
45738460Smckusick 	}
45838460Smckusick 	if (!xdr_bool(xdrsp, &false))
45938460Smckusick 		return (0);
46038460Smckusick 	return (1);
46138460Smckusick }
46238460Smckusick 
46338460Smckusick /*
46438460Smckusick  * Xdr conversion for export list
46538460Smckusick  */
46638460Smckusick xdr_explist(xdrsp, cp)
46738460Smckusick 	XDR *xdrsp;
46838460Smckusick 	caddr_t cp;
46938460Smckusick {
47038460Smckusick 	register struct exportlist *ep;
47151667Smckusick 	register struct grouplist *grp, *tgrp;
47238460Smckusick 	int true = 1;
47338460Smckusick 	int false = 0;
47438460Smckusick 	char *strp;
47538460Smckusick 	int omask;
47638460Smckusick 
47738460Smckusick 	omask = sigblock(sigmask(SIGHUP));
47838460Smckusick 	ep = exphead.ex_next;
47938460Smckusick 	while (ep != NULL) {
48038460Smckusick 		if (!xdr_bool(xdrsp, &true))
48138460Smckusick 			goto errout;
48238460Smckusick 		strp = &ep->ex_dirp[0];
48338460Smckusick 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
48438460Smckusick 			goto errout;
48538460Smckusick 		grp = ep->ex_groups;
48638460Smckusick 		while (grp != NULL) {
48751667Smckusick 			if (grp->type == MNT_GROUP) {
48851667Smckusick 				tgrp = grp->gr_ptr.gt_grpname->gn_glist;
48951667Smckusick 				while (tgrp) {
49051667Smckusick 					if (!xdr_bool(xdrsp, &true))
49151667Smckusick 						goto errout;
49251667Smckusick 					strp = tgrp->gr_ptr.gt_hostent->h_name;
49351667Smckusick 					if (!xdr_string(xdrsp, &strp,
49451667Smckusick 					    RPCMNT_NAMELEN))
49551667Smckusick 						goto errout;
49651667Smckusick 					tgrp = tgrp->gr_next;
49751667Smckusick 				}
49851667Smckusick 			} else if (grp->type == MNT_HOST) {
49951667Smckusick 				if (!xdr_bool(xdrsp, &true))
50051667Smckusick 					goto errout;
50151667Smckusick 				strp = grp->gr_ptr.gt_hostent->h_name;
50251667Smckusick 				if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
50351667Smckusick 					goto errout;
50451667Smckusick 			}
50538460Smckusick 			grp = grp->gr_next;
50638460Smckusick 		}
50738460Smckusick 		if (!xdr_bool(xdrsp, &false))
50838460Smckusick 			goto errout;
50938460Smckusick 		ep = ep->ex_next;
51038460Smckusick 	}
51138460Smckusick 	sigsetmask(omask);
51238460Smckusick 	if (!xdr_bool(xdrsp, &false))
51338460Smckusick 		return (0);
51438460Smckusick 	return (1);
51538460Smckusick errout:
51638460Smckusick 	sigsetmask(omask);
51738460Smckusick 	return (0);
51838460Smckusick }
51938460Smckusick 
52038460Smckusick #define LINESIZ	10240
52138460Smckusick char line[LINESIZ];
52238460Smckusick 
52338460Smckusick /*
52438460Smckusick  * Get the export list
52538460Smckusick  */
52646709Sbostic void
52738460Smckusick get_exportlist()
52838460Smckusick {
52951667Smckusick 	struct grouplist *grp, *tgrp;
53051667Smckusick 	struct al_mnt *al_mp, *t_almp;
53138460Smckusick 	register struct exportlist *ep, *ep2;
53251667Smckusick 	struct groupnames *t_gn, *t_gn2;
53351667Smckusick 	struct ucred anoncr;
53438460Smckusick 	FILE *inf;
53538460Smckusick 	char *cp, *endcp;
53639681Smckusick 	char savedc;
53751667Smckusick 	int len, dirplen, def_set;
53851667Smckusick 	int exflags;
53938460Smckusick 
54038460Smckusick 	/*
54138460Smckusick 	 * First, get rid of the old list
54238460Smckusick 	 */
54338460Smckusick 	ep = exphead.ex_next;
54438460Smckusick 	while (ep != NULL) {
54538460Smckusick 		ep2 = ep;
54638460Smckusick 		ep = ep->ex_next;
54744015Smckusick 		free_exp(ep2);
54838460Smckusick 	}
54951667Smckusick 	exphead.ex_next = exphead.ex_prev = (struct exportlist *)0;
55038460Smckusick 
55151667Smckusick 	t_gn = grpnames;
55251667Smckusick 	while(t_gn != NULL) {
55351667Smckusick 		t_gn2 = t_gn;
55451667Smckusick 		t_gn = t_gn->gn_next;
55551667Smckusick 		free_grp(t_gn2);
55651667Smckusick 	}
55751667Smckusick 	grpnames = (struct groupnames *)0;
55851667Smckusick 
55951667Smckusick 	al_mp = al_head;
56051667Smckusick 	while (al_mp) {
56151667Smckusick 		t_almp = al_mp;
56251667Smckusick 		al_mp = al_mp->al_next;
56351667Smckusick 		free((caddr_t)t_almp);
56451667Smckusick 	}
56551667Smckusick 	al_head = (struct al_mnt *)0;
56651667Smckusick 
56738460Smckusick 	/*
56838460Smckusick 	 * Read in the exports file and build the list, calling
56951667Smckusick 	 * mount() as we go along to push the export rules into the kernel.
57038460Smckusick 	 */
57138460Smckusick 	if ((inf = fopen(exname, "r")) == NULL) {
57238460Smckusick 		syslog(LOG_ERR, "Can't open %s", exname);
57338460Smckusick 		exit(2);
57438460Smckusick 	}
57538460Smckusick 	while (fgets(line, LINESIZ, inf)) {
57651667Smckusick 		def_set = TRUE;
57751667Smckusick 		if (debug)
57851667Smckusick 			fprintf(stderr,"Got line %s\n",line);
57938460Smckusick 		cp = line;
58038460Smckusick 		nextfield(&cp, &endcp);
58151667Smckusick 		if (*cp == '#')
58251667Smckusick 			goto nextline;
58351667Smckusick 		if (*cp != '/') {
58451667Smckusick 			/* create group listing of names */
58551667Smckusick 			get_group(cp, ep);
58651667Smckusick 			goto nextline;
58745271Smckusick 		}
58851667Smckusick 		exflags = MNT_EXPORTED;
58951667Smckusick 		anoncr = def_anon;
59044015Smckusick 
59144015Smckusick 		/*
59244015Smckusick 		 * Create new exports list entry
59344015Smckusick 		 */
59438460Smckusick 		len = endcp-cp;
59538460Smckusick 		if (len <= RPCMNT_PATHLEN && len > 0) {
59651667Smckusick 			/*
59751667Smckusick 			 * See if this directory is already in the list.
59851667Smckusick 			 */
59951667Smckusick 			ep = exphead.ex_next;
60051667Smckusick 			while (ep) {
60151667Smckusick 				if (!strcmp(ep->ex_dirp, cp))
60251667Smckusick 					break;
60351667Smckusick 				ep = ep->ex_next;
60451667Smckusick 			}
60551667Smckusick 			if (ep == (struct exportlist *)0) {
60651667Smckusick 				ep = (struct exportlist *)malloc(sizeof(*ep));
60751667Smckusick 				if (ep == NULL)
60851667Smckusick 					goto err;
60951667Smckusick 				ep->ex_next = (struct exportlist *)0;
61051667Smckusick 				ep->ex_prev = (struct exportlist *)0;
61151667Smckusick 				ep->ex_groups = (struct grouplist *)0;
61251667Smckusick 				ep->ex_defset = FALSE;
61351667Smckusick 				bcopy(cp, ep->ex_dirp, len);
61451667Smckusick 				ep->ex_dirp[len] = '\0';
61551667Smckusick 			}
61644015Smckusick 			dirplen = len;
61751667Smckusick 			if (debug)
61851667Smckusick 				fprintf(stderr, "Making new ep. [%s]\n",
61951667Smckusick 				    ep->ex_dirp);
62045271Smckusick 		} else {
62151667Smckusick 			syslog(LOG_ERR, "Bad Exports File line: %s\n", line);
62251667Smckusick 			goto nextline;
62345271Smckusick 		}
62438460Smckusick 		cp = endcp;
62538460Smckusick 		nextfield(&cp, &endcp);
62638460Smckusick 		len = endcp-cp;
62738460Smckusick 		while (len > 0) {
62839681Smckusick 			savedc = *endcp;
62939681Smckusick 			*endcp = '\0';
63045271Smckusick 			if (len > RPCMNT_NAMELEN)
63145271Smckusick 				goto more;
63245271Smckusick 			if (*cp == '-') {
63351667Smckusick 				do_opt(cp + 1, ep, &exflags, &anoncr);
63451667Smckusick 				exflags |= MNT_EXPORTED;
63551667Smckusick 				def_set = TRUE;
63651667Smckusick 				if (debug)
63751667Smckusick 					fprintf(stderr, "got r=%d, ex=%d\n",
63851667Smckusick 					    anoncr.cr_uid,exflags);
63945271Smckusick 				goto more;
64051667Smckusick 			} else {
64151667Smckusick 				def_set = FALSE;
64251667Smckusick 				if (*cp == '$') {
64351667Smckusick 					do_group(cp + 1, endcp, &grp);
64451667Smckusick 					grp->type = MNT_GROUP;
64551667Smckusick 				} else {
64651667Smckusick 					get_host(cp, endcp, ep, &grp);
64738460Smckusick 				}
64851667Smckusick 				if (grp != NULL) {
64951667Smckusick 					grp->exflags = exflags;
65051667Smckusick 					grp->anoncr = anoncr;
65151667Smckusick 					grp->gr_next = ep->ex_groups;
65251667Smckusick 					ep->ex_groups = grp;
65351667Smckusick 				}
65438460Smckusick 			}
65545271Smckusick 		more:
65638460Smckusick 			cp = endcp;
65739681Smckusick 			*cp = savedc;
65838460Smckusick 			nextfield(&cp, &endcp);
65945271Smckusick 			len = endcp - cp;
66038460Smckusick 		}
66151667Smckusick 		if (def_set == TRUE) {
66251667Smckusick 		    if (ep->ex_defset == TRUE)
66351667Smckusick 			syslog(LOG_ERR, "Default specified again dir:%s\n",
66451667Smckusick 				ep->ex_dirp);
66551667Smckusick 		    else {
66651667Smckusick 			struct hostent *hpe;
66751667Smckusick 
66851667Smckusick 			ep->ex_defset = TRUE;
66951667Smckusick 			if (debug)
67051667Smckusick 				fprintf(stderr,"Adding a default entry\n");
67151667Smckusick 			/* add a default group and make the grp list NULL */
67251667Smckusick 			hpe = (struct hostent *)malloc(sizeof(struct hostent));
67351667Smckusick 			if (hpe == NULL) {
67451667Smckusick 				syslog(LOG_ERR,"No more memory: mountd Failed");
67551667Smckusick 				exit(2);
67651667Smckusick 			}
67751667Smckusick 			tgrp = (struct grouplist *)
67851667Smckusick 			    malloc(sizeof(struct grouplist));
67951667Smckusick 			if (tgrp == NULL) {
68051667Smckusick 				syslog(LOG_ERR,"No more memory: mountd Failed");
68151667Smckusick 				exit(2);
68251667Smckusick 			}
68351667Smckusick 			tgrp->anoncr = anoncr;
68451667Smckusick 			tgrp->exflags = exflags;
685*51712Smckusick 			tgrp->type = MNT_HOST;
686*51712Smckusick 			hpe->h_name = (char *)0;
68751667Smckusick 			hpe->h_addrtype = AF_INET;
68851667Smckusick 			hpe->h_length = sizeof (u_long);
689*51712Smckusick 			hpe->h_addr_list = (char **)0;
69051667Smckusick 			tgrp->gr_ptr.gt_hostent = hpe;
69151667Smckusick 			tgrp->gr_next = ep->ex_groups;
69251667Smckusick 			ep->ex_groups = tgrp;
69351667Smckusick 		    }
69451667Smckusick 		}
69551667Smckusick 		grp = ep->ex_groups;
69651667Smckusick 		while (grp != NULL) {
69751667Smckusick 			exflags = grp->exflags;
69851667Smckusick 			anoncr = grp->anoncr;
69951667Smckusick 			if (grp->type == MNT_GROUP) {
70051667Smckusick 				tgrp = grp->gr_ptr.gt_grpname->gn_glist;
70151667Smckusick 				while(tgrp != NULL) {
70251667Smckusick 					if (do_mount(ep, tgrp, exflags, &anoncr,
70351667Smckusick 					    dirplen) == FALSE)
70451667Smckusick 						goto nextline;
70551667Smckusick 					tgrp = tgrp->gr_next;
70651667Smckusick 				}
70751667Smckusick 			} else {
70851667Smckusick 				if (do_mount(ep, grp, exflags, &anoncr, dirplen)
70951667Smckusick 				    == FALSE)
71051667Smckusick 					goto nextline;
71151667Smckusick 			}
71251667Smckusick 			grp = grp->gr_next;
71351667Smckusick 		}
71451667Smckusick 		if (cp)
71551667Smckusick 			*cp = savedc;
71651667Smckusick 		if (ep->ex_prev == (struct exportlist *)0) {
71751667Smckusick 			ep->ex_next = exphead.ex_next;
71851667Smckusick 			ep->ex_prev = &exphead;
71951667Smckusick 			if (ep->ex_next != NULL)
72051667Smckusick 				ep->ex_next->ex_prev = ep;
72151667Smckusick 			exphead.ex_next = ep;
72251667Smckusick 		}
72351667Smckusick nextline:
72451667Smckusick 		;
72551667Smckusick 	}
72651667Smckusick 	fclose(inf);
72751667Smckusick 	return;
72851667Smckusick err:
72951667Smckusick 	syslog(LOG_ERR, "No more memory: mountd Failed");
73051667Smckusick 	exit(2);
73151667Smckusick }
73251667Smckusick 
73351667Smckusick do_mount(ep, grp, exflags, anoncrp, dirplen)
73451667Smckusick 	struct exportlist *ep;
73551667Smckusick 	struct grouplist *grp;
73651667Smckusick 	int exflags, dirplen;
73751667Smckusick 	struct ucred *anoncrp;
73851667Smckusick {
73951667Smckusick 	int done, found;
74051667Smckusick 	register u_long **addrp;
74151667Smckusick 	struct sockaddr_in sin;
74251667Smckusick 	struct statfs stfsbuf;
74351667Smckusick 	struct ufs_args args, targs;
74451667Smckusick 	struct al_mnt *al_mp;
74551667Smckusick 	char *cp, savedc;
74651667Smckusick 
74751667Smckusick 	args.fspec = 0;
74851667Smckusick 	args.exflags = exflags;
74951667Smckusick 	args.anon = *anoncrp;
75051667Smckusick 	sin.sin_family = AF_INET;
75151667Smckusick 	sin.sin_port = 0;
75251667Smckusick 	sin.sin_len = sizeof(sin);
75351667Smckusick 	if (grp->type == MNT_HOST)
75451667Smckusick 		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
75551667Smckusick 	done = FALSE;
75651667Smckusick 	while(!done) {
75751667Smckusick 		if (grp->type == MNT_HOST) {
758*51712Smckusick 			if (grp->gr_ptr.gt_hostent->h_name)
759*51712Smckusick 				sin.sin_addr.s_addr = **addrp;
760*51712Smckusick 			else
76151667Smckusick 				sin.sin_addr.s_addr = INADDR_ANY;
76251667Smckusick 			args.saddr = (struct sockaddr *)&sin;
76351667Smckusick 			args.slen = sizeof(sin);
76451667Smckusick #ifdef ISO
76551667Smckusick 		} else if (grp->type == MNT_ISO) {
76651667Smckusick 			args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
76751667Smckusick 			args.slen = sizeof (struct sockaddr_iso);
76851667Smckusick #endif	/* ISO */
76951667Smckusick 		} else {
77051667Smckusick 			syslog(LOG_ERR, "Bad grouptype");
77151667Smckusick 			free_exp(ep);
77251667Smckusick 			return (FALSE);
77351667Smckusick 		}
77451667Smckusick 		if (statfs(ep->ex_dirp, &stfsbuf) < 0) {
77551667Smckusick 			if (debug) {
77651667Smckusick 				fprintf(stderr,"statfs failed.\n");
77751667Smckusick 			}
77851667Smckusick 			syslog(LOG_ERR, "Invalid path: %s", ep->ex_dirp);
77951667Smckusick 			free_exp(ep);
78051667Smckusick 			return(FALSE);
78151667Smckusick 		}
78251667Smckusick 		found = FALSE;
78351667Smckusick 		for (al_mp = al_head; al_mp && !found; al_mp = al_mp->al_next)
78451667Smckusick 			if (al_mp->al_mnted.val[0] == stfsbuf.f_fsid.val[0] &&
78551667Smckusick 			    al_mp->al_mnted.val[1] == stfsbuf.f_fsid.val[1])
78651667Smckusick 				found = TRUE;
78751667Smckusick 		if (!found) {
78851667Smckusick 			/* first time for fs, so must send a MNT_DELEXPORT
78951667Smckusick 			 * to clear the old export list held in the kernel
79051667Smckusick 			 * for this fs.
79151667Smckusick 			 */
79251667Smckusick 			al_mp = (struct al_mnt *)malloc(sizeof (struct al_mnt));
79351667Smckusick 			al_mp->al_mnted = stfsbuf.f_fsid;
79451667Smckusick 			al_mp->al_next = al_head;
79551667Smckusick 			al_head = al_mp;
79651667Smckusick 			targs.fspec = 0;
79751667Smckusick 			targs.exflags = MNT_DELEXPORT;
79844015Smckusick 			cp = (char *)0;
79951667Smckusick 			while (mount(MOUNT_UFS, ep->ex_dirp,
80051667Smckusick 			       stfsbuf.f_flags | MNT_UPDATE, &targs) < 0) {
80151667Smckusick 				if (debug) {
80251667Smckusick 					fprintf(stderr,
80351667Smckusick 					    "tried [%s][%d]\n",
80451667Smckusick 					    ep->ex_dirp,errno);
80551667Smckusick 				}
80644015Smckusick 				if (cp == NULL)
80744015Smckusick 					cp = ep->ex_dirp + dirplen - 1;
80844015Smckusick 				else
80944015Smckusick 					*cp = savedc;
81051667Smckusick 				cp--;
81144015Smckusick 				/* back up over the last component */
81244015Smckusick 				while (*cp == '/' && cp > ep->ex_dirp)
81344015Smckusick 					cp--;
81444015Smckusick 				while (*(cp - 1) != '/' && cp > ep->ex_dirp)
81544015Smckusick 					cp--;
81644015Smckusick 				if (cp == ep->ex_dirp) {
81751667Smckusick 					if (debug) {
81851667Smckusick 						fprintf(stderr,"mnt unsucc\n");
81951667Smckusick 					}
82051667Smckusick 					syslog(LOG_ERR,
82151667Smckusick 					    "Can't export %s", ep->ex_dirp);
82244015Smckusick 					free_exp(ep);
82351667Smckusick 					return(FALSE);
82444015Smckusick 				}
82544015Smckusick 				savedc = *cp;
82644015Smckusick 				*cp = '\0';
82744015Smckusick 			}
82851667Smckusick 			if (cp != NULL) {
82944015Smckusick 				*cp = savedc;
83051667Smckusick 			}
83138460Smckusick 		}
83251667Smckusick 		cp = (char *)0;
83351667Smckusick 		while (mount(MOUNT_UFS, ep->ex_dirp,
83451667Smckusick 		       stfsbuf.f_flags | MNT_UPDATE, &args) < 0) {
83551667Smckusick 			if (errno == EPERM) {
83651667Smckusick 				syslog(LOG_ERR,
83751667Smckusick 				     "Can't change attributes for %s.\n",
83851667Smckusick 				     ep->ex_dirp);
83951667Smckusick 				if (cp != NULL)
84051667Smckusick 					*cp = savedc;
84151667Smckusick 				break;
84251667Smckusick 			}
84351667Smckusick 			if (cp == NULL)
84451667Smckusick 				cp = ep->ex_dirp + dirplen - 1;
84551667Smckusick 			else
84651667Smckusick 				*cp = savedc;
84751667Smckusick 			cp--;
84851667Smckusick 			/* back up over the last component */
84951667Smckusick 			while (*cp == '/' && cp > ep->ex_dirp)
85051667Smckusick 				cp--;
85151667Smckusick 			while (*(cp - 1) != '/' && cp > ep->ex_dirp)
85251667Smckusick 				cp--;
85351667Smckusick 			if (cp == ep->ex_dirp) {
85451667Smckusick 				if (debug) {
85551667Smckusick 					fprintf(stderr,"mnt unsucc\n");
85651667Smckusick 				}
85751667Smckusick 				syslog(LOG_ERR, "Can't export %s", ep->ex_dirp);
85851667Smckusick 				free_exp(ep);
85951667Smckusick 				return(FALSE);
86051667Smckusick 			}
86151667Smckusick 			savedc = *cp;
86251667Smckusick 			*cp = '\0';
86351667Smckusick 		}
86451667Smckusick 		if (addrp == NULL)
86551667Smckusick 			done = TRUE;
86651667Smckusick 		else {
86751667Smckusick 			++addrp;
86851667Smckusick 			if (*addrp == NULL)
86951667Smckusick 				done = TRUE;
87051667Smckusick 		}
87151667Smckusick 		if (cp != NULL)
87251667Smckusick 			*cp = savedc;
87338460Smckusick 	}
87451667Smckusick 	return(TRUE);
87538460Smckusick }
87638460Smckusick 
87751667Smckusick 
87838460Smckusick /*
87938460Smckusick  * Parse out the next white space separated field
88038460Smckusick  */
88151667Smckusick void
88238460Smckusick nextfield(cp, endcp)
88338460Smckusick 	char **cp;
88438460Smckusick 	char **endcp;
88538460Smckusick {
88638460Smckusick 	register char *p;
88738460Smckusick 
88838460Smckusick 	p = *cp;
88938460Smckusick 	while (*p == ' ' || *p == '\t')
89038460Smckusick 		p++;
89138460Smckusick 	if (*p == '\n' || *p == '\0') {
89238460Smckusick 		*cp = *endcp = p;
89338460Smckusick 		return;
89438460Smckusick 	}
89538460Smckusick 	*cp = p++;
89638460Smckusick 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
89738460Smckusick 		p++;
89838460Smckusick 	*endcp = p;
89938460Smckusick }
90039681Smckusick 
90139681Smckusick /*
90244015Smckusick  * Parse the option string
90339681Smckusick  */
90451667Smckusick void
90551667Smckusick do_opt(cpopt, ep, exflagsp, cr)
90644015Smckusick 	register char *cpopt;
90751667Smckusick 	struct exportlist *ep;
90851667Smckusick 	int *exflagsp;
90951667Smckusick 	struct ucred *cr;
91039681Smckusick {
91144015Smckusick 	register char *cpoptarg, *cpoptend;
912*51712Smckusick 	int allflag = 1;
91339681Smckusick 
91444015Smckusick 	while (cpopt && *cpopt) {
91544015Smckusick 		if (cpoptend = index(cpopt, ','))
91644015Smckusick 			*cpoptend++ = '\0';
91744015Smckusick 		if (cpoptarg = index(cpopt, '='))
91844015Smckusick 			*cpoptarg++ = '\0';
91944015Smckusick 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
92051667Smckusick 			*exflagsp |= MNT_EXRDONLY;
92151667Smckusick 		} else if ((!strcmp(cpopt, "root") || !strcmp(cpopt, "r") ||
92251667Smckusick 		    !(allflag = strcmp(cpopt, "allanon"))) && cpoptarg) {
92351667Smckusick 			parsecred(cpoptarg, cr);
92451667Smckusick 			if (allflag == 0)
92551667Smckusick 				*exflagsp |= MNT_EXPORTANON;
92651667Smckusick 		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
92751667Smckusick 			*exflagsp |= MNT_EXKERB;
92844015Smckusick 		} else
92951667Smckusick 			syslog(LOG_ERR, "opt %s ignored for %s", cpopt,
93044015Smckusick 			       ep->ex_dirp);
93144015Smckusick 		cpopt = cpoptend;
93244015Smckusick 	}
93344015Smckusick }
93444015Smckusick 
93551667Smckusick /*
93651667Smckusick  * Parse a description of a credential.
93751667Smckusick  */
93851667Smckusick parsecred(namelist, cr)
93951667Smckusick 	char *namelist;
94051667Smckusick 	register struct ucred *cr;
94151667Smckusick {
94251667Smckusick 	register char *name;
94351667Smckusick 	register int cnt;
94451667Smckusick 	char *names;
94551667Smckusick 	struct passwd *pw;
94651667Smckusick 	struct group *gr;
94751667Smckusick 	int ngroups, groups[NGROUPS + 1];
94851667Smckusick 
94951667Smckusick 	/*
95051667Smckusick 	 * Set up the unpriviledged user.
95151667Smckusick 	 */
95251667Smckusick 	cr->cr_ref = 1;
95351667Smckusick 	cr->cr_uid = -2;
95451667Smckusick 	cr->cr_groups[0] = -2;
95551667Smckusick 	cr->cr_ngroups = 1;
95651667Smckusick 	/*
95751667Smckusick 	 * Get the user's password table entry.
95851667Smckusick 	 */
95951667Smckusick 	names = strsep(&namelist, " \t\n");
96051667Smckusick 	name = strsep(&names, ":");
96151667Smckusick 	if (isdigit(*name) || *name == '-')
96251667Smckusick 		pw = getpwuid(atoi(name));
96351667Smckusick 	else
96451667Smckusick 		pw = getpwnam(name);
96551667Smckusick 	/*
96651667Smckusick 	 * Credentials specified as those of a user.
96751667Smckusick 	 */
96851667Smckusick 	if (names == NULL) {
96951667Smckusick 		if (pw == NULL) {
97051667Smckusick 			syslog(LOG_ERR, "Unknown user: %s\n", name);
97151667Smckusick 			return;
97251667Smckusick 		}
97351667Smckusick 		cr->cr_uid = pw->pw_uid;
97451667Smckusick 		ngroups = NGROUPS + 1;
97551667Smckusick 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
97651667Smckusick 			syslog(LOG_ERR, "Too many groups\n");
97751667Smckusick 		/*
97851667Smckusick 		 * Convert from int's to gid_t's and compress out duplicate
97951667Smckusick 		 */
98051667Smckusick 		cr->cr_ngroups = ngroups - 1;
98151667Smckusick 		cr->cr_groups[0] = groups[0];
98251667Smckusick 		for (cnt = 2; cnt < ngroups; cnt++)
98351667Smckusick 			cr->cr_groups[cnt - 1] = groups[cnt];
98451667Smckusick 		return;
98551667Smckusick 	}
98651667Smckusick 	/*
98751667Smckusick 	 * Explicit credential specified as a colon separated list:
98851667Smckusick 	 *	uid:gid:gid:...
98951667Smckusick 	 */
99051667Smckusick 	if (pw != NULL)
99151667Smckusick 		cr->cr_uid = pw->pw_uid;
99251667Smckusick 	else if (isdigit(*name) || *name == '-')
99351667Smckusick 		cr->cr_uid = atoi(name);
99451667Smckusick 	else {
99551667Smckusick 		syslog(LOG_ERR, "Unknown user: %s\n", name);
99651667Smckusick 		return;
99751667Smckusick 	}
99851667Smckusick 	cr->cr_ngroups = 0;
99951667Smckusick 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
100051667Smckusick 		name = strsep(&names, ":");
100151667Smckusick 		if (isdigit(*name) || *name == '-') {
100251667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
100351667Smckusick 		} else {
100451667Smckusick 			if ((gr = getgrnam(name)) == NULL) {
100551667Smckusick 				syslog(LOG_ERR, "Unknown group: %s\n", name);
100651667Smckusick 				continue;
100751667Smckusick 			}
100851667Smckusick 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
100951667Smckusick 		}
101051667Smckusick 	}
101151667Smckusick 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
101251667Smckusick 		syslog(LOG_ERR, "Too many groups\n");
101351667Smckusick }
101451667Smckusick 
101544015Smckusick #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
101644015Smckusick /*
101744015Smckusick  * Routines that maintain the remote mounttab
101844015Smckusick  */
101951667Smckusick void
102051667Smckusick get_mountlist()
102144015Smckusick {
102244015Smckusick 	register struct mountlist *mlp, **mlpp;
102344015Smckusick 	register char *eos, *dirp;
102444015Smckusick 	int len;
102544015Smckusick 	char str[STRSIZ];
102644015Smckusick 	FILE *mlfile;
102744015Smckusick 
1028*51712Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
102951667Smckusick 		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
103044015Smckusick 		return;
103144015Smckusick 	}
103244015Smckusick 	mlpp = &mlhead;
103344015Smckusick 	while (fgets(str, STRSIZ, mlfile) != NULL) {
103444015Smckusick 		if ((dirp = index(str, '\t')) == NULL &&
103544015Smckusick 		    (dirp = index(str, ' ')) == NULL)
103644015Smckusick 			continue;
103744015Smckusick 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
103844015Smckusick 		len = dirp-str;
103944015Smckusick 		if (len > RPCMNT_NAMELEN)
104044015Smckusick 			len = RPCMNT_NAMELEN;
104144015Smckusick 		bcopy(str, mlp->ml_host, len);
104244015Smckusick 		mlp->ml_host[len] = '\0';
104344015Smckusick 		while (*dirp == '\t' || *dirp == ' ')
104444015Smckusick 			dirp++;
104544015Smckusick 		if ((eos = index(dirp, '\t')) == NULL &&
104644015Smckusick 		    (eos = index(dirp, ' ')) == NULL &&
104744015Smckusick 		    (eos = index(dirp, '\n')) == NULL)
104844015Smckusick 			len = strlen(dirp);
104944015Smckusick 		else
105044015Smckusick 			len = eos-dirp;
105144015Smckusick 		if (len > RPCMNT_PATHLEN)
105244015Smckusick 			len = RPCMNT_PATHLEN;
105344015Smckusick 		bcopy(dirp, mlp->ml_dirp, len);
105444015Smckusick 		mlp->ml_dirp[len] = '\0';
105544015Smckusick 		mlp->ml_next = (struct mountlist *)0;
105644015Smckusick 		*mlpp = mlp;
105744015Smckusick 		mlpp = &mlp->ml_next;
105844015Smckusick 	}
105944015Smckusick 	fclose(mlfile);
106044015Smckusick }
106144015Smckusick 
106251667Smckusick void
106351667Smckusick del_mlist(hostp, dirp)
106444015Smckusick 	register char *hostp, *dirp;
106544015Smckusick {
106644015Smckusick 	register struct mountlist *mlp, **mlpp;
1067*51712Smckusick 	struct mountlist *mlp2;
106844015Smckusick 	FILE *mlfile;
106944015Smckusick 	int fnd = 0;
107044015Smckusick 
107144015Smckusick 	mlpp = &mlhead;
107244015Smckusick 	mlp = mlhead;
107344015Smckusick 	while (mlp) {
107444015Smckusick 		if (!strcmp(mlp->ml_host, hostp) &&
107544015Smckusick 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
107644015Smckusick 			fnd = 1;
1077*51712Smckusick 			mlp2 = mlp;
1078*51712Smckusick 			*mlpp = mlp = mlp->ml_next;
1079*51712Smckusick 			free((caddr_t)mlp2);
1080*51712Smckusick 		} else {
1081*51712Smckusick 			mlpp = &mlp->ml_next;
1082*51712Smckusick 			mlp = mlp->ml_next;
108339681Smckusick 		}
108439681Smckusick 	}
108544015Smckusick 	if (fnd) {
108644015Smckusick 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
108751667Smckusick 			syslog(LOG_WARNING,"Can't update %s", _PATH_RMOUNTLIST);
108844015Smckusick 			return;
108944015Smckusick 		}
109044015Smckusick 		mlp = mlhead;
109144015Smckusick 		while (mlp) {
109244015Smckusick 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
109344015Smckusick 			mlp = mlp->ml_next;
109444015Smckusick 		}
109544015Smckusick 		fclose(mlfile);
109644015Smckusick 	}
109739681Smckusick }
109844015Smckusick 
109951667Smckusick void
110051667Smckusick add_mlist(hostp, dirp)
110144015Smckusick 	register char *hostp, *dirp;
110244015Smckusick {
110344015Smckusick 	register struct mountlist *mlp, **mlpp;
110444015Smckusick 	FILE *mlfile;
110544015Smckusick 
110644015Smckusick 	mlpp = &mlhead;
110744015Smckusick 	mlp = mlhead;
110844015Smckusick 	while (mlp) {
110944015Smckusick 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
111044015Smckusick 			return;
111144015Smckusick 		mlpp = &mlp->ml_next;
111244015Smckusick 		mlp = mlp->ml_next;
111344015Smckusick 	}
111444015Smckusick 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
111544015Smckusick 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
111644015Smckusick 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
111744015Smckusick 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
111844015Smckusick 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
111944015Smckusick 	mlp->ml_next = (struct mountlist *)0;
112044015Smckusick 	*mlpp = mlp;
112144015Smckusick 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
112244015Smckusick 		syslog(LOG_WARNING, "Can't update %s", _PATH_RMOUNTLIST);
112344015Smckusick 		return;
112444015Smckusick 	}
112544015Smckusick 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
112644015Smckusick 	fclose(mlfile);
112744015Smckusick }
112844015Smckusick 
112944015Smckusick /*
113044015Smckusick  * This function is called via. SIGTERM when the system is going down.
113144015Smckusick  * It sends a broadcast RPCMNT_UMNTALL.
113244015Smckusick  */
113346709Sbostic void
113444015Smckusick send_umntall()
113544015Smckusick {
113644015Smckusick 	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
113744015Smckusick 		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
113851667Smckusick 	exit(0);
113944015Smckusick }
114044015Smckusick 
114144015Smckusick umntall_each(resultsp, raddr)
114244015Smckusick 	caddr_t resultsp;
114344015Smckusick 	struct sockaddr_in *raddr;
114444015Smckusick {
114544015Smckusick 	return (1);
114644015Smckusick }
114744015Smckusick 
114844015Smckusick /*
114944015Smckusick  * Free up an exports list component
115044015Smckusick  */
115151667Smckusick void
115244015Smckusick free_exp(ep)
115344015Smckusick 	register struct exportlist *ep;
115444015Smckusick {
115544015Smckusick 	register struct grouplist *grp;
115644015Smckusick 	struct grouplist *grp2;
115744015Smckusick 
115844015Smckusick 	grp = ep->ex_groups;
115944015Smckusick 	while (grp != NULL) {
116044015Smckusick 		grp2 = grp;
116144015Smckusick 		grp = grp->gr_next;
116251667Smckusick 		free_grp(grp2);
116344015Smckusick 	}
116444015Smckusick 	free((caddr_t)ep);
116544015Smckusick }
116651667Smckusick 
116751667Smckusick /*
116851667Smckusick  * Free up a group list.
116951667Smckusick  */
117051667Smckusick void
117151667Smckusick free_grp(grp)
117251667Smckusick 	register struct grouplist *grp;
117351667Smckusick {
117451667Smckusick 	register char **addrp;
117551667Smckusick 
117651667Smckusick 	if (grp->type == MNT_HOST) {
1177*51712Smckusick 		if (grp->gr_ptr.gt_hostent->h_name) {
1178*51712Smckusick 			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
1179*51712Smckusick 			while (addrp && *addrp)
1180*51712Smckusick 				free(*addrp++);
1181*51712Smckusick 			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
1182*51712Smckusick 			free(grp->gr_ptr.gt_hostent->h_name);
1183*51712Smckusick 		}
118451667Smckusick 		free((caddr_t)grp->gr_ptr.gt_hostent);
118551667Smckusick 	}
118651667Smckusick #ifdef ISO
118751667Smckusick 	else if (grp->type == MNT_ISO)
118851667Smckusick 		free((caddr_t)grp->gr_ptr.gt_isoaddr);
118951667Smckusick #endif
119051667Smckusick 	free((caddr_t)grp);
119151667Smckusick }
119251667Smckusick 
119351667Smckusick void
119451667Smckusick get_group(line, ep)
119551667Smckusick 	char *line;
119651667Smckusick 	struct export_list *ep;
119751667Smckusick {
119851667Smckusick 	int done;
119951667Smckusick 	struct grouplist *grp;
120051667Smckusick 	struct groupnames *t_gn;
120151667Smckusick 	char *cp, *endcp, savedc;
120251667Smckusick 
120351667Smckusick 	cp = line;
120451667Smckusick 	nextfield(&cp, &endcp);
120551667Smckusick 	savedc = *endcp;
120651667Smckusick 	*endcp = NULL;
120751667Smckusick 	if (*(endcp-1) == '=') {
120851667Smckusick 		*(endcp-1) = NULL;
120951667Smckusick 	}
121051667Smckusick 	/* check to see if this group exists already */
121151667Smckusick 	t_gn = grpnames;
121251667Smckusick 	while(t_gn != NULL) {
121351667Smckusick 		if (strcmp(t_gn->gn_name,cp) == 0) {
121451667Smckusick 			syslog(LOG_ERR,"Group redifined, second ignored.");
121551667Smckusick 			return;
121651667Smckusick 		}
121751667Smckusick 		t_gn = t_gn->gn_next;
121851667Smckusick 	}
121951667Smckusick 
122051667Smckusick 	/* make a new group list entry */
122151667Smckusick 	t_gn = (struct groupnames *)malloc(sizeof(struct groupnames));
122251667Smckusick 	if (t_gn == NULL) {
122351667Smckusick 		syslog(LOG_ERR,"Group: Couldn't Malloc.");
122451667Smckusick 		exit(2);
122551667Smckusick 	}
122651667Smckusick 	strcpy(t_gn->gn_name,cp);
122751667Smckusick 	t_gn->gn_next = grpnames;
122851667Smckusick 	grpnames = t_gn;
122951667Smckusick 	t_gn->gn_glist = NULL;
123051667Smckusick 	*endcp = savedc;
123151667Smckusick 	cp = endcp;
123251667Smckusick 	done = FALSE;
123351667Smckusick 	while(!done) {
123451667Smckusick 		nextfield(&cp, &endcp);
123551667Smckusick 		if (cp == endcp)
123651667Smckusick 			done = TRUE;
123751667Smckusick 		else {
123851667Smckusick 			savedc = *endcp;
123951667Smckusick 			*endcp = NULL;
124051667Smckusick 			if (strcmp(cp, "=")) {
124151667Smckusick 				/* add to group list */
124251667Smckusick 				get_host(cp, endcp, ep, &grp);
124351667Smckusick 				if (grp != NULL) {
124451667Smckusick 					grp->gr_next = t_gn->gn_glist;
124551667Smckusick 					t_gn->gn_glist = grp;
124651667Smckusick 				}
124751667Smckusick 			}
124851667Smckusick 			*endcp = savedc;
124951667Smckusick 			cp = endcp;
125051667Smckusick 		}
125151667Smckusick 	}
125251667Smckusick }
125351667Smckusick 
125451667Smckusick void
125551667Smckusick get_host(cp, endcp, ep, gp)
125651667Smckusick 	char *cp, *endcp;
125751667Smckusick 	struct exportlist *ep;
125851667Smckusick 	struct grouplist **gp;
125951667Smckusick {
126051667Smckusick 	register struct hostent *hp, *nhp;
126151667Smckusick 	register struct grouplist *grp;
126251667Smckusick 	register char **addrp, **naddrp;
126351667Smckusick 	struct hostent t_host;
126451667Smckusick 	int i;
126551667Smckusick 	u_long saddr;
126651667Smckusick 	char *aptr[2];
126751667Smckusick #ifdef ISO
126851667Smckusick 	struct iso_addr *isop;
126951667Smckusick 	struct sockaddr_iso *isoaddr;
127051667Smckusick #endif
127151667Smckusick 
127251667Smckusick 	if (isdigit(*cp)) {
127351667Smckusick 		saddr = inet_addr(cp);
127451667Smckusick 		if (saddr == -1) {
127551667Smckusick 			syslog(LOG_ERR,
127651667Smckusick 			    "Bad Exports File, %s: %s", cp,
127751667Smckusick 			    "inet_addr failed, ignored");
127851667Smckusick 			*gp = NULL;
127951667Smckusick 			return;
128051667Smckusick 		}
128151667Smckusick 		hp = &t_host;
128251667Smckusick 		hp->h_name = cp;
128351667Smckusick 		hp->h_addrtype = AF_INET;
128451667Smckusick 		hp->h_length = sizeof (u_long);
128551667Smckusick 		hp->h_addr_list = aptr;
128651667Smckusick 		aptr[0] = (char *)&saddr;
128751667Smckusick 		aptr[1] = (char *)0;
128851667Smckusick #ifdef ISO
128951667Smckusick 	} else if (!strncmp(cp, "iso=", 4)) {
129051667Smckusick 		if ((isop = iso_addr(cp + 4)) == NULL) {
129151667Smckusick 			syslog(LOG_ERR,
129251667Smckusick 			    "Bad Exports File, %s: %s", cp,
129351667Smckusick 			    "iso_addr failed, ignored");
129451667Smckusick 			*gp = NULL;
129551667Smckusick 			return;
129651667Smckusick 		}
129751667Smckusick 		isoaddr = (struct sockaddr_iso *)
129851667Smckusick 		    malloc(sizeof (struct sockaddr_iso));
129951667Smckusick 		if (isoaddr == NULL)
130051667Smckusick 			goto err1;
130151667Smckusick 		bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
130251667Smckusick 		bcopy((caddr_t)isop, (caddr_t)isoaddr->siso_addr,
130351667Smckusick 			sizeof (struct iso_addr));
130451667Smckusick 		isoaddr->siso_len = sizeof (struct sockaddr_iso);
130551667Smckusick 		isoaddr->siso_family = AF_ISO;
130651667Smckusick 		grp = (struct grouplist *)
130751667Smckusick 			malloc(sizeof(struct grouplist));
130851667Smckusick 		if (grp == NULL)
130951667Smckusick 			goto err1;
131051667Smckusick 		grp->type = MNT_ISO;
131151667Smckusick 		grp->gr_ptr.gt_isoaddr = isoaddr;
131251667Smckusick 		*gp = grp;
131351667Smckusick 		return;
131451667Smckusick #endif	/* ISO */
131551667Smckusick 	} else if ((hp = gethostbyname(cp)) == NULL) {
131651667Smckusick 		syslog(LOG_ERR, "Bad Exports File, %s: %s",
131751667Smckusick 		    cp, "Gethostbyname failed, ignored");
131851667Smckusick 		*gp = NULL;
131951667Smckusick 		return;
132051667Smckusick 	}
132151667Smckusick 	grp = (struct grouplist *)
132251667Smckusick 		malloc(sizeof(struct grouplist));
132351667Smckusick 	if (grp == NULL)
132451667Smckusick 		goto err1;
132551667Smckusick 	grp->type = MNT_HOST;
132651667Smckusick 	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
132751667Smckusick 		malloc(sizeof(struct hostent));
132851667Smckusick 	if (nhp == NULL)
132951667Smckusick 		goto err1;
133051667Smckusick 	bcopy((caddr_t)hp, (caddr_t)nhp,
133151667Smckusick 		sizeof(struct hostent));
133251667Smckusick 	i = strlen(hp->h_name)+1;
133351667Smckusick 	nhp->h_name = (char *)malloc(i);
133451667Smckusick 	if (nhp->h_name == NULL)
133551667Smckusick 		goto err1;
133651667Smckusick 	bcopy(hp->h_name, nhp->h_name, i);
133751667Smckusick 	addrp = hp->h_addr_list;
133851667Smckusick 	i = 1;
133951667Smckusick 	while (*addrp++)
134051667Smckusick 		i++;
134151667Smckusick 	naddrp = nhp->h_addr_list = (char **)
134251667Smckusick 		malloc(i*sizeof(char *));
134351667Smckusick 	if (naddrp == NULL)
134451667Smckusick 		goto err1;
134551667Smckusick 	addrp = hp->h_addr_list;
134651667Smckusick 	while (*addrp) {
134751667Smckusick 		*naddrp = (char *)
134851667Smckusick 		    malloc(hp->h_length);
134951667Smckusick 		if (*naddrp == NULL)
135051667Smckusick 		    goto err1;
135151667Smckusick 		bcopy(*addrp, *naddrp,
135251667Smckusick 			hp->h_length);
135351667Smckusick 		addrp++;
135451667Smckusick 		naddrp++;
135551667Smckusick 	}
135651667Smckusick 	*naddrp = (char *)0;
135751667Smckusick 	*gp = grp;
135851667Smckusick 	return;
135951667Smckusick err1:
136051667Smckusick 	syslog(LOG_ERR, "No more memory: mountd Failed");
136151667Smckusick 	exit(2);
136251667Smckusick }
136351667Smckusick 
136451667Smckusick void
136551667Smckusick do_group(cp, endcp, gp)
136651667Smckusick 	char *cp, *endcp;
136751667Smckusick 	struct grouplist **gp;
136851667Smckusick {
136951667Smckusick 	int found;
137051667Smckusick 	struct groupnames *t_gn;
137151667Smckusick 
137251667Smckusick 	t_gn = grpnames;
137351667Smckusick 	found = FALSE;
137451667Smckusick 	while((t_gn != NULL) && !found) {
137551667Smckusick 		if(strcmp(t_gn->gn_name,cp) == 0) {
137651667Smckusick 			found = TRUE;
137751667Smckusick 			*gp = (struct grouplist *)
137851667Smckusick 			    malloc(sizeof(struct grouplist));
137951667Smckusick 			if (*gp == NULL) {
138051667Smckusick 				syslog(LOG_ERR,"No more memory: mountd Failed");
138151667Smckusick 				exit(2);
138251667Smckusick 			}
138351667Smckusick 			(*gp)->gr_ptr.gt_grpname = (struct groupnames *)
138451667Smckusick 			    malloc(sizeof(struct groupnames));
138551667Smckusick 			if ((*gp)->gr_ptr.gt_grpname == NULL) {
138651667Smckusick 				syslog(LOG_ERR,"No more memory: mountd Failed");
138751667Smckusick 				exit(2);
138851667Smckusick 			}
138951667Smckusick 			(*gp)->gr_ptr.gt_grpname->gn_glist = t_gn->gn_glist;
139051667Smckusick 			return;
139151667Smckusick 		}
139251667Smckusick 		t_gn = t_gn->gn_next;
139351667Smckusick 	}
139451667Smckusick 	*gp = NULL;
139551667Smckusick }
139651667Smckusick 
139751667Smckusick /*
139851667Smckusick  * char *realpath(const char *path, char resolved_path[MAXPATHLEN])
139951667Smckusick  *
140051667Smckusick  * find the real name of path, by removing all ".", ".."
140151667Smckusick  * and symlink components.
140251667Smckusick  *
140351667Smckusick  * Jan-Simon Pendry, September 1991.
140451667Smckusick  */
140551667Smckusick char *
140651667Smckusick realpath(path, resolved)
140751667Smckusick 	char *path;
140851667Smckusick 	char resolved[MAXPATHLEN];
140951667Smckusick {
141051667Smckusick 	int d = open(".", O_RDONLY);
141151667Smckusick 	int rootd = 0;
141251667Smckusick 	char *p, *q;
141351667Smckusick 	struct stat stb;
141451667Smckusick 	char wbuf[MAXPATHLEN];
141551667Smckusick 
141651667Smckusick 	strcpy(resolved, path);
141751667Smckusick 
141851667Smckusick 	if (d < 0)
141951667Smckusick 		return 0;
142051667Smckusick 
142151667Smckusick loop:;
142251667Smckusick 	q = strrchr(resolved, '/');
142351667Smckusick 	if (q) {
142451667Smckusick 		p = q + 1;
142551667Smckusick 		if (q == resolved)
142651667Smckusick 			q = "/";
142751667Smckusick 		else {
142851667Smckusick 			do
142951667Smckusick 				--q;
143051667Smckusick 			while (q > resolved && *q == '/');
143151667Smckusick 			q[1] = '\0';
143251667Smckusick 			q = resolved;
143351667Smckusick 		}
143451667Smckusick 		if (chdir(q) < 0)
143551667Smckusick 			goto out;
143651667Smckusick 	} else
143751667Smckusick 		p = resolved;
143851667Smckusick 
143951667Smckusick 	if (lstat(p, &stb) == 0) {
144051667Smckusick 		if (S_ISLNK(stb.st_mode)) {
144151667Smckusick 			int n = readlink(p, resolved, MAXPATHLEN);
144251667Smckusick 			if (n < 0)
144351667Smckusick 				goto out;
144451667Smckusick 			resolved[n] = '\0';
144551667Smckusick 			goto loop;
144651667Smckusick 		}
144751667Smckusick 		if (S_ISDIR(stb.st_mode)) {
144851667Smckusick 			if (chdir(p) < 0)
144951667Smckusick 				goto out;
145051667Smckusick 			p = "";
145151667Smckusick 		}
145251667Smckusick 	}
145351667Smckusick 
145451667Smckusick 	strcpy(wbuf, p);
145551667Smckusick 	if (getcwd(resolved, MAXPATHLEN) == 0)
145651667Smckusick 		goto out;
145751667Smckusick 	if (resolved[0] == '/' && resolved[1] == '\0')
145851667Smckusick 		rootd = 1;
145951667Smckusick 
146051667Smckusick 	if (*wbuf) {
146151667Smckusick 		if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) {
146251667Smckusick 			errno = ENAMETOOLONG;
146351667Smckusick 			goto out;
146451667Smckusick 		}
146551667Smckusick 		if (rootd == 0)
146651667Smckusick 			strcat(resolved, "/");
146751667Smckusick 		strcat(resolved, wbuf);
146851667Smckusick 	}
146951667Smckusick 
147051667Smckusick 	if (fchdir(d) < 0)
147151667Smckusick 		goto out;
147251667Smckusick 	(void) close(d);
147351667Smckusick 
147451667Smckusick 	return resolved;
147551667Smckusick 
147651667Smckusick out:;
147751667Smckusick 	(void) close(d);
147851667Smckusick 	return 0;
147951667Smckusick }
148051711Smckusick 
148151711Smckusick #ifdef DEBUG
148251711Smckusick void
148351711Smckusick SYSLOG(int pri, const char *fmt, ...)
148451711Smckusick {
148551711Smckusick 	va_list ap;
148651711Smckusick 
148751711Smckusick 	va_start(ap, fmt);
148851711Smckusick 	vfprintf(stderr, fmt, ap);
148951711Smckusick 	va_end(ap);
149051711Smckusick }
149151711Smckusick #endif /* DEBUG */
1492