mountd.c revision 24359
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  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 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright (c) 1989, 1993\n\
40	The Regents of the University of California.  All rights reserved.\n";
41#endif /*not lint*/
42
43#ifndef lint
44/*static char sccsid[] = "@(#)mountd.c	8.15 (Berkeley) 5/1/95"; */
45static const char rcsid[] =
46	"$Id: mountd.c,v 1.15 1997/03/27 20:00:48 guido Exp $";
47#endif /*not lint*/
48
49#include <sys/param.h>
50#include <sys/file.h>
51#include <sys/ioctl.h>
52#include <sys/mount.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#include <sys/syslog.h>
56#include <sys/ucred.h>
57#include <sys/sysctl.h>
58
59#include <rpc/rpc.h>
60#include <rpc/pmap_clnt.h>
61#include <rpc/pmap_prot.h>
62#ifdef ISO
63#include <netiso/iso.h>
64#endif
65#include <nfs/rpcv2.h>
66#include <nfs/nfsproto.h>
67#include <nfs/nfs.h>
68#include <ufs/ufs/ufsmount.h>
69#include <msdosfs/msdosfsmount.h>
70#include <isofs/cd9660/cd9660_mount.h>	/* XXX need isofs in include */
71
72#include <arpa/inet.h>
73
74#include <ctype.h>
75#include <errno.h>
76#include <grp.h>
77#include <netdb.h>
78#include <pwd.h>
79#include <signal.h>
80#include <stdio.h>
81#include <stdlib.h>
82#include <string.h>
83#include <unistd.h>
84#include "pathnames.h"
85
86#ifdef DEBUG
87#include <stdarg.h>
88#endif
89
90/*
91 * Structures for keeping the mount list and export list
92 */
93struct mountlist {
94	struct mountlist *ml_next;
95	char	ml_host[RPCMNT_NAMELEN+1];
96	char	ml_dirp[RPCMNT_PATHLEN+1];
97};
98
99struct dirlist {
100	struct dirlist	*dp_left;
101	struct dirlist	*dp_right;
102	int		dp_flag;
103	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
104	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
105};
106/* dp_flag bits */
107#define	DP_DEFSET	0x1
108#define DP_HOSTSET	0x2
109#define DP_KERB		0x4
110
111struct exportlist {
112	struct exportlist *ex_next;
113	struct dirlist	*ex_dirl;
114	struct dirlist	*ex_defdir;
115	int		ex_flag;
116	fsid_t		ex_fs;
117	char		*ex_fsdir;
118};
119/* ex_flag bits */
120#define	EX_LINKED	0x1
121
122struct netmsk {
123	u_long	nt_net;
124	u_long	nt_mask;
125	char *nt_name;
126};
127
128union grouptypes {
129	struct hostent *gt_hostent;
130	struct netmsk	gt_net;
131#ifdef ISO
132	struct sockaddr_iso *gt_isoaddr;
133#endif
134};
135
136struct grouplist {
137	int gr_type;
138	union grouptypes gr_ptr;
139	struct grouplist *gr_next;
140};
141/* Group types */
142#define	GT_NULL		0x0
143#define	GT_HOST		0x1
144#define	GT_NET		0x2
145#define	GT_ISO		0x4
146#define GT_IGNORE	0x5
147
148struct hostlist {
149	int		 ht_flag;	/* Uses DP_xx bits */
150	struct grouplist *ht_grp;
151	struct hostlist	 *ht_next;
152};
153
154struct fhreturn {
155	int	fhr_flag;
156	int	fhr_vers;
157	nfsfh_t	fhr_fh;
158};
159
160/* Global defs */
161char	*add_expdir __P((struct dirlist **, char *, int));
162void	add_dlist __P((struct dirlist **, struct dirlist *,
163				struct grouplist *, int));
164void	add_mlist __P((char *, char *));
165int	check_dirpath __P((char *));
166int	check_options __P((struct dirlist *));
167int	chk_host __P((struct dirlist *, u_long, int *, int *));
168void	del_mlist __P((char *, char *));
169struct dirlist *dirp_search __P((struct dirlist *, char *));
170int	do_mount __P((struct exportlist *, struct grouplist *, int,
171		struct ucred *, char *, int, struct statfs *));
172int	do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
173				int *, int *, struct ucred *));
174struct	exportlist *ex_search __P((fsid_t *));
175struct	exportlist *get_exp __P((void));
176void	free_dir __P((struct dirlist *));
177void	free_exp __P((struct exportlist *));
178void	free_grp __P((struct grouplist *));
179void	free_host __P((struct hostlist *));
180void	get_exportlist __P((void));
181int	get_host __P((char *, struct grouplist *, struct grouplist *));
182int	get_num __P((char *));
183struct hostlist *get_ht __P((void));
184int	get_line __P((void));
185void	get_mountlist __P((void));
186int	get_net __P((char *, struct netmsk *, int));
187void	getexp_err __P((struct exportlist *, struct grouplist *));
188struct grouplist *get_grp __P((void));
189void	hang_dirp __P((struct dirlist *, struct grouplist *,
190				struct exportlist *, int));
191void	mntsrv __P((struct svc_req *, SVCXPRT *));
192void	nextfield __P((char **, char **));
193void	out_of_mem __P((void));
194void	parsecred __P((char *, struct ucred *));
195int	put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
196int	scan_tree __P((struct dirlist *, u_long));
197void	send_umntall __P((void));
198int	umntall_each __P((caddr_t, struct sockaddr_in *));
199int	xdr_dir __P((XDR *, char *));
200int	xdr_explist __P((XDR *, caddr_t));
201int	xdr_fhs __P((XDR *, caddr_t));
202int	xdr_mlist __P((XDR *, caddr_t));
203
204/* C library */
205int	getnetgrent();
206void	endnetgrent();
207void	setnetgrent();
208
209#ifdef ISO
210struct iso_addr *iso_addr();
211#endif
212
213struct exportlist *exphead;
214struct mountlist *mlhead;
215struct grouplist *grphead;
216char exname[MAXPATHLEN];
217struct ucred def_anon = {
218	1,
219	(uid_t) -2,
220	1,
221	{ (gid_t) -2 }
222};
223int resvport_only = 1;
224int dir_only = 1;
225int opt_flags;
226/* Bits for above */
227#define	OP_MAPROOT	0x01
228#define	OP_MAPALL	0x02
229#define	OP_KERB		0x04
230#define	OP_MASK		0x08
231#define	OP_NET		0x10
232#define	OP_ISO		0x20
233#define	OP_ALLDIRS	0x40
234
235#ifdef DEBUG
236int debug = 1;
237void	SYSLOG __P((int, const char *, ...));
238#define syslog SYSLOG
239#else
240int debug = 0;
241#endif
242
243/*
244 * Mountd server for NFS mount protocol as described in:
245 * NFS: Network File System Protocol Specification, RFC1094, Appendix A
246 * The optional arguments are the exports file name
247 * default: _PATH_EXPORTS
248 * and "-n" to allow nonroot mount.
249 */
250int
251main(argc, argv)
252	int argc;
253	char **argv;
254{
255	SVCXPRT *udptransp, *tcptransp;
256	int c;
257#ifdef __FreeBSD__
258	struct vfsconf vfc;
259	int error;
260	int mib[3];
261
262	error = getvfsbyname("nfs", &vfc);
263	if (error && vfsisloadable("nfs")) {
264		if(vfsload("nfs"))
265			err(1, "vfsload(nfs)");
266		endvfsent();	/* flush cache */
267		error = getvfsbyname("nfs", &vfc);
268	}
269	if (error)
270		errx(1, "NFS support is not available in the running kernel");
271#endif	/* __FreeBSD__ */
272
273	while ((c = getopt(argc, argv, "dnr")) != -1)
274		switch (c) {
275		case 'n':
276			resvport_only = 0;
277			break;
278		case 'r':
279			dir_only = 0;
280			break;
281		case 'd':
282			debug = debug ? 0 : 1;
283			break;
284		default:
285			fprintf(stderr, "Usage: mountd [-d] [-r] [-n] [export_file]\n");
286			exit(1);
287		};
288	argc -= optind;
289	argv += optind;
290	grphead = (struct grouplist *)NULL;
291	exphead = (struct exportlist *)NULL;
292	mlhead = (struct mountlist *)NULL;
293	if (argc == 1) {
294		strncpy(exname, *argv, MAXPATHLEN-1);
295		exname[MAXPATHLEN-1] = '\0';
296	} else
297		strcpy(exname, _PATH_EXPORTS);
298	openlog("mountd", LOG_PID, LOG_DAEMON);
299	if (debug)
300		fprintf(stderr,"Getting export list.\n");
301	get_exportlist();
302	if (debug)
303		fprintf(stderr,"Getting mount list.\n");
304	get_mountlist();
305	if (debug)
306		fprintf(stderr,"Here we go.\n");
307	if (debug == 0) {
308		daemon(0, 0);
309		signal(SIGINT, SIG_IGN);
310		signal(SIGQUIT, SIG_IGN);
311	}
312	signal(SIGHUP, (void (*) __P((int))) get_exportlist);
313	signal(SIGTERM, (void (*) __P((int))) send_umntall);
314	{ FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
315	  if (pidfile != NULL) {
316		fprintf(pidfile, "%d\n", getpid());
317		fclose(pidfile);
318	  }
319	}
320
321	mib[0] = CTL_VFS;
322	mib[1] = MOUNT_NFS;
323	mib[2] = NFS_NFSPRIVPORT;
324	if (sysctl(mib, 3, NULL, NULL,
325	    &resvport_only, sizeof(resvport_only)) != 0) {
326		syslog(LOG_ERR, "sysctl: %m");
327		exit(1);
328	}
329
330	if ((udptransp = svcudp_create(RPC_ANYSOCK)) == NULL ||
331	    (tcptransp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL) {
332		syslog(LOG_ERR, "Can't create socket");
333		exit(1);
334	}
335	pmap_unset(RPCPROG_MNT, 1);
336	pmap_unset(RPCPROG_MNT, 3);
337	if (!svc_register(udptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_UDP) ||
338	    !svc_register(udptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_UDP) ||
339	    !svc_register(tcptransp, RPCPROG_MNT, 1, mntsrv, IPPROTO_TCP) ||
340	    !svc_register(tcptransp, RPCPROG_MNT, 3, mntsrv, IPPROTO_TCP)) {
341		syslog(LOG_ERR, "Can't register mount");
342		exit(1);
343	}
344	svc_run();
345	syslog(LOG_ERR, "Mountd died");
346	exit(1);
347}
348
349/*
350 * The mount rpc service
351 */
352void
353mntsrv(rqstp, transp)
354	struct svc_req *rqstp;
355	SVCXPRT *transp;
356{
357	struct exportlist *ep;
358	struct dirlist *dp;
359	struct fhreturn fhr;
360	struct stat stb;
361	struct statfs fsb;
362	struct hostent *hp;
363	u_long saddr;
364	u_short sport;
365	char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
366	int bad = ENOENT, defset, hostset;
367	sigset_t sighup_mask;
368
369	sigemptyset(&sighup_mask);
370	sigaddset(&sighup_mask, SIGHUP);
371	saddr = transp->xp_raddr.sin_addr.s_addr;
372	sport = ntohs(transp->xp_raddr.sin_port);
373	hp = (struct hostent *)NULL;
374	switch (rqstp->rq_proc) {
375	case NULLPROC:
376		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
377			syslog(LOG_ERR, "Can't send reply");
378		return;
379	case RPCMNT_MOUNT:
380		if (sport >= IPPORT_RESERVED && resvport_only) {
381			svcerr_weakauth(transp);
382			return;
383		}
384		if (!svc_getargs(transp, xdr_dir, rpcpath)) {
385			svcerr_decode(transp);
386			return;
387		}
388
389		/*
390		 * Get the real pathname and make sure it is a directory
391		 * or a regular file if the -r option was specified
392		 * and it exists.
393		 */
394		if (realpath(rpcpath, dirpath) == 0 ||
395		    stat(dirpath, &stb) < 0 ||
396		    (!S_ISDIR(stb.st_mode) &&
397		     (dir_only || !S_ISREG(stb.st_mode))) ||
398		    statfs(dirpath, &fsb) < 0) {
399			chdir("/");	/* Just in case realpath doesn't */
400			if (debug)
401				fprintf(stderr, "stat failed on %s\n", dirpath);
402			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
403				syslog(LOG_ERR, "Can't send reply");
404			return;
405		}
406
407		/* Check in the exports list */
408		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
409		ep = ex_search(&fsb.f_fsid);
410		hostset = defset = 0;
411		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
412		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
413		     chk_host(dp, saddr, &defset, &hostset)) ||
414		     (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
415		      scan_tree(ep->ex_dirl, saddr) == 0))) {
416			if (hostset & DP_HOSTSET)
417				fhr.fhr_flag = hostset;
418			else
419				fhr.fhr_flag = defset;
420			fhr.fhr_vers = rqstp->rq_vers;
421			/* Get the file handle */
422			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
423			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
424				bad = errno;
425				syslog(LOG_ERR, "Can't get fh for %s", dirpath);
426				if (!svc_sendreply(transp, xdr_long,
427				    (caddr_t)&bad))
428					syslog(LOG_ERR, "Can't send reply");
429				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
430				return;
431			}
432			if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&fhr))
433				syslog(LOG_ERR, "Can't send reply");
434			if (hp == NULL)
435				hp = gethostbyaddr((caddr_t)&saddr,
436				    sizeof(saddr), AF_INET);
437			if (hp)
438				add_mlist(hp->h_name, dirpath);
439			else
440				add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
441					dirpath);
442			if (debug)
443				fprintf(stderr,"Mount successfull.\n");
444		} else {
445			bad = EACCES;
446			if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
447				syslog(LOG_ERR, "Can't send reply");
448		}
449		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
450		return;
451	case RPCMNT_DUMP:
452		if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
453			syslog(LOG_ERR, "Can't send reply");
454		return;
455	case RPCMNT_UMOUNT:
456		if (sport >= IPPORT_RESERVED && resvport_only) {
457			svcerr_weakauth(transp);
458			return;
459		}
460		if (!svc_getargs(transp, xdr_dir, dirpath)) {
461			svcerr_decode(transp);
462			return;
463		}
464		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
465			syslog(LOG_ERR, "Can't send reply");
466		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
467		if (hp)
468			del_mlist(hp->h_name, dirpath);
469		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
470		return;
471	case RPCMNT_UMNTALL:
472		if (sport >= IPPORT_RESERVED && resvport_only) {
473			svcerr_weakauth(transp);
474			return;
475		}
476		if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
477			syslog(LOG_ERR, "Can't send reply");
478		hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
479		if (hp)
480			del_mlist(hp->h_name, (char *)NULL);
481		del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
482		return;
483	case RPCMNT_EXPORT:
484		if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
485			syslog(LOG_ERR, "Can't send reply");
486		return;
487	default:
488		svcerr_noproc(transp);
489		return;
490	}
491}
492
493/*
494 * Xdr conversion for a dirpath string
495 */
496int
497xdr_dir(xdrsp, dirp)
498	XDR *xdrsp;
499	char *dirp;
500{
501	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
502}
503
504/*
505 * Xdr routine to generate file handle reply
506 */
507int
508xdr_fhs(xdrsp, cp)
509	XDR *xdrsp;
510	caddr_t cp;
511{
512	register struct fhreturn *fhrp = (struct fhreturn *)cp;
513	u_long ok = 0, len, auth;
514
515	if (!xdr_long(xdrsp, &ok))
516		return (0);
517	switch (fhrp->fhr_vers) {
518	case 1:
519		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
520	case 3:
521		len = NFSX_V3FH;
522		if (!xdr_long(xdrsp, &len))
523			return (0);
524		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
525			return (0);
526		if (fhrp->fhr_flag & DP_KERB)
527			auth = RPCAUTH_KERB4;
528		else
529			auth = RPCAUTH_UNIX;
530		len = 1;
531		if (!xdr_long(xdrsp, &len))
532			return (0);
533		return (xdr_long(xdrsp, &auth));
534	};
535	return (0);
536}
537
538int
539xdr_mlist(xdrsp, cp)
540	XDR *xdrsp;
541	caddr_t cp;
542{
543	struct mountlist *mlp;
544	int true = 1;
545	int false = 0;
546	char *strp;
547
548	mlp = mlhead;
549	while (mlp) {
550		if (!xdr_bool(xdrsp, &true))
551			return (0);
552		strp = &mlp->ml_host[0];
553		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
554			return (0);
555		strp = &mlp->ml_dirp[0];
556		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
557			return (0);
558		mlp = mlp->ml_next;
559	}
560	if (!xdr_bool(xdrsp, &false))
561		return (0);
562	return (1);
563}
564
565/*
566 * Xdr conversion for export list
567 */
568int
569xdr_explist(xdrsp, cp)
570	XDR *xdrsp;
571	caddr_t cp;
572{
573	struct exportlist *ep;
574	int false = 0;
575	int putdef;
576	sigset_t sighup_mask;
577
578	sigemptyset(&sighup_mask);
579	sigaddset(&sighup_mask, SIGHUP);
580	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
581	ep = exphead;
582	while (ep) {
583		putdef = 0;
584		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
585			goto errout;
586		if (ep->ex_defdir && putdef == 0 &&
587			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
588			&putdef))
589			goto errout;
590		ep = ep->ex_next;
591	}
592	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
593	if (!xdr_bool(xdrsp, &false))
594		return (0);
595	return (1);
596errout:
597	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
598	return (0);
599}
600
601/*
602 * Called from xdr_explist() to traverse the tree and export the
603 * directory paths.
604 */
605int
606put_exlist(dp, xdrsp, adp, putdefp)
607	struct dirlist *dp;
608	XDR *xdrsp;
609	struct dirlist *adp;
610	int *putdefp;
611{
612	struct grouplist *grp;
613	struct hostlist *hp;
614	int true = 1;
615	int false = 0;
616	int gotalldir = 0;
617	char *strp;
618
619	if (dp) {
620		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
621			return (1);
622		if (!xdr_bool(xdrsp, &true))
623			return (1);
624		strp = dp->dp_dirp;
625		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
626			return (1);
627		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
628			gotalldir = 1;
629			*putdefp = 1;
630		}
631		if ((dp->dp_flag & DP_DEFSET) == 0 &&
632		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
633			hp = dp->dp_hosts;
634			while (hp) {
635				grp = hp->ht_grp;
636				if (grp->gr_type == GT_HOST) {
637					if (!xdr_bool(xdrsp, &true))
638						return (1);
639					strp = grp->gr_ptr.gt_hostent->h_name;
640					if (!xdr_string(xdrsp, &strp,
641					    RPCMNT_NAMELEN))
642						return (1);
643				} else if (grp->gr_type == GT_NET) {
644					if (!xdr_bool(xdrsp, &true))
645						return (1);
646					strp = grp->gr_ptr.gt_net.nt_name;
647					if (!xdr_string(xdrsp, &strp,
648					    RPCMNT_NAMELEN))
649						return (1);
650				}
651				hp = hp->ht_next;
652				if (gotalldir && hp == (struct hostlist *)NULL) {
653					hp = adp->dp_hosts;
654					gotalldir = 0;
655				}
656			}
657		}
658		if (!xdr_bool(xdrsp, &false))
659			return (1);
660		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
661			return (1);
662	}
663	return (0);
664}
665
666#define LINESIZ	10240
667char line[LINESIZ];
668FILE *exp_file;
669
670/*
671 * Get the export list
672 */
673void
674get_exportlist()
675{
676	struct exportlist *ep, *ep2;
677	struct grouplist *grp, *tgrp;
678	struct exportlist **epp;
679	struct dirlist *dirhead;
680	struct statfs fsb, *fsp;
681	struct hostent *hpe;
682	struct ucred anon;
683	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
684	int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
685
686	/*
687	 * First, get rid of the old list
688	 */
689	ep = exphead;
690	while (ep) {
691		ep2 = ep;
692		ep = ep->ex_next;
693		free_exp(ep2);
694	}
695	exphead = (struct exportlist *)NULL;
696
697	grp = grphead;
698	while (grp) {
699		tgrp = grp;
700		grp = grp->gr_next;
701		free_grp(tgrp);
702	}
703	grphead = (struct grouplist *)NULL;
704
705	/*
706	 * And delete exports that are in the kernel for all local
707	 * file systems.
708	 * XXX: Should know how to handle all local exportable file systems
709	 *      instead of just "ufs".
710	 */
711	num = getmntinfo(&fsp, MNT_NOWAIT);
712	for (i = 0; i < num; i++) {
713		union {
714			struct ufs_args ua;
715			struct iso_args ia;
716			struct mfs_args ma;
717			struct msdosfs_args da;
718		} targs;
719
720		if (!strcmp(fsp->f_fstypename, "mfs") ||
721		    !strcmp(fsp->f_fstypename, "ufs") ||
722		    !strcmp(fsp->f_fstypename, "msdos") ||
723		    !strcmp(fsp->f_fstypename, "cd9660")) {
724			targs.ua.fspec = NULL;
725			targs.ua.export.ex_flags = MNT_DELEXPORT;
726			if (mount(fsp->f_fstypename, fsp->f_mntonname,
727				  fsp->f_flags | MNT_UPDATE,
728				  (caddr_t)&targs) < 0)
729				syslog(LOG_ERR, "Can't delete exports for %s",
730				       fsp->f_mntonname);
731		}
732		fsp++;
733	}
734
735	/*
736	 * Read in the exports file and build the list, calling
737	 * mount() as we go along to push the export rules into the kernel.
738	 */
739	if ((exp_file = fopen(exname, "r")) == NULL) {
740		syslog(LOG_ERR, "Can't open %s", exname);
741		exit(2);
742	}
743	dirhead = (struct dirlist *)NULL;
744	while (get_line()) {
745		if (debug)
746			fprintf(stderr,"Got line %s\n",line);
747		cp = line;
748		nextfield(&cp, &endcp);
749		if (*cp == '#')
750			goto nextline;
751
752		/*
753		 * Set defaults.
754		 */
755		has_host = FALSE;
756		anon = def_anon;
757		exflags = MNT_EXPORTED;
758		got_nondir = 0;
759		opt_flags = 0;
760		ep = (struct exportlist *)NULL;
761
762		/*
763		 * Create new exports list entry
764		 */
765		len = endcp-cp;
766		tgrp = grp = get_grp();
767		while (len > 0) {
768			if (len > RPCMNT_NAMELEN) {
769			    getexp_err(ep, tgrp);
770			    goto nextline;
771			}
772			if (*cp == '-') {
773			    if (ep == (struct exportlist *)NULL) {
774				getexp_err(ep, tgrp);
775				goto nextline;
776			    }
777			    if (debug)
778				fprintf(stderr, "doing opt %s\n", cp);
779			    got_nondir = 1;
780			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
781				&exflags, &anon)) {
782				getexp_err(ep, tgrp);
783				goto nextline;
784			    }
785			} else if (*cp == '/') {
786			    savedc = *endcp;
787			    *endcp = '\0';
788			    if (check_dirpath(cp) &&
789				statfs(cp, &fsb) >= 0) {
790				if (got_nondir) {
791				    syslog(LOG_ERR, "Dirs must be first");
792				    getexp_err(ep, tgrp);
793				    goto nextline;
794				}
795				if (ep) {
796				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
797					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
798					getexp_err(ep, tgrp);
799					goto nextline;
800				    }
801				} else {
802				    /*
803				     * See if this directory is already
804				     * in the list.
805				     */
806				    ep = ex_search(&fsb.f_fsid);
807				    if (ep == (struct exportlist *)NULL) {
808					ep = get_exp();
809					ep->ex_fs = fsb.f_fsid;
810					ep->ex_fsdir = (char *)
811					    malloc(strlen(fsb.f_mntonname) + 1);
812					if (ep->ex_fsdir)
813					    strcpy(ep->ex_fsdir,
814						fsb.f_mntonname);
815					else
816					    out_of_mem();
817					if (debug)
818					  fprintf(stderr,
819					      "Making new ep fs=0x%x,0x%x\n",
820					      fsb.f_fsid.val[0],
821					      fsb.f_fsid.val[1]);
822				    } else if (debug)
823					fprintf(stderr,
824					    "Found ep fs=0x%x,0x%x\n",
825					    fsb.f_fsid.val[0],
826					    fsb.f_fsid.val[1]);
827				}
828
829				/*
830				 * Add dirpath to export mount point.
831				 */
832				dirp = add_expdir(&dirhead, cp, len);
833				dirplen = len;
834			    } else {
835				getexp_err(ep, tgrp);
836				goto nextline;
837			    }
838			    *endcp = savedc;
839			} else {
840			    savedc = *endcp;
841			    *endcp = '\0';
842			    got_nondir = 1;
843			    if (ep == (struct exportlist *)NULL) {
844				getexp_err(ep, tgrp);
845				goto nextline;
846			    }
847
848			    /*
849			     * Get the host or netgroup.
850			     */
851			    setnetgrent(cp);
852			    netgrp = getnetgrent(&hst, &usr, &dom);
853			    do {
854				if (has_host) {
855				    grp->gr_next = get_grp();
856				    grp = grp->gr_next;
857				}
858				if (netgrp) {
859				    if (get_host(hst, grp, tgrp)) {
860					syslog(LOG_ERR, "Bad netgroup %s", cp);
861					getexp_err(ep, tgrp);
862					endnetgrent();
863					goto nextline;
864				    }
865				} else if (get_host(cp, grp, tgrp)) {
866				    getexp_err(ep, tgrp);
867				    goto nextline;
868				}
869				has_host = TRUE;
870			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
871			    endnetgrent();
872			    *endcp = savedc;
873			}
874			cp = endcp;
875			nextfield(&cp, &endcp);
876			len = endcp - cp;
877		}
878		if (check_options(dirhead)) {
879			getexp_err(ep, tgrp);
880			goto nextline;
881		}
882		if (!has_host) {
883			grp->gr_type = GT_HOST;
884			if (debug)
885				fprintf(stderr,"Adding a default entry\n");
886			/* add a default group and make the grp list NULL */
887			hpe = (struct hostent *)malloc(sizeof(struct hostent));
888			if (hpe == (struct hostent *)NULL)
889				out_of_mem();
890			hpe->h_name = strdup("Default");
891			hpe->h_addrtype = AF_INET;
892			hpe->h_length = sizeof (u_long);
893			hpe->h_addr_list = (char **)NULL;
894			grp->gr_ptr.gt_hostent = hpe;
895
896		/*
897		 * Don't allow a network export coincide with a list of
898		 * host(s) on the same line.
899		 */
900		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
901			getexp_err(ep, tgrp);
902			goto nextline;
903		}
904
905		/*
906		 * Loop through hosts, pushing the exports into the kernel.
907		 * After loop, tgrp points to the start of the list and
908		 * grp points to the last entry in the list.
909		 */
910		grp = tgrp;
911		do {
912		    if (do_mount(ep, grp, exflags, &anon, dirp,
913			dirplen, &fsb)) {
914			getexp_err(ep, tgrp);
915			goto nextline;
916		    }
917		} while (grp->gr_next && (grp = grp->gr_next));
918
919		/*
920		 * Success. Update the data structures.
921		 */
922		if (has_host) {
923			hang_dirp(dirhead, tgrp, ep, opt_flags);
924			grp->gr_next = grphead;
925			grphead = tgrp;
926		} else {
927			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
928				opt_flags);
929			free_grp(grp);
930		}
931		dirhead = (struct dirlist *)NULL;
932		if ((ep->ex_flag & EX_LINKED) == 0) {
933			ep2 = exphead;
934			epp = &exphead;
935
936			/*
937			 * Insert in the list in alphabetical order.
938			 */
939			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
940				epp = &ep2->ex_next;
941				ep2 = ep2->ex_next;
942			}
943			if (ep2)
944				ep->ex_next = ep2;
945			*epp = ep;
946			ep->ex_flag |= EX_LINKED;
947		}
948nextline:
949		if (dirhead) {
950			free_dir(dirhead);
951			dirhead = (struct dirlist *)NULL;
952		}
953	}
954	fclose(exp_file);
955}
956
957/*
958 * Allocate an export list element
959 */
960struct exportlist *
961get_exp()
962{
963	struct exportlist *ep;
964
965	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
966	if (ep == (struct exportlist *)NULL)
967		out_of_mem();
968	memset(ep, 0, sizeof(struct exportlist));
969	return (ep);
970}
971
972/*
973 * Allocate a group list element
974 */
975struct grouplist *
976get_grp()
977{
978	struct grouplist *gp;
979
980	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
981	if (gp == (struct grouplist *)NULL)
982		out_of_mem();
983	memset(gp, 0, sizeof(struct grouplist));
984	return (gp);
985}
986
987/*
988 * Clean up upon an error in get_exportlist().
989 */
990void
991getexp_err(ep, grp)
992	struct exportlist *ep;
993	struct grouplist *grp;
994{
995	struct grouplist *tgrp;
996
997	syslog(LOG_ERR, "Bad exports list line %s", line);
998	if (ep && (ep->ex_flag & EX_LINKED) == 0)
999		free_exp(ep);
1000	while (grp) {
1001		tgrp = grp;
1002		grp = grp->gr_next;
1003		free_grp(tgrp);
1004	}
1005}
1006
1007/*
1008 * Search the export list for a matching fs.
1009 */
1010struct exportlist *
1011ex_search(fsid)
1012	fsid_t *fsid;
1013{
1014	struct exportlist *ep;
1015
1016	ep = exphead;
1017	while (ep) {
1018		if (ep->ex_fs.val[0] == fsid->val[0] &&
1019		    ep->ex_fs.val[1] == fsid->val[1])
1020			return (ep);
1021		ep = ep->ex_next;
1022	}
1023	return (ep);
1024}
1025
1026/*
1027 * Add a directory path to the list.
1028 */
1029char *
1030add_expdir(dpp, cp, len)
1031	struct dirlist **dpp;
1032	char *cp;
1033	int len;
1034{
1035	struct dirlist *dp;
1036
1037	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
1038	dp->dp_left = *dpp;
1039	dp->dp_right = (struct dirlist *)NULL;
1040	dp->dp_flag = 0;
1041	dp->dp_hosts = (struct hostlist *)NULL;
1042	strcpy(dp->dp_dirp, cp);
1043	*dpp = dp;
1044	return (dp->dp_dirp);
1045}
1046
1047/*
1048 * Hang the dir list element off the dirpath binary tree as required
1049 * and update the entry for host.
1050 */
1051void
1052hang_dirp(dp, grp, ep, flags)
1053	struct dirlist *dp;
1054	struct grouplist *grp;
1055	struct exportlist *ep;
1056	int flags;
1057{
1058	struct hostlist *hp;
1059	struct dirlist *dp2;
1060
1061	if (flags & OP_ALLDIRS) {
1062		if (ep->ex_defdir)
1063			free((caddr_t)dp);
1064		else
1065			ep->ex_defdir = dp;
1066		if (grp == (struct grouplist *)NULL) {
1067			ep->ex_defdir->dp_flag |= DP_DEFSET;
1068			if (flags & OP_KERB)
1069				ep->ex_defdir->dp_flag |= DP_KERB;
1070		} else while (grp) {
1071			hp = get_ht();
1072			if (flags & OP_KERB)
1073				hp->ht_flag |= DP_KERB;
1074			hp->ht_grp = grp;
1075			hp->ht_next = ep->ex_defdir->dp_hosts;
1076			ep->ex_defdir->dp_hosts = hp;
1077			grp = grp->gr_next;
1078		}
1079	} else {
1080
1081		/*
1082		 * Loop throught the directories adding them to the tree.
1083		 */
1084		while (dp) {
1085			dp2 = dp->dp_left;
1086			add_dlist(&ep->ex_dirl, dp, grp, flags);
1087			dp = dp2;
1088		}
1089	}
1090}
1091
1092/*
1093 * Traverse the binary tree either updating a node that is already there
1094 * for the new directory or adding the new node.
1095 */
1096void
1097add_dlist(dpp, newdp, grp, flags)
1098	struct dirlist **dpp;
1099	struct dirlist *newdp;
1100	struct grouplist *grp;
1101	int flags;
1102{
1103	struct dirlist *dp;
1104	struct hostlist *hp;
1105	int cmp;
1106
1107	dp = *dpp;
1108	if (dp) {
1109		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
1110		if (cmp > 0) {
1111			add_dlist(&dp->dp_left, newdp, grp, flags);
1112			return;
1113		} else if (cmp < 0) {
1114			add_dlist(&dp->dp_right, newdp, grp, flags);
1115			return;
1116		} else
1117			free((caddr_t)newdp);
1118	} else {
1119		dp = newdp;
1120		dp->dp_left = (struct dirlist *)NULL;
1121		*dpp = dp;
1122	}
1123	if (grp) {
1124
1125		/*
1126		 * Hang all of the host(s) off of the directory point.
1127		 */
1128		do {
1129			hp = get_ht();
1130			if (flags & OP_KERB)
1131				hp->ht_flag |= DP_KERB;
1132			hp->ht_grp = grp;
1133			hp->ht_next = dp->dp_hosts;
1134			dp->dp_hosts = hp;
1135			grp = grp->gr_next;
1136		} while (grp);
1137	} else {
1138		dp->dp_flag |= DP_DEFSET;
1139		if (flags & OP_KERB)
1140			dp->dp_flag |= DP_KERB;
1141	}
1142}
1143
1144/*
1145 * Search for a dirpath on the export point.
1146 */
1147struct dirlist *
1148dirp_search(dp, dirpath)
1149	struct dirlist *dp;
1150	char *dirpath;
1151{
1152	int cmp;
1153
1154	if (dp) {
1155		cmp = strcmp(dp->dp_dirp, dirpath);
1156		if (cmp > 0)
1157			return (dirp_search(dp->dp_left, dirpath));
1158		else if (cmp < 0)
1159			return (dirp_search(dp->dp_right, dirpath));
1160		else
1161			return (dp);
1162	}
1163	return (dp);
1164}
1165
1166/*
1167 * Scan for a host match in a directory tree.
1168 */
1169int
1170chk_host(dp, saddr, defsetp, hostsetp)
1171	struct dirlist *dp;
1172	u_long saddr;
1173	int *defsetp;
1174	int *hostsetp;
1175{
1176	struct hostlist *hp;
1177	struct grouplist *grp;
1178	u_long **addrp;
1179
1180	if (dp) {
1181		if (dp->dp_flag & DP_DEFSET)
1182			*defsetp = dp->dp_flag;
1183		hp = dp->dp_hosts;
1184		while (hp) {
1185			grp = hp->ht_grp;
1186			switch (grp->gr_type) {
1187			case GT_HOST:
1188			    addrp = (u_long **)
1189				grp->gr_ptr.gt_hostent->h_addr_list;
1190			    while (*addrp) {
1191				if (**addrp == saddr) {
1192				    *hostsetp = (hp->ht_flag | DP_HOSTSET);
1193				    return (1);
1194				}
1195				addrp++;
1196			    }
1197			    break;
1198			case GT_NET:
1199			    if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
1200				grp->gr_ptr.gt_net.nt_net) {
1201				*hostsetp = (hp->ht_flag | DP_HOSTSET);
1202				return (1);
1203			    }
1204			    break;
1205			};
1206			hp = hp->ht_next;
1207		}
1208	}
1209	return (0);
1210}
1211
1212/*
1213 * Scan tree for a host that matches the address.
1214 */
1215int
1216scan_tree(dp, saddr)
1217	struct dirlist *dp;
1218	u_long saddr;
1219{
1220	int defset, hostset;
1221
1222	if (dp) {
1223		if (scan_tree(dp->dp_left, saddr))
1224			return (1);
1225		if (chk_host(dp, saddr, &defset, &hostset))
1226			return (1);
1227		if (scan_tree(dp->dp_right, saddr))
1228			return (1);
1229	}
1230	return (0);
1231}
1232
1233/*
1234 * Traverse the dirlist tree and free it up.
1235 */
1236void
1237free_dir(dp)
1238	struct dirlist *dp;
1239{
1240
1241	if (dp) {
1242		free_dir(dp->dp_left);
1243		free_dir(dp->dp_right);
1244		free_host(dp->dp_hosts);
1245		free((caddr_t)dp);
1246	}
1247}
1248
1249/*
1250 * Parse the option string and update fields.
1251 * Option arguments may either be -<option>=<value> or
1252 * -<option> <value>
1253 */
1254int
1255do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
1256	char **cpp, **endcpp;
1257	struct exportlist *ep;
1258	struct grouplist *grp;
1259	int *has_hostp;
1260	int *exflagsp;
1261	struct ucred *cr;
1262{
1263	char *cpoptarg, *cpoptend;
1264	char *cp, *endcp, *cpopt, savedc, savedc2;
1265	int allflag, usedarg;
1266
1267	cpopt = *cpp;
1268	cpopt++;
1269	cp = *endcpp;
1270	savedc = *cp;
1271	*cp = '\0';
1272	while (cpopt && *cpopt) {
1273		allflag = 1;
1274		usedarg = -2;
1275		if (cpoptend = strchr(cpopt, ',')) {
1276			*cpoptend++ = '\0';
1277			if (cpoptarg = strchr(cpopt, '='))
1278				*cpoptarg++ = '\0';
1279		} else {
1280			if (cpoptarg = strchr(cpopt, '='))
1281				*cpoptarg++ = '\0';
1282			else {
1283				*cp = savedc;
1284				nextfield(&cp, &endcp);
1285				**endcpp = '\0';
1286				if (endcp > cp && *cp != '-') {
1287					cpoptarg = cp;
1288					savedc2 = *endcp;
1289					*endcp = '\0';
1290					usedarg = 0;
1291				}
1292			}
1293		}
1294		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
1295			*exflagsp |= MNT_EXRDONLY;
1296		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
1297		    !(allflag = strcmp(cpopt, "mapall")) ||
1298		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
1299			usedarg++;
1300			parsecred(cpoptarg, cr);
1301			if (allflag == 0) {
1302				*exflagsp |= MNT_EXPORTANON;
1303				opt_flags |= OP_MAPALL;
1304			} else
1305				opt_flags |= OP_MAPROOT;
1306		} else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
1307			*exflagsp |= MNT_EXKERB;
1308			opt_flags |= OP_KERB;
1309		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
1310			!strcmp(cpopt, "m"))) {
1311			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
1312				syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
1313				return (1);
1314			}
1315			usedarg++;
1316			opt_flags |= OP_MASK;
1317		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
1318			!strcmp(cpopt, "n"))) {
1319			if (grp->gr_type != GT_NULL) {
1320				syslog(LOG_ERR, "Network/host conflict");
1321				return (1);
1322			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
1323				syslog(LOG_ERR, "Bad net: %s", cpoptarg);
1324				return (1);
1325			}
1326			grp->gr_type = GT_NET;
1327			*has_hostp = 1;
1328			usedarg++;
1329			opt_flags |= OP_NET;
1330		} else if (!strcmp(cpopt, "alldirs")) {
1331			opt_flags |= OP_ALLDIRS;
1332#ifdef ISO
1333		} else if (cpoptarg && !strcmp(cpopt, "iso")) {
1334			if (get_isoaddr(cpoptarg, grp)) {
1335				syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
1336				return (1);
1337			}
1338			*has_hostp = 1;
1339			usedarg++;
1340			opt_flags |= OP_ISO;
1341#endif /* ISO */
1342		} else {
1343			syslog(LOG_ERR, "Bad opt %s", cpopt);
1344			return (1);
1345		}
1346		if (usedarg >= 0) {
1347			*endcp = savedc2;
1348			**endcpp = savedc;
1349			if (usedarg > 0) {
1350				*cpp = cp;
1351				*endcpp = endcp;
1352			}
1353			return (0);
1354		}
1355		cpopt = cpoptend;
1356	}
1357	**endcpp = savedc;
1358	return (0);
1359}
1360
1361/*
1362 * Translate a character string to the corresponding list of network
1363 * addresses for a hostname.
1364 */
1365int
1366get_host(cp, grp, tgrp)
1367	char *cp;
1368	struct grouplist *grp;
1369	struct grouplist *tgrp;
1370{
1371	struct grouplist *checkgrp;
1372	struct hostent *hp, *nhp;
1373	char **addrp, **naddrp;
1374	struct hostent t_host;
1375	int i;
1376	u_long saddr;
1377	char *aptr[2];
1378
1379	if (grp->gr_type != GT_NULL)
1380		return (1);
1381	if ((hp = gethostbyname(cp)) == NULL) {
1382		if (isdigit(*cp)) {
1383			saddr = inet_addr(cp);
1384			if (saddr == -1) {
1385 				syslog(LOG_ERR, "Inet_addr failed for %s", cp);
1386				return (1);
1387			}
1388			if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
1389				AF_INET)) == NULL) {
1390				hp = &t_host;
1391				hp->h_name = cp;
1392				hp->h_addrtype = AF_INET;
1393				hp->h_length = sizeof (u_long);
1394				hp->h_addr_list = aptr;
1395				aptr[0] = (char *)&saddr;
1396				aptr[1] = (char *)NULL;
1397			}
1398		} else {
1399 			syslog(LOG_ERR, "Gethostbyname failed for %s", cp);
1400			return (1);
1401		}
1402	}
1403        /*
1404         * Sanity check: make sure we don't already have an entry
1405         * for this host in the grouplist.
1406         */
1407        checkgrp = tgrp;
1408        while (checkgrp) {
1409		if (checkgrp->gr_type == GT_HOST &&
1410                    checkgrp->gr_ptr.gt_hostent != NULL &&
1411                    !strcmp(checkgrp->gr_ptr.gt_hostent->h_name, hp->h_name)) {
1412                        grp->gr_type = GT_IGNORE;
1413			return(0);
1414		}
1415                checkgrp = checkgrp->gr_next;
1416        }
1417
1418	grp->gr_type = GT_HOST;
1419	nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
1420		malloc(sizeof(struct hostent));
1421	if (nhp == (struct hostent *)NULL)
1422		out_of_mem();
1423	memmove(nhp, hp, sizeof(struct hostent));
1424	i = strlen(hp->h_name)+1;
1425	nhp->h_name = (char *)malloc(i);
1426	if (nhp->h_name == (char *)NULL)
1427		out_of_mem();
1428	memmove(nhp->h_name, hp->h_name, i);
1429	addrp = hp->h_addr_list;
1430	i = 1;
1431	while (*addrp++)
1432		i++;
1433	naddrp = nhp->h_addr_list = (char **)
1434		malloc(i*sizeof(char *));
1435	if (naddrp == (char **)NULL)
1436		out_of_mem();
1437	addrp = hp->h_addr_list;
1438	while (*addrp) {
1439		*naddrp = (char *)
1440		    malloc(hp->h_length);
1441		if (*naddrp == (char *)NULL)
1442		    out_of_mem();
1443		memmove(*naddrp, *addrp, hp->h_length);
1444		addrp++;
1445		naddrp++;
1446	}
1447	*naddrp = (char *)NULL;
1448	if (debug)
1449		fprintf(stderr, "got host %s\n", hp->h_name);
1450	return (0);
1451}
1452
1453/*
1454 * Free up an exports list component
1455 */
1456void
1457free_exp(ep)
1458	struct exportlist *ep;
1459{
1460
1461	if (ep->ex_defdir) {
1462		free_host(ep->ex_defdir->dp_hosts);
1463		free((caddr_t)ep->ex_defdir);
1464	}
1465	if (ep->ex_fsdir)
1466		free(ep->ex_fsdir);
1467	free_dir(ep->ex_dirl);
1468	free((caddr_t)ep);
1469}
1470
1471/*
1472 * Free hosts.
1473 */
1474void
1475free_host(hp)
1476	struct hostlist *hp;
1477{
1478	struct hostlist *hp2;
1479
1480	while (hp) {
1481		hp2 = hp;
1482		hp = hp->ht_next;
1483		free((caddr_t)hp2);
1484	}
1485}
1486
1487struct hostlist *
1488get_ht()
1489{
1490	struct hostlist *hp;
1491
1492	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
1493	if (hp == (struct hostlist *)NULL)
1494		out_of_mem();
1495	hp->ht_next = (struct hostlist *)NULL;
1496	hp->ht_flag = 0;
1497	return (hp);
1498}
1499
1500#ifdef ISO
1501/*
1502 * Translate an iso address.
1503 */
1504get_isoaddr(cp, grp)
1505	char *cp;
1506	struct grouplist *grp;
1507{
1508	struct iso_addr *isop;
1509	struct sockaddr_iso *isoaddr;
1510
1511	if (grp->gr_type != GT_NULL)
1512		return (1);
1513	if ((isop = iso_addr(cp)) == NULL) {
1514		syslog(LOG_ERR,
1515		    "iso_addr failed, ignored");
1516		return (1);
1517	}
1518	isoaddr = (struct sockaddr_iso *)
1519	    malloc(sizeof (struct sockaddr_iso));
1520	if (isoaddr == (struct sockaddr_iso *)NULL)
1521		out_of_mem();
1522	memset(isoaddr, 0, sizeof(struct sockaddr_iso));
1523	memmove(&isoaddr->siso_addr, isop, sizeof(struct iso_addr));
1524	isoaddr->siso_len = sizeof(struct sockaddr_iso);
1525	isoaddr->siso_family = AF_ISO;
1526	grp->gr_type = GT_ISO;
1527	grp->gr_ptr.gt_isoaddr = isoaddr;
1528	return (0);
1529}
1530#endif	/* ISO */
1531
1532/*
1533 * Out of memory, fatal
1534 */
1535void
1536out_of_mem()
1537{
1538
1539	syslog(LOG_ERR, "Out of memory");
1540	exit(2);
1541}
1542
1543/*
1544 * Do the mount syscall with the update flag to push the export info into
1545 * the kernel.
1546 */
1547int
1548do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
1549	struct exportlist *ep;
1550	struct grouplist *grp;
1551	int exflags;
1552	struct ucred *anoncrp;
1553	char *dirp;
1554	int dirplen;
1555	struct statfs *fsb;
1556{
1557	char *cp = (char *)NULL;
1558	u_long **addrp;
1559	int done;
1560	char savedc = '\0';
1561	struct sockaddr_in sin, imask;
1562	union {
1563		struct ufs_args ua;
1564		struct iso_args ia;
1565		struct mfs_args ma;
1566#ifdef __NetBSD__
1567		struct msdosfs_args da;
1568#endif
1569	} args;
1570	u_long net;
1571
1572	args.ua.fspec = 0;
1573	args.ua.export.ex_flags = exflags;
1574	args.ua.export.ex_anon = *anoncrp;
1575	memset(&sin, 0, sizeof(sin));
1576	memset(&imask, 0, sizeof(imask));
1577	sin.sin_family = AF_INET;
1578	sin.sin_len = sizeof(sin);
1579	imask.sin_family = AF_INET;
1580	imask.sin_len = sizeof(sin);
1581	if (grp->gr_type == GT_HOST)
1582		addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
1583	else
1584		addrp = (u_long **)NULL;
1585	done = FALSE;
1586	while (!done) {
1587		switch (grp->gr_type) {
1588		case GT_HOST:
1589			if (addrp) {
1590				sin.sin_addr.s_addr = **addrp;
1591				args.ua.export.ex_addrlen = sizeof(sin);
1592			} else
1593				args.ua.export.ex_addrlen = 0;
1594			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1595			args.ua.export.ex_masklen = 0;
1596			break;
1597		case GT_NET:
1598			if (grp->gr_ptr.gt_net.nt_mask)
1599			    imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
1600			else {
1601			    net = ntohl(grp->gr_ptr.gt_net.nt_net);
1602			    if (IN_CLASSA(net))
1603				imask.sin_addr.s_addr = inet_addr("255.0.0.0");
1604			    else if (IN_CLASSB(net))
1605				imask.sin_addr.s_addr =
1606				    inet_addr("255.255.0.0");
1607			    else
1608				imask.sin_addr.s_addr =
1609				    inet_addr("255.255.255.0");
1610			    grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
1611			}
1612			sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
1613			args.ua.export.ex_addr = (struct sockaddr *)&sin;
1614			args.ua.export.ex_addrlen = sizeof (sin);
1615			args.ua.export.ex_mask = (struct sockaddr *)&imask;
1616			args.ua.export.ex_masklen = sizeof (imask);
1617			break;
1618#ifdef ISO
1619		case GT_ISO:
1620			args.ua.export.ex_addr =
1621				(struct sockaddr *)grp->gr_ptr.gt_isoaddr;
1622			args.ua.export.ex_addrlen =
1623				sizeof(struct sockaddr_iso);
1624			args.ua.export.ex_masklen = 0;
1625			break;
1626#endif	/* ISO */
1627		case GT_IGNORE:
1628			return(0);
1629			break;
1630		default:
1631			syslog(LOG_ERR, "Bad grouptype");
1632			if (cp)
1633				*cp = savedc;
1634			return (1);
1635		};
1636
1637		/*
1638		 * XXX:
1639		 * Maybe I should just use the fsb->f_mntonname path instead
1640		 * of looping back up the dirp to the mount point??
1641		 * Also, needs to know how to export all types of local
1642		 * exportable file systems and not just "ufs".
1643		 */
1644		while (mount(fsb->f_fstypename, dirp,
1645		       fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
1646			if (cp)
1647				*cp-- = savedc;
1648			else
1649				cp = dirp + dirplen - 1;
1650			if (errno == EPERM) {
1651				syslog(LOG_ERR,
1652				   "Can't change attributes for %s.\n", dirp);
1653				return (1);
1654			}
1655			if (opt_flags & OP_ALLDIRS) {
1656				syslog(LOG_ERR, "Could not remount %s: %m",
1657					dirp);
1658				return (1);
1659			}
1660			/* back up over the last component */
1661			while (*cp == '/' && cp > dirp)
1662				cp--;
1663			while (*(cp - 1) != '/' && cp > dirp)
1664				cp--;
1665			if (cp == dirp) {
1666				if (debug)
1667					fprintf(stderr,"mnt unsucc\n");
1668				syslog(LOG_ERR, "Can't export %s", dirp);
1669				return (1);
1670			}
1671			savedc = *cp;
1672			*cp = '\0';
1673		}
1674		if (addrp) {
1675			++addrp;
1676			if (*addrp == (u_long *)NULL)
1677				done = TRUE;
1678		} else
1679			done = TRUE;
1680	}
1681	if (cp)
1682		*cp = savedc;
1683	return (0);
1684}
1685
1686/*
1687 * Translate a net address.
1688 */
1689int
1690get_net(cp, net, maskflg)
1691	char *cp;
1692	struct netmsk *net;
1693	int maskflg;
1694{
1695	struct netent *np;
1696	long netaddr;
1697	struct in_addr inetaddr, inetaddr2;
1698	char *name;
1699
1700	if (np = getnetbyname(cp))
1701		inetaddr = inet_makeaddr(np->n_net, 0);
1702	else if (isdigit(*cp)) {
1703		if ((netaddr = inet_network(cp)) == -1)
1704			return (1);
1705		inetaddr = inet_makeaddr(netaddr, 0);
1706		/*
1707		 * Due to arbritrary subnet masks, you don't know how many
1708		 * bits to shift the address to make it into a network,
1709		 * however you do know how to make a network address into
1710		 * a host with host == 0 and then compare them.
1711		 * (What a pest)
1712		 */
1713		if (!maskflg) {
1714			setnetent(0);
1715			while (np = getnetent()) {
1716				inetaddr2 = inet_makeaddr(np->n_net, 0);
1717				if (inetaddr2.s_addr == inetaddr.s_addr)
1718					break;
1719			}
1720			endnetent();
1721		}
1722	} else
1723		return (1);
1724	if (maskflg)
1725		net->nt_mask = inetaddr.s_addr;
1726	else {
1727		if (np)
1728			name = np->n_name;
1729		else
1730			name = inet_ntoa(inetaddr);
1731		net->nt_name = (char *)malloc(strlen(name) + 1);
1732		if (net->nt_name == (char *)NULL)
1733			out_of_mem();
1734		strcpy(net->nt_name, name);
1735		net->nt_net = inetaddr.s_addr;
1736	}
1737	return (0);
1738}
1739
1740/*
1741 * Parse out the next white space separated field
1742 */
1743void
1744nextfield(cp, endcp)
1745	char **cp;
1746	char **endcp;
1747{
1748	char *p;
1749
1750	p = *cp;
1751	while (*p == ' ' || *p == '\t')
1752		p++;
1753	if (*p == '\n' || *p == '\0')
1754		*cp = *endcp = p;
1755	else {
1756		*cp = p++;
1757		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
1758			p++;
1759		*endcp = p;
1760	}
1761}
1762
1763/*
1764 * Get an exports file line. Skip over blank lines and handle line
1765 * continuations.
1766 */
1767int
1768get_line()
1769{
1770	char *p, *cp;
1771	int len;
1772	int totlen, cont_line;
1773
1774	/*
1775	 * Loop around ignoring blank lines and getting all continuation lines.
1776	 */
1777	p = line;
1778	totlen = 0;
1779	do {
1780		if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
1781			return (0);
1782		len = strlen(p);
1783		cp = p + len - 1;
1784		cont_line = 0;
1785		while (cp >= p &&
1786		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
1787			if (*cp == '\\')
1788				cont_line = 1;
1789			cp--;
1790			len--;
1791		}
1792		*++cp = '\0';
1793		if (len > 0) {
1794			totlen += len;
1795			if (totlen >= LINESIZ) {
1796				syslog(LOG_ERR, "Exports line too long");
1797				exit(2);
1798			}
1799			p = cp;
1800		}
1801	} while (totlen == 0 || cont_line);
1802	return (1);
1803}
1804
1805/*
1806 * Parse a description of a credential.
1807 */
1808void
1809parsecred(namelist, cr)
1810	char *namelist;
1811	struct ucred *cr;
1812{
1813	char *name;
1814	int cnt;
1815	char *names;
1816	struct passwd *pw;
1817	struct group *gr;
1818	int ngroups, groups[NGROUPS + 1];
1819
1820	/*
1821	 * Set up the unpriviledged user.
1822	 */
1823	cr->cr_ref = 1;
1824	cr->cr_uid = -2;
1825	cr->cr_groups[0] = -2;
1826	cr->cr_ngroups = 1;
1827	/*
1828	 * Get the user's password table entry.
1829	 */
1830	names = strsep(&namelist, " \t\n");
1831	name = strsep(&names, ":");
1832	if (isdigit(*name) || *name == '-')
1833		pw = getpwuid(atoi(name));
1834	else
1835		pw = getpwnam(name);
1836	/*
1837	 * Credentials specified as those of a user.
1838	 */
1839	if (names == NULL) {
1840		if (pw == NULL) {
1841			syslog(LOG_ERR, "Unknown user: %s", name);
1842			return;
1843		}
1844		cr->cr_uid = pw->pw_uid;
1845		ngroups = NGROUPS + 1;
1846		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
1847			syslog(LOG_ERR, "Too many groups");
1848		/*
1849		 * Convert from int's to gid_t's and compress out duplicate
1850		 */
1851		cr->cr_ngroups = ngroups - 1;
1852		cr->cr_groups[0] = groups[0];
1853		for (cnt = 2; cnt < ngroups; cnt++)
1854			cr->cr_groups[cnt - 1] = groups[cnt];
1855		return;
1856	}
1857	/*
1858	 * Explicit credential specified as a colon separated list:
1859	 *	uid:gid:gid:...
1860	 */
1861	if (pw != NULL)
1862		cr->cr_uid = pw->pw_uid;
1863	else if (isdigit(*name) || *name == '-')
1864		cr->cr_uid = atoi(name);
1865	else {
1866		syslog(LOG_ERR, "Unknown user: %s", name);
1867		return;
1868	}
1869	cr->cr_ngroups = 0;
1870	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
1871		name = strsep(&names, ":");
1872		if (isdigit(*name) || *name == '-') {
1873			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
1874		} else {
1875			if ((gr = getgrnam(name)) == NULL) {
1876				syslog(LOG_ERR, "Unknown group: %s", name);
1877				continue;
1878			}
1879			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
1880		}
1881	}
1882	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
1883		syslog(LOG_ERR, "Too many groups");
1884}
1885
1886#define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
1887/*
1888 * Routines that maintain the remote mounttab
1889 */
1890void
1891get_mountlist()
1892{
1893	struct mountlist *mlp, **mlpp;
1894	char *host, *dirp, *cp;
1895	int len;
1896	char str[STRSIZ];
1897	FILE *mlfile;
1898
1899	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
1900		syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
1901		return;
1902	}
1903	mlpp = &mlhead;
1904	while (fgets(str, STRSIZ, mlfile) != NULL) {
1905		cp = str;
1906		host = strsep(&cp, " \t\n");
1907		dirp = strsep(&cp, " \t\n");
1908		if (host == NULL || dirp == NULL)
1909			continue;
1910		mlp = (struct mountlist *)malloc(sizeof (*mlp));
1911		strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
1912		mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1913		strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1914		mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1915		mlp->ml_next = (struct mountlist *)NULL;
1916		*mlpp = mlp;
1917		mlpp = &mlp->ml_next;
1918	}
1919	fclose(mlfile);
1920}
1921
1922void
1923del_mlist(hostp, dirp)
1924	char *hostp, *dirp;
1925{
1926	struct mountlist *mlp, **mlpp;
1927	struct mountlist *mlp2;
1928	FILE *mlfile;
1929	int fnd = 0;
1930
1931	mlpp = &mlhead;
1932	mlp = mlhead;
1933	while (mlp) {
1934		if (!strcmp(mlp->ml_host, hostp) &&
1935		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
1936			fnd = 1;
1937			mlp2 = mlp;
1938			*mlpp = mlp = mlp->ml_next;
1939			free((caddr_t)mlp2);
1940		} else {
1941			mlpp = &mlp->ml_next;
1942			mlp = mlp->ml_next;
1943		}
1944	}
1945	if (fnd) {
1946		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
1947			syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
1948			return;
1949		}
1950		mlp = mlhead;
1951		while (mlp) {
1952			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1953			mlp = mlp->ml_next;
1954		}
1955		fclose(mlfile);
1956	}
1957}
1958
1959void
1960add_mlist(hostp, dirp)
1961	char *hostp, *dirp;
1962{
1963	struct mountlist *mlp, **mlpp;
1964	FILE *mlfile;
1965
1966	mlpp = &mlhead;
1967	mlp = mlhead;
1968	while (mlp) {
1969		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
1970			return;
1971		mlpp = &mlp->ml_next;
1972		mlp = mlp->ml_next;
1973	}
1974	mlp = (struct mountlist *)malloc(sizeof (*mlp));
1975	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
1976	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
1977	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
1978	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
1979	mlp->ml_next = (struct mountlist *)NULL;
1980	*mlpp = mlp;
1981	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
1982		syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
1983		return;
1984	}
1985	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
1986	fclose(mlfile);
1987}
1988
1989/*
1990 * This function is called via. SIGTERM when the system is going down.
1991 * It sends a broadcast RPCMNT_UMNTALL.
1992 */
1993void
1994send_umntall()
1995{
1996	(void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
1997		xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
1998	exit(0);
1999}
2000
2001int
2002umntall_each(resultsp, raddr)
2003	caddr_t resultsp;
2004	struct sockaddr_in *raddr;
2005{
2006	return (1);
2007}
2008
2009/*
2010 * Free up a group list.
2011 */
2012void
2013free_grp(grp)
2014	struct grouplist *grp;
2015{
2016	char **addrp;
2017
2018	if (grp->gr_type == GT_HOST) {
2019		if (grp->gr_ptr.gt_hostent->h_name) {
2020			addrp = grp->gr_ptr.gt_hostent->h_addr_list;
2021			while (addrp && *addrp)
2022				free(*addrp++);
2023			free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
2024			free(grp->gr_ptr.gt_hostent->h_name);
2025		}
2026		free((caddr_t)grp->gr_ptr.gt_hostent);
2027	} else if (grp->gr_type == GT_NET) {
2028		if (grp->gr_ptr.gt_net.nt_name)
2029			free(grp->gr_ptr.gt_net.nt_name);
2030	}
2031#ifdef ISO
2032	else if (grp->gr_type == GT_ISO)
2033		free((caddr_t)grp->gr_ptr.gt_isoaddr);
2034#endif
2035	free((caddr_t)grp);
2036}
2037
2038#ifdef DEBUG
2039void
2040SYSLOG(int pri, const char *fmt, ...)
2041{
2042	va_list ap;
2043
2044	va_start(ap, fmt);
2045	vfprintf(stderr, fmt, ap);
2046	va_end(ap);
2047}
2048#endif /* DEBUG */
2049
2050/*
2051 * Check options for consistency.
2052 */
2053int
2054check_options(dp)
2055	struct dirlist *dp;
2056{
2057
2058	if (dp == (struct dirlist *)NULL)
2059	    return (1);
2060	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
2061	    (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
2062	    (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
2063	    syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
2064	    return (1);
2065	}
2066	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
2067	    syslog(LOG_ERR, "-mask requires -net");
2068	    return (1);
2069	}
2070	if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
2071	    syslog(LOG_ERR, "-net and -iso mutually exclusive");
2072	    return (1);
2073	}
2074	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
2075	    syslog(LOG_ERR, "-alldir has multiple directories");
2076	    return (1);
2077	}
2078	return (0);
2079}
2080
2081/*
2082 * Check an absolute directory path for any symbolic links. Return true
2083 * if no symbolic links are found.
2084 */
2085int
2086check_dirpath(dirp)
2087	char *dirp;
2088{
2089	char *cp;
2090	int ret = 1;
2091	struct stat sb;
2092
2093	cp = dirp + 1;
2094	while (*cp && ret) {
2095		if (*cp == '/') {
2096			*cp = '\0';
2097			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2098				ret = 0;
2099			*cp = '/';
2100		}
2101		cp++;
2102	}
2103	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
2104		ret = 0;
2105	return (ret);
2106}
2107
2108/*
2109 * Just translate an ascii string to an integer.
2110 */
2111int
2112get_num(cp)
2113	register char *cp;
2114{
2115	register int res = 0;
2116
2117	while (*cp) {
2118		if (*cp < '0' || *cp > '9')
2119			return (-1);
2120		res = res * 10 + (*cp++ - '0');
2121	}
2122	return (res);
2123}
2124