11558Srgrimes/*
21558Srgrimes * Copyright (c) 1989, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 4. Neither the name of the University nor the names of its contributors
171558Srgrimes *    may be used to endorse or promote products derived from this software
181558Srgrimes *    without specific prior written permission.
191558Srgrimes *
201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301558Srgrimes * SUCH DAMAGE.
311558Srgrimes */
321558Srgrimes
331558Srgrimes#ifndef lint
3437663Scharnierstatic const char copyright[] =
351558Srgrimes"@(#) Copyright (c) 1989, 1993\n\
361558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
372999Swollman#endif /*not lint*/
381558Srgrimes
39105267Scharnier#if 0
401558Srgrimes#ifndef lint
4137663Scharnierstatic char sccsid[] = "@(#)mountd.c	8.15 (Berkeley) 5/1/95";
42105267Scharnier#endif /*not lint*/
4337663Scharnier#endif
441558Srgrimes
45105267Scharnier#include <sys/cdefs.h>
46105267Scharnier__FBSDID("$FreeBSD: stable/10/usr.sbin/mountd/mountd.c 333198 2018-05-03 07:28:49Z avg $");
47105267Scharnier
481558Srgrimes#include <sys/param.h>
49192934Srmacklem#include <sys/fcntl.h>
50192934Srmacklem#include <sys/linker.h>
51192934Srmacklem#include <sys/module.h>
521558Srgrimes#include <sys/mount.h>
531558Srgrimes#include <sys/stat.h>
54192934Srmacklem#include <sys/sysctl.h>
551558Srgrimes#include <sys/syslog.h>
561558Srgrimes
571558Srgrimes#include <rpc/rpc.h>
58109363Smbr#include <rpc/rpc_com.h>
591558Srgrimes#include <rpc/pmap_clnt.h>
6074462Salfred#include <rpc/pmap_prot.h>
6174462Salfred#include <rpcsvc/mount.h>
629336Sdfr#include <nfs/nfsproto.h>
63192934Srmacklem#include <nfs/nfssvc.h>
6483653Speter#include <nfsserver/nfs.h>
651558Srgrimes
66192934Srmacklem#include <fs/nfs/nfsport.h>
67192934Srmacklem
681558Srgrimes#include <arpa/inet.h>
691558Srgrimes
701558Srgrimes#include <ctype.h>
7137663Scharnier#include <err.h>
721558Srgrimes#include <errno.h>
731558Srgrimes#include <grp.h>
74149433Spjd#include <libutil.h>
75103949Smike#include <limits.h>
761558Srgrimes#include <netdb.h>
771558Srgrimes#include <pwd.h>
781558Srgrimes#include <signal.h>
791558Srgrimes#include <stdio.h>
801558Srgrimes#include <stdlib.h>
811558Srgrimes#include <string.h>
821558Srgrimes#include <unistd.h>
831558Srgrimes#include "pathnames.h"
84158857Srodrigc#include "mntopts.h"
851558Srgrimes
861558Srgrimes#ifdef DEBUG
871558Srgrimes#include <stdarg.h>
881558Srgrimes#endif
891558Srgrimes
901558Srgrimes/*
911558Srgrimes * Structures for keeping the mount list and export list
921558Srgrimes */
931558Srgrimesstruct mountlist {
941558Srgrimes	struct mountlist *ml_next;
95194880Sdfr	char	ml_host[MNTNAMLEN+1];
96194880Sdfr	char	ml_dirp[MNTPATHLEN+1];
971558Srgrimes};
981558Srgrimes
991558Srgrimesstruct dirlist {
1001558Srgrimes	struct dirlist	*dp_left;
1011558Srgrimes	struct dirlist	*dp_right;
1021558Srgrimes	int		dp_flag;
1031558Srgrimes	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
1041558Srgrimes	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
1051558Srgrimes};
1061558Srgrimes/* dp_flag bits */
1071558Srgrimes#define	DP_DEFSET	0x1
1089336Sdfr#define DP_HOSTSET	0x2
1091558Srgrimes
1101558Srgrimesstruct exportlist {
1111558Srgrimes	struct exportlist *ex_next;
1121558Srgrimes	struct dirlist	*ex_dirl;
1131558Srgrimes	struct dirlist	*ex_defdir;
1141558Srgrimes	int		ex_flag;
1151558Srgrimes	fsid_t		ex_fs;
1161558Srgrimes	char		*ex_fsdir;
11727447Sdfr	char		*ex_indexfile;
118184588Sdfr	int		ex_numsecflavors;
119184588Sdfr	int		ex_secflavors[MAXSECFLAVORS];
120240902Srmacklem	int		ex_defnumsecflavors;
121240902Srmacklem	int		ex_defsecflavors[MAXSECFLAVORS];
1221558Srgrimes};
1231558Srgrimes/* ex_flag bits */
1241558Srgrimes#define	EX_LINKED	0x1
1251558Srgrimes
1261558Srgrimesstruct netmsk {
12774462Salfred	struct sockaddr_storage nt_net;
12875801Siedowse	struct sockaddr_storage nt_mask;
12942144Sdfr	char		*nt_name;
1301558Srgrimes};
1311558Srgrimes
1321558Srgrimesunion grouptypes {
13374462Salfred	struct addrinfo *gt_addrinfo;
1341558Srgrimes	struct netmsk	gt_net;
1351558Srgrimes};
1361558Srgrimes
1371558Srgrimesstruct grouplist {
1381558Srgrimes	int gr_type;
1391558Srgrimes	union grouptypes gr_ptr;
1401558Srgrimes	struct grouplist *gr_next;
141240902Srmacklem	int gr_numsecflavors;
142240902Srmacklem	int gr_secflavors[MAXSECFLAVORS];
1431558Srgrimes};
1441558Srgrimes/* Group types */
1451558Srgrimes#define	GT_NULL		0x0
1461558Srgrimes#define	GT_HOST		0x1
1471558Srgrimes#define	GT_NET		0x2
14875641Siedowse#define	GT_DEFAULT	0x3
1497401Swpaul#define GT_IGNORE	0x5
1501558Srgrimes
1511558Srgrimesstruct hostlist {
1529336Sdfr	int		 ht_flag;	/* Uses DP_xx bits */
1531558Srgrimes	struct grouplist *ht_grp;
1541558Srgrimes	struct hostlist	 *ht_next;
1551558Srgrimes};
1561558Srgrimes
1579336Sdfrstruct fhreturn {
1589336Sdfr	int	fhr_flag;
1599336Sdfr	int	fhr_vers;
1609336Sdfr	nfsfh_t	fhr_fh;
161184588Sdfr	int	fhr_numsecflavors;
162184588Sdfr	int	*fhr_secflavors;
1639336Sdfr};
1649336Sdfr
165222623Srmacklem#define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
166222623Srmacklem
1671558Srgrimes/* Global defs */
16892882Simpchar	*add_expdir(struct dirlist **, char *, int);
16992882Simpvoid	add_dlist(struct dirlist **, struct dirlist *,
170240902Srmacklem				struct grouplist *, int, struct exportlist *);
17192882Simpvoid	add_mlist(char *, char *);
17292882Simpint	check_dirpath(char *);
17392882Simpint	check_options(struct dirlist *);
17475801Siedowseint	checkmask(struct sockaddr *sa);
175240902Srmacklemint	chk_host(struct dirlist *, struct sockaddr *, int *, int *, int *,
176240902Srmacklem				 int **);
177294124Sjpaetzelstatic char	*strsep_quote(char **stringp, const char *delim);
178222623Srmacklemstatic int	create_service(struct netconfig *nconf);
179222623Srmacklemstatic void	complete_service(struct netconfig *nconf, char *port_str);
180222623Srmacklemstatic void	clearout_service(void);
18175635Siedowsevoid	del_mlist(char *hostp, char *dirp);
18292882Simpstruct dirlist *dirp_search(struct dirlist *, char *);
18392882Simpint	do_mount(struct exportlist *, struct grouplist *, int,
18492882Simp		struct xucred *, char *, int, struct statfs *);
18592882Simpint	do_opt(char **, char **, struct exportlist *, struct grouplist *,
18692882Simp				int *, int *, struct xucred *);
18792882Simpstruct	exportlist *ex_search(fsid_t *);
18892882Simpstruct	exportlist *get_exp(void);
18992882Simpvoid	free_dir(struct dirlist *);
19092882Simpvoid	free_exp(struct exportlist *);
19192882Simpvoid	free_grp(struct grouplist *);
19292882Simpvoid	free_host(struct hostlist *);
19392882Simpvoid	get_exportlist(void);
19492882Simpint	get_host(char *, struct grouplist *, struct grouplist *);
19592882Simpstruct hostlist *get_ht(void);
19692882Simpint	get_line(void);
19792882Simpvoid	get_mountlist(void);
19892882Simpint	get_net(char *, struct netmsk *, int);
19992882Simpvoid	getexp_err(struct exportlist *, struct grouplist *);
20092882Simpstruct grouplist *get_grp(void);
20192882Simpvoid	hang_dirp(struct dirlist *, struct grouplist *,
20292882Simp				struct exportlist *, int);
20375754Siedowsevoid	huphandler(int sig);
20475801Siedowseint	makemask(struct sockaddr_storage *ssp, int bitlen);
20592882Simpvoid	mntsrv(struct svc_req *, SVCXPRT *);
20692882Simpvoid	nextfield(char **, char **);
20792882Simpvoid	out_of_mem(void);
20892882Simpvoid	parsecred(char *, struct xucred *);
209216587Scharnierint	parsesec(char *, struct exportlist *);
210100117Salfredint	put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int);
21175801Siedowsevoid	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
21275801Siedowseint	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
21375801Siedowse    struct sockaddr *samask);
21492882Simpint	scan_tree(struct dirlist *, struct sockaddr *);
21592882Simpstatic void usage(void);
21692882Simpint	xdr_dir(XDR *, char *);
21792882Simpint	xdr_explist(XDR *, caddr_t);
218100117Salfredint	xdr_explist_brief(XDR *, caddr_t);
219216587Scharnierint	xdr_explist_common(XDR *, caddr_t, int);
22092882Simpint	xdr_fhs(XDR *, caddr_t);
22192882Simpint	xdr_mlist(XDR *, caddr_t);
22292882Simpvoid	terminate(int);
2231558Srgrimes
2241558Srgrimesstruct exportlist *exphead;
2251558Srgrimesstruct mountlist *mlhead;
2261558Srgrimesstruct grouplist *grphead;
227166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL };
228166440Spjdchar **exnames;
229172827Smatteochar **hosts = NULL;
23072650Sgreenstruct xucred def_anon = {
23191354Sdd	XUCRED_VERSION,
23272650Sgreen	(uid_t)-2,
2331558Srgrimes	1,
23472650Sgreen	{ (gid_t)-2 },
23572650Sgreen	NULL
2361558Srgrimes};
23725087Sdfrint force_v2 = 0;
2389336Sdfrint resvport_only = 1;
239172827Smatteoint nhosts = 0;
2409336Sdfrint dir_only = 1;
241121767Speterint dolog = 0;
24275754Siedowseint got_sighup = 0;
243172827Smatteoint xcreated = 0;
24474462Salfred
245172827Smatteochar *svcport_str = NULL;
246222623Srmacklemstatic int	mallocd_svcport = 0;
247222623Srmacklemstatic int	*sock_fd;
248222623Srmacklemstatic int	sock_fdcnt;
249222623Srmacklemstatic int	sock_fdpos;
250241568Srmacklemstatic int	suspend_nfsd = 0;
251172827Smatteo
2521558Srgrimesint opt_flags;
25374462Salfredstatic int have_v6 = 1;
25474462Salfred
255192934Srmacklemint v4root_phase = 0;
256192934Srmacklemchar v4root_dirpath[PATH_MAX + 1];
257220980Srmacklemint run_v4server = 1;
258192934Srmacklemint has_publicfh = 0;
259192934Srmacklem
260149433Spjdstruct pidfh *pfh = NULL;
26175801Siedowse/* Bits for opt_flags above */
2621558Srgrimes#define	OP_MAPROOT	0x01
2631558Srgrimes#define	OP_MAPALL	0x02
26483653Speter/* 0x4 free */
2651558Srgrimes#define	OP_MASK		0x08
2661558Srgrimes#define	OP_NET		0x10
2671558Srgrimes#define	OP_ALLDIRS	0x40
26875801Siedowse#define	OP_HAVEMASK	0x80	/* A mask was specified or inferred. */
269100336Sjoerg#define	OP_QUIET	0x100
27074462Salfred#define OP_MASKLEN	0x200
271184588Sdfr#define OP_SEC		0x400
2721558Srgrimes
2731558Srgrimes#ifdef DEBUG
2741558Srgrimesint debug = 1;
27592882Simpvoid	SYSLOG(int, const char *, ...) __printflike(2, 3);
2761558Srgrimes#define syslog SYSLOG
2771558Srgrimes#else
2781558Srgrimesint debug = 0;
2791558Srgrimes#endif
2801558Srgrimes
2811558Srgrimes/*
282294124Sjpaetzel * Similar to strsep(), but it allows for quoted strings
283294124Sjpaetzel * and escaped characters.
284294124Sjpaetzel *
285294124Sjpaetzel * It returns the string (or NULL, if *stringp is NULL),
286294124Sjpaetzel * which is a de-quoted version of the string if necessary.
287294124Sjpaetzel *
288294124Sjpaetzel * It modifies *stringp in place.
289294124Sjpaetzel */
290294124Sjpaetzelstatic char *
291294124Sjpaetzelstrsep_quote(char **stringp, const char *delim)
292294124Sjpaetzel{
293294124Sjpaetzel	char *srcptr, *dstptr, *retval;
294294124Sjpaetzel	char quot = 0;
295294124Sjpaetzel
296294124Sjpaetzel	if (stringp == NULL || *stringp == NULL)
297294124Sjpaetzel		return (NULL);
298294124Sjpaetzel
299294124Sjpaetzel	srcptr = dstptr = retval = *stringp;
300294124Sjpaetzel
301294124Sjpaetzel	while (*srcptr) {
302294124Sjpaetzel		/*
303294124Sjpaetzel		 * We're looking for several edge cases here.
304294124Sjpaetzel		 * First:  if we're in quote state (quot != 0),
305294124Sjpaetzel		 * then we ignore the delim characters, but otherwise
306294124Sjpaetzel		 * process as normal, unless it is the quote character.
307294124Sjpaetzel		 * Second:  if the current character is a backslash,
308294124Sjpaetzel		 * we take the next character as-is, without checking
309294124Sjpaetzel		 * for delim, quote, or backslash.  Exception:  if the
310294124Sjpaetzel		 * next character is a NUL, that's the end of the string.
311294124Sjpaetzel		 * Third:  if the character is a quote character, we toggle
312294124Sjpaetzel		 * quote state.
313294124Sjpaetzel		 * Otherwise:  check the current character for NUL, or
314294124Sjpaetzel		 * being in delim, and end the string if either is true.
315294124Sjpaetzel		 */
316294124Sjpaetzel		if (*srcptr == '\\') {
317294124Sjpaetzel			srcptr++;
318294124Sjpaetzel			/*
319294124Sjpaetzel			 * The edge case here is if the next character
320294124Sjpaetzel			 * is NUL, we want to stop processing.  But if
321294124Sjpaetzel			 * it's not NUL, then we simply want to copy it.
322294124Sjpaetzel			 */
323294124Sjpaetzel			if (*srcptr) {
324294124Sjpaetzel				*dstptr++ = *srcptr++;
325294124Sjpaetzel			}
326294124Sjpaetzel			continue;
327294124Sjpaetzel		}
328294124Sjpaetzel		if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) {
329294124Sjpaetzel			quot = *srcptr++;
330294124Sjpaetzel			continue;
331294124Sjpaetzel		}
332294124Sjpaetzel		if (quot && *srcptr == quot) {
333294124Sjpaetzel			/* End of the quoted part */
334294124Sjpaetzel			quot = 0;
335294124Sjpaetzel			srcptr++;
336294124Sjpaetzel			continue;
337294124Sjpaetzel		}
338294124Sjpaetzel		if (!quot && strchr(delim, *srcptr))
339294124Sjpaetzel			break;
340294124Sjpaetzel		*dstptr++ = *srcptr++;
341294124Sjpaetzel	}
342294124Sjpaetzel
343294124Sjpaetzel	*dstptr = 0; /* Terminate the string */
344294124Sjpaetzel	*stringp = (*srcptr == '\0') ? NULL : srcptr + 1;
345294124Sjpaetzel	return (retval);
346294124Sjpaetzel}
347294124Sjpaetzel
348294124Sjpaetzel/*
3491558Srgrimes * Mountd server for NFS mount protocol as described in:
3501558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A
3511558Srgrimes * The optional arguments are the exports file name
3521558Srgrimes * default: _PATH_EXPORTS
3531558Srgrimes * and "-n" to allow nonroot mount.
3541558Srgrimes */
3551558Srgrimesint
356216587Scharniermain(int argc, char **argv)
3571558Srgrimes{
35875754Siedowse	fd_set readfds;
359172827Smatteo	struct netconfig *nconf;
360172827Smatteo	char *endptr, **hosts_bak;
361172827Smatteo	void *nc_handle;
362149433Spjd	pid_t otherpid;
363172827Smatteo	in_port_t svcport;
364172827Smatteo	int c, k, s;
365109363Smbr	int maxrec = RPC_MAXDATASIZE;
366222623Srmacklem	int attempt_cnt, port_len, port_pos, ret;
367222623Srmacklem	char **port_list;
3681558Srgrimes
36974462Salfred	/* Check that another mountd isn't already running. */
370150214Spjd	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
371149433Spjd	if (pfh == NULL) {
372149433Spjd		if (errno == EEXIST)
373149433Spjd			errx(1, "mountd already running, pid: %d.", otherpid);
374149433Spjd		warn("cannot open or create pidfile");
375149433Spjd	}
37674462Salfred
37774462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
37874462Salfred	if (s < 0)
37974462Salfred		have_v6 = 0;
38074462Salfred	else
38174462Salfred		close(s);
3822999Swollman
383241568Srmacklem	while ((c = getopt(argc, argv, "2deh:lnop:rS")) != -1)
3841558Srgrimes		switch (c) {
38525087Sdfr		case '2':
38625087Sdfr			force_v2 = 1;
38725087Sdfr			break;
388192993Srmacklem		case 'e':
389220980Srmacklem			/* now a no-op, since this is the default */
390192934Srmacklem			break;
3919336Sdfr		case 'n':
3929336Sdfr			resvport_only = 0;
3939336Sdfr			break;
3949336Sdfr		case 'r':
3959336Sdfr			dir_only = 0;
3969336Sdfr			break;
3978688Sphk		case 'd':
3988688Sphk			debug = debug ? 0 : 1;
3998688Sphk			break;
40031656Sguido		case 'l':
401121767Speter			dolog = 1;
40231656Sguido			break;
403220980Srmacklem		case 'o':
404220980Srmacklem			run_v4server = 0;
405220980Srmacklem			break;
406126572Sbms		case 'p':
407126572Sbms			endptr = NULL;
408126572Sbms			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
409126572Sbms			if (endptr == NULL || *endptr != '\0' ||
410126572Sbms			    svcport == 0 || svcport >= IPPORT_MAX)
411126572Sbms				usage();
412172827Smatteo			svcport_str = strdup(optarg);
413126572Sbms			break;
414172827Smatteo		case 'h':
415172827Smatteo			++nhosts;
416172827Smatteo			hosts_bak = hosts;
417172827Smatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
418172827Smatteo			if (hosts_bak == NULL) {
419172827Smatteo				if (hosts != NULL) {
420172827Smatteo					for (k = 0; k < nhosts; k++)
421172827Smatteo						free(hosts[k]);
422172827Smatteo					free(hosts);
423172827Smatteo					out_of_mem();
424172827Smatteo				}
425172827Smatteo			}
426172827Smatteo			hosts = hosts_bak;
427172827Smatteo			hosts[nhosts - 1] = strdup(optarg);
428172827Smatteo			if (hosts[nhosts - 1] == NULL) {
429172827Smatteo				for (k = 0; k < (nhosts - 1); k++)
430172827Smatteo					free(hosts[k]);
431172827Smatteo				free(hosts);
432172827Smatteo				out_of_mem();
433172827Smatteo			}
434172827Smatteo			break;
435241568Srmacklem		case 'S':
436241568Srmacklem			suspend_nfsd = 1;
437241568Srmacklem			break;
4381558Srgrimes		default:
43937663Scharnier			usage();
4401558Srgrimes		};
441192934Srmacklem
442192934Srmacklem	/*
443220980Srmacklem	 * Unless the "-o" option was specified, try and run "nfsd".
444220980Srmacklem	 * If "-o" was specified, try and run "nfsserver".
445192934Srmacklem	 */
446192934Srmacklem	if (run_v4server > 0) {
447192934Srmacklem		if (modfind("nfsd") < 0) {
448192934Srmacklem			/* Not present in kernel, try loading it */
449192934Srmacklem			if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
450192934Srmacklem				errx(1, "NFS server is not available");
451192934Srmacklem		}
452192934Srmacklem	} else if (modfind("nfsserver") < 0) {
453192934Srmacklem		/* Not present in kernel, try loading it */
454192934Srmacklem		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
455192934Srmacklem			errx(1, "NFS server is not available");
456192934Srmacklem	}
457192934Srmacklem
4581558Srgrimes	argc -= optind;
4591558Srgrimes	argv += optind;
4601558Srgrimes	grphead = (struct grouplist *)NULL;
4611558Srgrimes	exphead = (struct exportlist *)NULL;
4621558Srgrimes	mlhead = (struct mountlist *)NULL;
463166440Spjd	if (argc > 0)
464166440Spjd		exnames = argv;
465166440Spjd	else
466166440Spjd		exnames = exnames_default;
4671558Srgrimes	openlog("mountd", LOG_PID, LOG_DAEMON);
4681558Srgrimes	if (debug)
46937663Scharnier		warnx("getting export list");
4701558Srgrimes	get_exportlist();
4711558Srgrimes	if (debug)
47237663Scharnier		warnx("getting mount list");
4731558Srgrimes	get_mountlist();
4741558Srgrimes	if (debug)
47537663Scharnier		warnx("here we go");
4761558Srgrimes	if (debug == 0) {
4771558Srgrimes		daemon(0, 0);
4781558Srgrimes		signal(SIGINT, SIG_IGN);
4791558Srgrimes		signal(SIGQUIT, SIG_IGN);
4801558Srgrimes	}
48175754Siedowse	signal(SIGHUP, huphandler);
48274462Salfred	signal(SIGTERM, terminate);
483164394Srodrigc	signal(SIGPIPE, SIG_IGN);
484149433Spjd
485149433Spjd	pidfile_write(pfh);
486149433Spjd
487194880Sdfr	rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
488194880Sdfr	rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
489109363Smbr	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
490109363Smbr
49124759Sguido	if (!resvport_only) {
492308452Srmacklem		if (run_v4server != 0) {
493308452Srmacklem			if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL,
494308452Srmacklem			    &resvport_only, sizeof(resvport_only)) != 0 &&
495308452Srmacklem			    errno != ENOENT) {
496308452Srmacklem				syslog(LOG_ERR, "sysctl: %m");
497308452Srmacklem				exit(1);
498308452Srmacklem			}
499308452Srmacklem		} else {
500308452Srmacklem			if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL,
501308452Srmacklem			    &resvport_only, sizeof(resvport_only)) != 0 &&
502308452Srmacklem			    errno != ENOENT) {
503308452Srmacklem				syslog(LOG_ERR, "sysctl: %m");
504308452Srmacklem				exit(1);
505308452Srmacklem			}
50624759Sguido		}
50724330Sguido	}
508126572Sbms
509172827Smatteo	/*
510172827Smatteo	 * If no hosts were specified, add a wildcard entry to bind to
511172827Smatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
512172827Smatteo	 * list.
513172827Smatteo	 */
514172827Smatteo	if (nhosts == 0) {
515172827Smatteo		hosts = malloc(sizeof(char**));
516172827Smatteo		if (hosts == NULL)
517172827Smatteo			out_of_mem();
518172827Smatteo		hosts[0] = "*";
519172827Smatteo		nhosts = 1;
520172827Smatteo	} else {
521172827Smatteo		hosts_bak = hosts;
522172827Smatteo		if (have_v6) {
523172827Smatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
524172827Smatteo			    sizeof(char *));
525172827Smatteo			if (hosts_bak == NULL) {
526172827Smatteo				for (k = 0; k < nhosts; k++)
527172827Smatteo					free(hosts[k]);
528172827Smatteo		    		free(hosts);
529172827Smatteo		    		out_of_mem();
530172827Smatteo			} else
531172827Smatteo				hosts = hosts_bak;
532172827Smatteo			nhosts += 2;
533172827Smatteo			hosts[nhosts - 2] = "::1";
534172827Smatteo		} else {
535172827Smatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
536172827Smatteo			if (hosts_bak == NULL) {
537172827Smatteo				for (k = 0; k < nhosts; k++)
538172827Smatteo					free(hosts[k]);
539172827Smatteo				free(hosts);
540172827Smatteo				out_of_mem();
541172827Smatteo			} else {
542172827Smatteo				nhosts += 1;
543172827Smatteo				hosts = hosts_bak;
544126572Sbms			}
545172827Smatteo		}
54674462Salfred
547172827Smatteo		hosts[nhosts - 1] = "127.0.0.1";
54874462Salfred	}
54974462Salfred
550222623Srmacklem	attempt_cnt = 1;
551222623Srmacklem	sock_fdcnt = 0;
552222623Srmacklem	sock_fd = NULL;
553222623Srmacklem	port_list = NULL;
554222623Srmacklem	port_len = 0;
555172827Smatteo	nc_handle = setnetconfig();
556172827Smatteo	while ((nconf = getnetconfig(nc_handle))) {
557172827Smatteo		if (nconf->nc_flag & NC_VISIBLE) {
558172827Smatteo			if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
559172827Smatteo			    "inet6") == 0) {
560172827Smatteo				/* DO NOTHING */
561222623Srmacklem			} else {
562222623Srmacklem				ret = create_service(nconf);
563222623Srmacklem				if (ret == 1)
564222623Srmacklem					/* Ignore this call */
565222623Srmacklem					continue;
566222623Srmacklem				if (ret < 0) {
567222623Srmacklem					/*
568222623Srmacklem					 * Failed to bind port, so close off
569222623Srmacklem					 * all sockets created and try again
570222623Srmacklem					 * if the port# was dynamically
571222623Srmacklem					 * assigned via bind(2).
572222623Srmacklem					 */
573222623Srmacklem					clearout_service();
574222623Srmacklem					if (mallocd_svcport != 0 &&
575222623Srmacklem					    attempt_cnt < GETPORT_MAXTRY) {
576222623Srmacklem						free(svcport_str);
577222623Srmacklem						svcport_str = NULL;
578222623Srmacklem						mallocd_svcport = 0;
579222623Srmacklem					} else {
580222623Srmacklem						errno = EADDRINUSE;
581222623Srmacklem						syslog(LOG_ERR,
582222623Srmacklem						    "bindresvport_sa: %m");
583222623Srmacklem						exit(1);
584222623Srmacklem					}
585222623Srmacklem
586222623Srmacklem					/* Start over at the first service. */
587222623Srmacklem					free(sock_fd);
588222623Srmacklem					sock_fdcnt = 0;
589222623Srmacklem					sock_fd = NULL;
590222623Srmacklem					nc_handle = setnetconfig();
591222623Srmacklem					attempt_cnt++;
592222623Srmacklem				} else if (mallocd_svcport != 0 &&
593222623Srmacklem				    attempt_cnt == GETPORT_MAXTRY) {
594222623Srmacklem					/*
595222623Srmacklem					 * For the last attempt, allow
596222623Srmacklem					 * different port #s for each nconf
597222623Srmacklem					 * by saving the svcport_str and
598222623Srmacklem					 * setting it back to NULL.
599222623Srmacklem					 */
600222623Srmacklem					port_list = realloc(port_list,
601222623Srmacklem					    (port_len + 1) * sizeof(char *));
602222623Srmacklem					if (port_list == NULL)
603222623Srmacklem						out_of_mem();
604222623Srmacklem					port_list[port_len++] = svcport_str;
605222623Srmacklem					svcport_str = NULL;
606222623Srmacklem					mallocd_svcport = 0;
607222623Srmacklem				}
608222623Srmacklem			}
609222623Srmacklem		}
610222623Srmacklem	}
611222623Srmacklem
612222623Srmacklem	/*
613222623Srmacklem	 * Successfully bound the ports, so call complete_service() to
614222623Srmacklem	 * do the rest of the setup on the service(s).
615222623Srmacklem	 */
616222623Srmacklem	sock_fdpos = 0;
617222623Srmacklem	port_pos = 0;
618222623Srmacklem	nc_handle = setnetconfig();
619222623Srmacklem	while ((nconf = getnetconfig(nc_handle))) {
620222623Srmacklem		if (nconf->nc_flag & NC_VISIBLE) {
621222623Srmacklem			if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
622222623Srmacklem			    "inet6") == 0) {
623222623Srmacklem				/* DO NOTHING */
624222623Srmacklem			} else if (port_list != NULL) {
625222623Srmacklem				if (port_pos >= port_len) {
626222623Srmacklem					syslog(LOG_ERR, "too many port#s");
627222623Srmacklem					exit(1);
628222623Srmacklem				}
629222623Srmacklem				complete_service(nconf, port_list[port_pos++]);
630172827Smatteo			} else
631222623Srmacklem				complete_service(nconf, svcport_str);
632172827Smatteo		}
63374462Salfred	}
634172827Smatteo	endnetconfig(nc_handle);
635222623Srmacklem	free(sock_fd);
636222623Srmacklem	if (port_list != NULL) {
637222623Srmacklem		for (port_pos = 0; port_pos < port_len; port_pos++)
638222623Srmacklem			free(port_list[port_pos]);
639222623Srmacklem		free(port_list);
640222623Srmacklem	}
64174462Salfred
64274462Salfred	if (xcreated == 0) {
64374462Salfred		syslog(LOG_ERR, "could not create any services");
6441558Srgrimes		exit(1);
6451558Srgrimes	}
64675754Siedowse
64775754Siedowse	/* Expand svc_run() here so that we can call get_exportlist(). */
64875754Siedowse	for (;;) {
64975754Siedowse		if (got_sighup) {
65075754Siedowse			get_exportlist();
65175754Siedowse			got_sighup = 0;
65275754Siedowse		}
65375754Siedowse		readfds = svc_fdset;
65475754Siedowse		switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) {
65575754Siedowse		case -1:
65675754Siedowse			if (errno == EINTR)
65775754Siedowse                                continue;
65875754Siedowse			syslog(LOG_ERR, "mountd died: select: %m");
65975754Siedowse			exit(1);
66075754Siedowse		case 0:
66175754Siedowse			continue;
66275754Siedowse		default:
66375754Siedowse			svc_getreqset(&readfds);
66475754Siedowse		}
66575754Siedowse	}
666172827Smatteo}
667172827Smatteo
668172827Smatteo/*
669172827Smatteo * This routine creates and binds sockets on the appropriate
670222623Srmacklem * addresses. It gets called one time for each transport.
671222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate
672222623Srmacklem * bind failed with EADDRINUSE.
673222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and
674222623Srmacklem * the total count of them is maintained in sock_fdcnt.
675172827Smatteo */
676222623Srmacklemstatic int
677172827Smatteocreate_service(struct netconfig *nconf)
678172827Smatteo{
679172827Smatteo	struct addrinfo hints, *res = NULL;
680172827Smatteo	struct sockaddr_in *sin;
681172827Smatteo	struct sockaddr_in6 *sin6;
682172827Smatteo	struct __rpc_sockinfo si;
683172827Smatteo	int aicode;
684172827Smatteo	int fd;
685172827Smatteo	int nhostsbak;
686172827Smatteo	int one = 1;
687172827Smatteo	int r;
688172827Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
689222623Srmacklem	int mallocd_res;
690172827Smatteo
691172827Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
692172827Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
693172827Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
694222623Srmacklem		return (1);	/* not my type */
695172827Smatteo
696172827Smatteo	/*
697172827Smatteo	 * XXX - using RPC library internal functions.
698172827Smatteo	 */
699172827Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
700172827Smatteo		syslog(LOG_ERR, "cannot get information for %s",
701172827Smatteo		    nconf->nc_netid);
702222623Srmacklem		return (1);
703172827Smatteo	}
704172827Smatteo
705172827Smatteo	/* Get mountd's address on this transport */
706172827Smatteo	memset(&hints, 0, sizeof hints);
707172827Smatteo	hints.ai_family = si.si_af;
708172827Smatteo	hints.ai_socktype = si.si_socktype;
709172827Smatteo	hints.ai_protocol = si.si_proto;
710172827Smatteo
711172827Smatteo	/*
712172827Smatteo	 * Bind to specific IPs if asked to
713172827Smatteo	 */
714172827Smatteo	nhostsbak = nhosts;
715172827Smatteo	while (nhostsbak > 0) {
716172827Smatteo		--nhostsbak;
717222623Srmacklem		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
718222623Srmacklem		if (sock_fd == NULL)
719222623Srmacklem			out_of_mem();
720222623Srmacklem		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
721222623Srmacklem		mallocd_res = 0;
722222623Srmacklem
723277859Srstone		hints.ai_flags = AI_PASSIVE;
724277859Srstone
725172827Smatteo		/*
726172827Smatteo		 * XXX - using RPC library internal functions.
727172827Smatteo		 */
728172827Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
729172827Smatteo			int non_fatal = 0;
730244538Skevlo	    		if (errno == EAFNOSUPPORT &&
731172827Smatteo			    nconf->nc_semantics != NC_TPI_CLTS)
732172827Smatteo				non_fatal = 1;
733172827Smatteo
734172827Smatteo			syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
735172827Smatteo			    "cannot create socket for %s", nconf->nc_netid);
736222623Srmacklem			if (non_fatal != 0)
737222623Srmacklem				continue;
738222623Srmacklem			exit(1);
739172827Smatteo		}
740172827Smatteo
741172827Smatteo		switch (hints.ai_family) {
742172827Smatteo		case AF_INET:
743172827Smatteo			if (inet_pton(AF_INET, hosts[nhostsbak],
744172827Smatteo			    host_addr) == 1) {
745222623Srmacklem				hints.ai_flags |= AI_NUMERICHOST;
746172827Smatteo			} else {
747172827Smatteo				/*
748172827Smatteo				 * Skip if we have an AF_INET6 address.
749172827Smatteo				 */
750172827Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
751172827Smatteo				    host_addr) == 1) {
752172827Smatteo					close(fd);
753172827Smatteo					continue;
754172827Smatteo				}
755172827Smatteo			}
756172827Smatteo			break;
757172827Smatteo		case AF_INET6:
758172827Smatteo			if (inet_pton(AF_INET6, hosts[nhostsbak],
759172827Smatteo			    host_addr) == 1) {
760222623Srmacklem				hints.ai_flags |= AI_NUMERICHOST;
761172827Smatteo			} else {
762172827Smatteo				/*
763172827Smatteo				 * Skip if we have an AF_INET address.
764172827Smatteo				 */
765172827Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
766172827Smatteo				    host_addr) == 1) {
767172827Smatteo					close(fd);
768172827Smatteo					continue;
769172827Smatteo				}
770172827Smatteo			}
771172827Smatteo
772172827Smatteo			/*
773172827Smatteo			 * We're doing host-based access checks here, so don't
774172827Smatteo			 * allow v4-in-v6 to confuse things. The kernel will
775172827Smatteo			 * disable it by default on NFS sockets too.
776172827Smatteo			 */
777172827Smatteo			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
778172827Smatteo			    sizeof one) < 0) {
779172827Smatteo				syslog(LOG_ERR,
780172827Smatteo				    "can't disable v4-in-v6 on IPv6 socket");
781172827Smatteo				exit(1);
782172827Smatteo			}
783172827Smatteo			break;
784172827Smatteo		default:
785172827Smatteo			break;
786172827Smatteo		}
787172827Smatteo
788172827Smatteo		/*
789172827Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
790172827Smatteo		 */
791172827Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
792172827Smatteo			if (svcport_str == NULL) {
793172827Smatteo				res = malloc(sizeof(struct addrinfo));
794172827Smatteo				if (res == NULL)
795172827Smatteo					out_of_mem();
796222623Srmacklem				mallocd_res = 1;
797172827Smatteo				res->ai_flags = hints.ai_flags;
798172827Smatteo				res->ai_family = hints.ai_family;
799172827Smatteo				res->ai_protocol = hints.ai_protocol;
800172827Smatteo				switch (res->ai_family) {
801172827Smatteo				case AF_INET:
802172827Smatteo					sin = malloc(sizeof(struct sockaddr_in));
803172827Smatteo					if (sin == NULL)
804172827Smatteo						out_of_mem();
805172827Smatteo					sin->sin_family = AF_INET;
806172827Smatteo					sin->sin_port = htons(0);
807172827Smatteo					sin->sin_addr.s_addr = htonl(INADDR_ANY);
808172827Smatteo					res->ai_addr = (struct sockaddr*) sin;
809172827Smatteo					res->ai_addrlen = (socklen_t)
810222623Srmacklem					    sizeof(struct sockaddr_in);
811172827Smatteo					break;
812172827Smatteo				case AF_INET6:
813172827Smatteo					sin6 = malloc(sizeof(struct sockaddr_in6));
814173056Ssimon					if (sin6 == NULL)
815172827Smatteo						out_of_mem();
816172827Smatteo					sin6->sin6_family = AF_INET6;
817172827Smatteo					sin6->sin6_port = htons(0);
818172827Smatteo					sin6->sin6_addr = in6addr_any;
819172827Smatteo					res->ai_addr = (struct sockaddr*) sin6;
820172827Smatteo					res->ai_addrlen = (socklen_t)
821222623Srmacklem					    sizeof(struct sockaddr_in6);
822222623Srmacklem					break;
823172827Smatteo				default:
824222623Srmacklem					syslog(LOG_ERR, "bad addr fam %d",
825222623Srmacklem					    res->ai_family);
826222623Srmacklem					exit(1);
827172827Smatteo				}
828172827Smatteo			} else {
829172827Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
830172827Smatteo				    &hints, &res)) != 0) {
831172827Smatteo					syslog(LOG_ERR,
832172827Smatteo					    "cannot get local address for %s: %s",
833172827Smatteo					    nconf->nc_netid,
834172827Smatteo					    gai_strerror(aicode));
835222623Srmacklem					close(fd);
836172827Smatteo					continue;
837172827Smatteo				}
838172827Smatteo			}
839172827Smatteo		} else {
840172827Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
841172827Smatteo			    &hints, &res)) != 0) {
842172827Smatteo				syslog(LOG_ERR,
843172827Smatteo				    "cannot get local address for %s: %s",
844172827Smatteo				    nconf->nc_netid, gai_strerror(aicode));
845222623Srmacklem				close(fd);
846172827Smatteo				continue;
847172827Smatteo			}
848172827Smatteo		}
849172827Smatteo
850222623Srmacklem		/* Store the fd. */
851222623Srmacklem		sock_fd[sock_fdcnt - 1] = fd;
852222623Srmacklem
853222623Srmacklem		/* Now, attempt the bind. */
854172827Smatteo		r = bindresvport_sa(fd, res->ai_addr);
855172827Smatteo		if (r != 0) {
856222623Srmacklem			if (errno == EADDRINUSE && mallocd_svcport != 0) {
857222623Srmacklem				if (mallocd_res != 0) {
858222623Srmacklem					free(res->ai_addr);
859222623Srmacklem					free(res);
860222623Srmacklem				} else
861222623Srmacklem					freeaddrinfo(res);
862222623Srmacklem				return (-1);
863222623Srmacklem			}
864172827Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
865172827Smatteo			exit(1);
866172827Smatteo		}
867172827Smatteo
868222623Srmacklem		if (svcport_str == NULL) {
869222623Srmacklem			svcport_str = malloc(NI_MAXSERV * sizeof(char));
870222623Srmacklem			if (svcport_str == NULL)
871222623Srmacklem				out_of_mem();
872222623Srmacklem			mallocd_svcport = 1;
873222623Srmacklem
874222623Srmacklem			if (getnameinfo(res->ai_addr,
875222623Srmacklem			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
876222623Srmacklem			    svcport_str, NI_MAXSERV * sizeof(char),
877222623Srmacklem			    NI_NUMERICHOST | NI_NUMERICSERV))
878222623Srmacklem				errx(1, "Cannot get port number");
879222623Srmacklem		}
880222623Srmacklem		if (mallocd_res != 0) {
881222623Srmacklem			free(res->ai_addr);
882222623Srmacklem			free(res);
883222623Srmacklem		} else
884222623Srmacklem			freeaddrinfo(res);
885222623Srmacklem		res = NULL;
886222623Srmacklem	}
887222623Srmacklem	return (0);
888222623Srmacklem}
889222623Srmacklem
890222623Srmacklem/*
891222623Srmacklem * Called after all the create_service() calls have succeeded, to complete
892222623Srmacklem * the setup and registration.
893222623Srmacklem */
894222623Srmacklemstatic void
895222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str)
896222623Srmacklem{
897222623Srmacklem	struct addrinfo hints, *res = NULL;
898222623Srmacklem	struct __rpc_sockinfo si;
899222623Srmacklem	struct netbuf servaddr;
900222623Srmacklem	SVCXPRT	*transp = NULL;
901222623Srmacklem	int aicode, fd, nhostsbak;
902222623Srmacklem	int registered = 0;
903222623Srmacklem
904222623Srmacklem	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
905222623Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS) &&
906222623Srmacklem	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
907222623Srmacklem		return;	/* not my type */
908222623Srmacklem
909222623Srmacklem	/*
910222623Srmacklem	 * XXX - using RPC library internal functions.
911222623Srmacklem	 */
912222623Srmacklem	if (!__rpc_nconf2sockinfo(nconf, &si)) {
913222623Srmacklem		syslog(LOG_ERR, "cannot get information for %s",
914222623Srmacklem		    nconf->nc_netid);
915222623Srmacklem		return;
916222623Srmacklem	}
917222623Srmacklem
918222623Srmacklem	nhostsbak = nhosts;
919222623Srmacklem	while (nhostsbak > 0) {
920222623Srmacklem		--nhostsbak;
921222623Srmacklem		if (sock_fdpos >= sock_fdcnt) {
922222623Srmacklem			/* Should never happen. */
923222623Srmacklem			syslog(LOG_ERR, "Ran out of socket fd's");
924222623Srmacklem			return;
925222623Srmacklem		}
926222623Srmacklem		fd = sock_fd[sock_fdpos++];
927222623Srmacklem		if (fd < 0)
928222623Srmacklem			continue;
929222623Srmacklem
930172827Smatteo		if (nconf->nc_semantics != NC_TPI_CLTS)
931172827Smatteo			listen(fd, SOMAXCONN);
932172827Smatteo
933172827Smatteo		if (nconf->nc_semantics == NC_TPI_CLTS )
934172827Smatteo			transp = svc_dg_create(fd, 0, 0);
935172827Smatteo		else
936172827Smatteo			transp = svc_vc_create(fd, RPC_MAXDATASIZE,
937172827Smatteo			    RPC_MAXDATASIZE);
938172827Smatteo
939172827Smatteo		if (transp != (SVCXPRT *) NULL) {
940194880Sdfr			if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv,
941172827Smatteo			    NULL))
942172827Smatteo				syslog(LOG_ERR,
943194880Sdfr				    "can't register %s MOUNTVERS service",
944172827Smatteo				    nconf->nc_netid);
945172827Smatteo			if (!force_v2) {
946194880Sdfr				if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3,
947172827Smatteo				    mntsrv, NULL))
948172827Smatteo					syslog(LOG_ERR,
949194880Sdfr					    "can't register %s MOUNTVERS3 service",
950172827Smatteo					    nconf->nc_netid);
951172827Smatteo			}
952172827Smatteo		} else
953172827Smatteo			syslog(LOG_WARNING, "can't create %s services",
954172827Smatteo			    nconf->nc_netid);
955172827Smatteo
956172827Smatteo		if (registered == 0) {
957172827Smatteo			registered = 1;
958172827Smatteo			memset(&hints, 0, sizeof hints);
959172827Smatteo			hints.ai_flags = AI_PASSIVE;
960172827Smatteo			hints.ai_family = si.si_af;
961172827Smatteo			hints.ai_socktype = si.si_socktype;
962172827Smatteo			hints.ai_protocol = si.si_proto;
963172827Smatteo
964222623Srmacklem			if ((aicode = getaddrinfo(NULL, port_str, &hints,
965172827Smatteo			    &res)) != 0) {
966172827Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
967172827Smatteo				    gai_strerror(aicode));
968172827Smatteo				exit(1);
969172827Smatteo			}
970172827Smatteo
971172827Smatteo			servaddr.buf = malloc(res->ai_addrlen);
972172827Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
973172827Smatteo			servaddr.len = res->ai_addrlen;
974172827Smatteo
975194880Sdfr			rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr);
976194880Sdfr			rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr);
977172827Smatteo
978172827Smatteo			xcreated++;
979172827Smatteo			freeaddrinfo(res);
980172827Smatteo		}
981172827Smatteo	} /* end while */
9821558Srgrimes}
9831558Srgrimes
984222623Srmacklem/*
985222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the
986222623Srmacklem * cycle of socket creation/binding can start anew.
987222623Srmacklem */
98837663Scharnierstatic void
989222623Srmacklemclearout_service(void)
990222623Srmacklem{
991222623Srmacklem	int i;
992222623Srmacklem
993222623Srmacklem	for (i = 0; i < sock_fdcnt; i++) {
994222623Srmacklem		if (sock_fd[i] >= 0) {
995222623Srmacklem			shutdown(sock_fd[i], SHUT_RDWR);
996222623Srmacklem			close(sock_fd[i]);
997222623Srmacklem		}
998222623Srmacklem	}
999222623Srmacklem}
1000222623Srmacklem
1001222623Srmacklemstatic void
1002216587Scharnierusage(void)
100337663Scharnier{
100437663Scharnier	fprintf(stderr,
1005192993Srmacklem		"usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] "
1006241568Srmacklem		"[-S] [-h <bindip>] [export_file ...]\n");
100737663Scharnier	exit(1);
100837663Scharnier}
100937663Scharnier
10101558Srgrimes/*
10111558Srgrimes * The mount rpc service
10121558Srgrimes */
10131558Srgrimesvoid
1014216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp)
10151558Srgrimes{
10161558Srgrimes	struct exportlist *ep;
10171558Srgrimes	struct dirlist *dp;
10189336Sdfr	struct fhreturn fhr;
10191558Srgrimes	struct stat stb;
10201558Srgrimes	struct statfs fsb;
102174462Salfred	char host[NI_MAXHOST], numerichost[NI_MAXHOST];
102274462Salfred	int lookup_failed = 1;
102374462Salfred	struct sockaddr *saddr;
10249336Sdfr	u_short sport;
1025194880Sdfr	char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN];
102628911Sguido	int bad = 0, defset, hostset;
10279336Sdfr	sigset_t sighup_mask;
1028240902Srmacklem	int numsecflavors, *secflavorsp;
10291558Srgrimes
10309336Sdfr	sigemptyset(&sighup_mask);
10319336Sdfr	sigaddset(&sighup_mask, SIGHUP);
103274462Salfred	saddr = svc_getrpccaller(transp)->buf;
103374462Salfred	switch (saddr->sa_family) {
103474462Salfred	case AF_INET6:
103575635Siedowse		sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
103674462Salfred		break;
103774462Salfred	case AF_INET:
103875635Siedowse		sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
103974462Salfred		break;
104074462Salfred	default:
104174462Salfred		syslog(LOG_ERR, "request from unknown address family");
104274462Salfred		return;
104374462Salfred	}
104474462Salfred	lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
104574462Salfred	    NULL, 0, 0);
104674462Salfred	getnameinfo(saddr, saddr->sa_len, numerichost,
104774462Salfred	    sizeof numerichost, NULL, 0, NI_NUMERICHOST);
10481558Srgrimes	switch (rqstp->rq_proc) {
10491558Srgrimes	case NULLPROC:
1050121556Speter		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
105137663Scharnier			syslog(LOG_ERR, "can't send reply");
10521558Srgrimes		return;
1053194880Sdfr	case MOUNTPROC_MNT:
10549336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
105531656Sguido			syslog(LOG_NOTICE,
105631656Sguido			    "mount request from %s from unprivileged port",
105774462Salfred			    numerichost);
10581558Srgrimes			svcerr_weakauth(transp);
10591558Srgrimes			return;
10601558Srgrimes		}
1061121556Speter		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
106231656Sguido			syslog(LOG_NOTICE, "undecodable mount request from %s",
106374462Salfred			    numerichost);
10641558Srgrimes			svcerr_decode(transp);
10651558Srgrimes			return;
10661558Srgrimes		}
10671558Srgrimes
10681558Srgrimes		/*
10691558Srgrimes		 * Get the real pathname and make sure it is a directory
10709336Sdfr		 * or a regular file if the -r option was specified
10719336Sdfr		 * and it exists.
10721558Srgrimes		 */
107351968Salfred		if (realpath(rpcpath, dirpath) == NULL ||
10741558Srgrimes		    stat(dirpath, &stb) < 0 ||
10751558Srgrimes		    statfs(dirpath, &fsb) < 0) {
10761558Srgrimes			chdir("/");	/* Just in case realpath doesn't */
107731656Sguido			syslog(LOG_NOTICE,
107837663Scharnier			    "mount request from %s for non existent path %s",
107974462Salfred			    numerichost, dirpath);
10801558Srgrimes			if (debug)
108137663Scharnier				warnx("stat failed on %s", dirpath);
108228911Sguido			bad = ENOENT;	/* We will send error reply later */
10831558Srgrimes		}
1084330093Srpokala		if (!bad &&
1085330093Srpokala		    !S_ISDIR(stb.st_mode) &&
1086330093Srpokala		    (dir_only || !S_ISREG(stb.st_mode))) {
1087330093Srpokala			syslog(LOG_NOTICE,
1088330093Srpokala			    "mount request from %s for non-directory path %s",
1089330093Srpokala			    numerichost, dirpath);
1090330093Srpokala			if (debug)
1091330093Srpokala				warnx("mounting non-directory %s", dirpath);
1092330093Srpokala			bad = ENOTDIR;	/* We will send error reply later */
1093330093Srpokala		}
10941558Srgrimes
10951558Srgrimes		/* Check in the exports list */
10969336Sdfr		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1097330093Srpokala		if (bad)
1098330093Srpokala			ep = NULL;
1099330093Srpokala		else
1100330093Srpokala			ep = ex_search(&fsb.f_fsid);
11019336Sdfr		hostset = defset = 0;
1102240902Srmacklem		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
1103240902Srmacklem		    &numsecflavors, &secflavorsp) ||
11041558Srgrimes		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
1105240902Srmacklem		      chk_host(dp, saddr, &defset, &hostset, &numsecflavors,
1106240902Srmacklem		       &secflavorsp)) ||
110774462Salfred		    (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
110874462Salfred		     scan_tree(ep->ex_dirl, saddr) == 0))) {
110928911Sguido			if (bad) {
1110121556Speter				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
111128911Sguido				    (caddr_t)&bad))
111237663Scharnier					syslog(LOG_ERR, "can't send reply");
111328911Sguido				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
111428911Sguido				return;
111528911Sguido			}
1116240902Srmacklem			if (hostset & DP_HOSTSET) {
11179336Sdfr				fhr.fhr_flag = hostset;
1118240902Srmacklem				fhr.fhr_numsecflavors = numsecflavors;
1119240902Srmacklem				fhr.fhr_secflavors = secflavorsp;
1120240902Srmacklem			} else {
11219336Sdfr				fhr.fhr_flag = defset;
1122240902Srmacklem				fhr.fhr_numsecflavors = ep->ex_defnumsecflavors;
1123240902Srmacklem				fhr.fhr_secflavors = ep->ex_defsecflavors;
1124240902Srmacklem			}
11259336Sdfr			fhr.fhr_vers = rqstp->rq_vers;
11261558Srgrimes			/* Get the file handle */
112723681Speter			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
11289336Sdfr			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
11291558Srgrimes				bad = errno;
113037663Scharnier				syslog(LOG_ERR, "can't get fh for %s", dirpath);
1131121556Speter				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
11321558Srgrimes				    (caddr_t)&bad))
113337663Scharnier					syslog(LOG_ERR, "can't send reply");
11349336Sdfr				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
11351558Srgrimes				return;
11361558Srgrimes			}
1137121556Speter			if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
1138121556Speter			    (caddr_t)&fhr))
113937663Scharnier				syslog(LOG_ERR, "can't send reply");
114074462Salfred			if (!lookup_failed)
114174462Salfred				add_mlist(host, dirpath);
11421558Srgrimes			else
114374462Salfred				add_mlist(numerichost, dirpath);
11441558Srgrimes			if (debug)
114537663Scharnier				warnx("mount successful");
1146121767Speter			if (dolog)
114731656Sguido				syslog(LOG_NOTICE,
114831656Sguido				    "mount request succeeded from %s for %s",
114974462Salfred				    numerichost, dirpath);
115031656Sguido		} else {
1151330093Srpokala			if (!bad)
1152330093Srpokala				bad = EACCES;
115331656Sguido			syslog(LOG_NOTICE,
115431656Sguido			    "mount request denied from %s for %s",
115574462Salfred			    numerichost, dirpath);
115631656Sguido		}
115728911Sguido
1158121556Speter		if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
1159121556Speter		    (caddr_t)&bad))
116037663Scharnier			syslog(LOG_ERR, "can't send reply");
11619336Sdfr		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
11621558Srgrimes		return;
1163194880Sdfr	case MOUNTPROC_DUMP:
1164121556Speter		if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
116537663Scharnier			syslog(LOG_ERR, "can't send reply");
1166121767Speter		else if (dolog)
116731656Sguido			syslog(LOG_NOTICE,
116831656Sguido			    "dump request succeeded from %s",
116974462Salfred			    numerichost);
11701558Srgrimes		return;
1171194880Sdfr	case MOUNTPROC_UMNT:
11729336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
117331656Sguido			syslog(LOG_NOTICE,
117431656Sguido			    "umount request from %s from unprivileged port",
117574462Salfred			    numerichost);
11761558Srgrimes			svcerr_weakauth(transp);
11771558Srgrimes			return;
11781558Srgrimes		}
1179121556Speter		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
118031656Sguido			syslog(LOG_NOTICE, "undecodable umount request from %s",
118174462Salfred			    numerichost);
11821558Srgrimes			svcerr_decode(transp);
11831558Srgrimes			return;
11841558Srgrimes		}
118551968Salfred		if (realpath(rpcpath, dirpath) == NULL) {
118651968Salfred			syslog(LOG_NOTICE, "umount request from %s "
118751968Salfred			    "for non existent path %s",
118874462Salfred			    numerichost, dirpath);
118951968Salfred		}
1190121556Speter		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
119137663Scharnier			syslog(LOG_ERR, "can't send reply");
119274462Salfred		if (!lookup_failed)
119375635Siedowse			del_mlist(host, dirpath);
119475635Siedowse		del_mlist(numerichost, dirpath);
1195121767Speter		if (dolog)
119631656Sguido			syslog(LOG_NOTICE,
119731656Sguido			    "umount request succeeded from %s for %s",
119874462Salfred			    numerichost, dirpath);
11991558Srgrimes		return;
1200194880Sdfr	case MOUNTPROC_UMNTALL:
12019336Sdfr		if (sport >= IPPORT_RESERVED && resvport_only) {
120231656Sguido			syslog(LOG_NOTICE,
120331656Sguido			    "umountall request from %s from unprivileged port",
120474462Salfred			    numerichost);
12051558Srgrimes			svcerr_weakauth(transp);
12061558Srgrimes			return;
12071558Srgrimes		}
1208121556Speter		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
120937663Scharnier			syslog(LOG_ERR, "can't send reply");
121074462Salfred		if (!lookup_failed)
121175635Siedowse			del_mlist(host, NULL);
121275635Siedowse		del_mlist(numerichost, NULL);
1213121767Speter		if (dolog)
121431656Sguido			syslog(LOG_NOTICE,
121531656Sguido			    "umountall request succeeded from %s",
121674462Salfred			    numerichost);
12171558Srgrimes		return;
1218194880Sdfr	case MOUNTPROC_EXPORT:
1219121556Speter		if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
1220121556Speter			if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
1221121556Speter			    (caddr_t)NULL))
1222100117Salfred				syslog(LOG_ERR, "can't send reply");
1223121767Speter		if (dolog)
122431656Sguido			syslog(LOG_NOTICE,
122531656Sguido			    "export request succeeded from %s",
122674462Salfred			    numerichost);
12271558Srgrimes		return;
12281558Srgrimes	default:
12291558Srgrimes		svcerr_noproc(transp);
12301558Srgrimes		return;
12311558Srgrimes	}
12321558Srgrimes}
12331558Srgrimes
12341558Srgrimes/*
12351558Srgrimes * Xdr conversion for a dirpath string
12361558Srgrimes */
12371558Srgrimesint
1238216587Scharnierxdr_dir(XDR *xdrsp, char *dirp)
12391558Srgrimes{
1240194880Sdfr	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
12411558Srgrimes}
12421558Srgrimes
12431558Srgrimes/*
12449336Sdfr * Xdr routine to generate file handle reply
12451558Srgrimes */
12461558Srgrimesint
1247216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp)
12481558Srgrimes{
124992806Sobrien	struct fhreturn *fhrp = (struct fhreturn *)cp;
12509336Sdfr	u_long ok = 0, len, auth;
1251184588Sdfr	int i;
12521558Srgrimes
12531558Srgrimes	if (!xdr_long(xdrsp, &ok))
12541558Srgrimes		return (0);
12559336Sdfr	switch (fhrp->fhr_vers) {
12569336Sdfr	case 1:
12579336Sdfr		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
12589336Sdfr	case 3:
12599336Sdfr		len = NFSX_V3FH;
12609336Sdfr		if (!xdr_long(xdrsp, &len))
12619336Sdfr			return (0);
12629336Sdfr		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
12639336Sdfr			return (0);
1264184588Sdfr		if (fhrp->fhr_numsecflavors) {
1265184588Sdfr			if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors))
1266184588Sdfr				return (0);
1267184588Sdfr			for (i = 0; i < fhrp->fhr_numsecflavors; i++)
1268184588Sdfr				if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i]))
1269184588Sdfr					return (0);
1270184588Sdfr			return (1);
1271184588Sdfr		} else {
1272184588Sdfr			auth = AUTH_SYS;
1273184588Sdfr			len = 1;
1274184588Sdfr			if (!xdr_long(xdrsp, &len))
1275184588Sdfr				return (0);
1276184588Sdfr			return (xdr_long(xdrsp, &auth));
1277184588Sdfr		}
12789336Sdfr	};
12799336Sdfr	return (0);
12801558Srgrimes}
12811558Srgrimes
12821558Srgrimesint
1283216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused)
12841558Srgrimes{
12851558Srgrimes	struct mountlist *mlp;
12861558Srgrimes	int true = 1;
12871558Srgrimes	int false = 0;
12881558Srgrimes	char *strp;
12891558Srgrimes
12901558Srgrimes	mlp = mlhead;
12911558Srgrimes	while (mlp) {
12921558Srgrimes		if (!xdr_bool(xdrsp, &true))
12931558Srgrimes			return (0);
12941558Srgrimes		strp = &mlp->ml_host[0];
1295194880Sdfr		if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
12961558Srgrimes			return (0);
12971558Srgrimes		strp = &mlp->ml_dirp[0];
1298194880Sdfr		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
12991558Srgrimes			return (0);
13001558Srgrimes		mlp = mlp->ml_next;
13011558Srgrimes	}
13021558Srgrimes	if (!xdr_bool(xdrsp, &false))
13031558Srgrimes		return (0);
13041558Srgrimes	return (1);
13051558Srgrimes}
13061558Srgrimes
13071558Srgrimes/*
13081558Srgrimes * Xdr conversion for export list
13091558Srgrimes */
13101558Srgrimesint
1311216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief)
13121558Srgrimes{
13131558Srgrimes	struct exportlist *ep;
13141558Srgrimes	int false = 0;
13159336Sdfr	int putdef;
13169336Sdfr	sigset_t sighup_mask;
13171558Srgrimes
13189336Sdfr	sigemptyset(&sighup_mask);
13199336Sdfr	sigaddset(&sighup_mask, SIGHUP);
13209336Sdfr	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
13211558Srgrimes	ep = exphead;
13221558Srgrimes	while (ep) {
13231558Srgrimes		putdef = 0;
1324100117Salfred		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
1325100117Salfred			       &putdef, brief))
13261558Srgrimes			goto errout;
13271558Srgrimes		if (ep->ex_defdir && putdef == 0 &&
13281558Srgrimes			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
1329100117Salfred			&putdef, brief))
13301558Srgrimes			goto errout;
13311558Srgrimes		ep = ep->ex_next;
13321558Srgrimes	}
13339336Sdfr	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
13341558Srgrimes	if (!xdr_bool(xdrsp, &false))
13351558Srgrimes		return (0);
13361558Srgrimes	return (1);
13371558Srgrimeserrout:
13389336Sdfr	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
13391558Srgrimes	return (0);
13401558Srgrimes}
13411558Srgrimes
13421558Srgrimes/*
13431558Srgrimes * Called from xdr_explist() to traverse the tree and export the
13441558Srgrimes * directory paths.
13451558Srgrimes */
13461558Srgrimesint
1347216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp,
1348216587Scharnier	int brief)
13491558Srgrimes{
13501558Srgrimes	struct grouplist *grp;
13511558Srgrimes	struct hostlist *hp;
13521558Srgrimes	int true = 1;
13531558Srgrimes	int false = 0;
13541558Srgrimes	int gotalldir = 0;
13551558Srgrimes	char *strp;
13561558Srgrimes
13571558Srgrimes	if (dp) {
1358100117Salfred		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
13591558Srgrimes			return (1);
13601558Srgrimes		if (!xdr_bool(xdrsp, &true))
13611558Srgrimes			return (1);
13621558Srgrimes		strp = dp->dp_dirp;
1363194880Sdfr		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
13641558Srgrimes			return (1);
13651558Srgrimes		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
13661558Srgrimes			gotalldir = 1;
13671558Srgrimes			*putdefp = 1;
13681558Srgrimes		}
1369100117Salfred		if (brief) {
1370100117Salfred			if (!xdr_bool(xdrsp, &true))
1371100117Salfred				return (1);
1372100117Salfred			strp = "(...)";
1373194880Sdfr			if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
1374100117Salfred				return (1);
1375100117Salfred		} else if ((dp->dp_flag & DP_DEFSET) == 0 &&
13761558Srgrimes		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
13771558Srgrimes			hp = dp->dp_hosts;
13781558Srgrimes			while (hp) {
13791558Srgrimes				grp = hp->ht_grp;
13801558Srgrimes				if (grp->gr_type == GT_HOST) {
13811558Srgrimes					if (!xdr_bool(xdrsp, &true))
13821558Srgrimes						return (1);
138374462Salfred					strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
13848871Srgrimes					if (!xdr_string(xdrsp, &strp,
1385194880Sdfr					    MNTNAMLEN))
13861558Srgrimes						return (1);
13871558Srgrimes				} else if (grp->gr_type == GT_NET) {
13881558Srgrimes					if (!xdr_bool(xdrsp, &true))
13891558Srgrimes						return (1);
13901558Srgrimes					strp = grp->gr_ptr.gt_net.nt_name;
13918871Srgrimes					if (!xdr_string(xdrsp, &strp,
1392194880Sdfr					    MNTNAMLEN))
13931558Srgrimes						return (1);
13941558Srgrimes				}
13951558Srgrimes				hp = hp->ht_next;
13961558Srgrimes				if (gotalldir && hp == (struct hostlist *)NULL) {
13971558Srgrimes					hp = adp->dp_hosts;
13981558Srgrimes					gotalldir = 0;
13991558Srgrimes				}
14001558Srgrimes			}
14011558Srgrimes		}
14021558Srgrimes		if (!xdr_bool(xdrsp, &false))
14031558Srgrimes			return (1);
1404100117Salfred		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
14051558Srgrimes			return (1);
14061558Srgrimes	}
14071558Srgrimes	return (0);
14081558Srgrimes}
14091558Srgrimes
1410100117Salfredint
1411216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp)
1412100117Salfred{
1413100117Salfred
1414100117Salfred	return xdr_explist_common(xdrsp, cp, 0);
1415100117Salfred}
1416100117Salfred
1417100117Salfredint
1418216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp)
1419100117Salfred{
1420100117Salfred
1421100117Salfred	return xdr_explist_common(xdrsp, cp, 1);
1422100117Salfred}
1423100117Salfred
142496622Siedowsechar *line;
142596622Siedowseint linesize;
14261558SrgrimesFILE *exp_file;
14271558Srgrimes
14281558Srgrimes/*
1429166440Spjd * Get the export list from one, currently open file
14301558Srgrimes */
1431166440Spjdstatic void
1432216587Scharnierget_exportlist_one(void)
14331558Srgrimes{
14341558Srgrimes	struct exportlist *ep, *ep2;
14351558Srgrimes	struct grouplist *grp, *tgrp;
14361558Srgrimes	struct exportlist **epp;
14371558Srgrimes	struct dirlist *dirhead;
1438166440Spjd	struct statfs fsb;
143972650Sgreen	struct xucred anon;
14401558Srgrimes	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
1441166440Spjd	int len, has_host, exflags, got_nondir, dirplen, netgrp;
14421558Srgrimes
1443192934Srmacklem	v4root_phase = 0;
14441558Srgrimes	dirhead = (struct dirlist *)NULL;
14451558Srgrimes	while (get_line()) {
14461558Srgrimes		if (debug)
144737663Scharnier			warnx("got line %s", line);
14481558Srgrimes		cp = line;
14491558Srgrimes		nextfield(&cp, &endcp);
14501558Srgrimes		if (*cp == '#')
14511558Srgrimes			goto nextline;
14521558Srgrimes
14531558Srgrimes		/*
14541558Srgrimes		 * Set defaults.
14551558Srgrimes		 */
14561558Srgrimes		has_host = FALSE;
14571558Srgrimes		anon = def_anon;
14581558Srgrimes		exflags = MNT_EXPORTED;
14591558Srgrimes		got_nondir = 0;
14601558Srgrimes		opt_flags = 0;
14611558Srgrimes		ep = (struct exportlist *)NULL;
1462192934Srmacklem		dirp = NULL;
14631558Srgrimes
14641558Srgrimes		/*
1465192934Srmacklem		 * Handle the V4 root dir.
1466192934Srmacklem		 */
1467192934Srmacklem		if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') {
1468192934Srmacklem			/*
1469192934Srmacklem			 * V4: just indicates that it is the v4 root point,
1470192934Srmacklem			 * so skip over that and set v4root_phase.
1471192934Srmacklem			 */
1472192934Srmacklem			if (v4root_phase > 0) {
1473192934Srmacklem				syslog(LOG_ERR, "V4:duplicate line, ignored");
1474192934Srmacklem				goto nextline;
1475192934Srmacklem			}
1476192934Srmacklem			v4root_phase = 1;
1477192934Srmacklem			cp += 3;
1478192934Srmacklem			nextfield(&cp, &endcp);
1479192934Srmacklem		}
1480192934Srmacklem
1481192934Srmacklem		/*
14821558Srgrimes		 * Create new exports list entry
14831558Srgrimes		 */
14841558Srgrimes		len = endcp-cp;
14851558Srgrimes		tgrp = grp = get_grp();
14861558Srgrimes		while (len > 0) {
1487194880Sdfr			if (len > MNTNAMLEN) {
14881558Srgrimes			    getexp_err(ep, tgrp);
14891558Srgrimes			    goto nextline;
14901558Srgrimes			}
14911558Srgrimes			if (*cp == '-') {
14921558Srgrimes			    if (ep == (struct exportlist *)NULL) {
14931558Srgrimes				getexp_err(ep, tgrp);
14941558Srgrimes				goto nextline;
14951558Srgrimes			    }
14961558Srgrimes			    if (debug)
149737663Scharnier				warnx("doing opt %s", cp);
14981558Srgrimes			    got_nondir = 1;
14991558Srgrimes			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
15001558Srgrimes				&exflags, &anon)) {
15011558Srgrimes				getexp_err(ep, tgrp);
15021558Srgrimes				goto nextline;
15031558Srgrimes			    }
15041558Srgrimes			} else if (*cp == '/') {
15051558Srgrimes			    savedc = *endcp;
15061558Srgrimes			    *endcp = '\0';
1507192934Srmacklem			    if (v4root_phase > 1) {
1508192934Srmacklem				    if (dirp != NULL) {
1509192934Srmacklem					syslog(LOG_ERR, "Multiple V4 dirs");
1510192934Srmacklem					getexp_err(ep, tgrp);
1511192934Srmacklem					goto nextline;
1512192934Srmacklem				    }
1513192934Srmacklem			    }
15141558Srgrimes			    if (check_dirpath(cp) &&
15151558Srgrimes				statfs(cp, &fsb) >= 0) {
1516283762Srmacklem				if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0)
1517283762Srmacklem				    syslog(LOG_ERR, "Warning: exporting of "
1518283762Srmacklem					"automounted fs %s not supported", cp);
15191558Srgrimes				if (got_nondir) {
152037663Scharnier				    syslog(LOG_ERR, "dirs must be first");
15211558Srgrimes				    getexp_err(ep, tgrp);
15221558Srgrimes				    goto nextline;
15231558Srgrimes				}
1524192934Srmacklem				if (v4root_phase == 1) {
1525192934Srmacklem				    if (dirp != NULL) {
1526192934Srmacklem					syslog(LOG_ERR, "Multiple V4 dirs");
15271558Srgrimes					getexp_err(ep, tgrp);
15281558Srgrimes					goto nextline;
15291558Srgrimes				    }
1530192934Srmacklem				    if (strlen(v4root_dirpath) == 0) {
1531192934Srmacklem					strlcpy(v4root_dirpath, cp,
1532192934Srmacklem					    sizeof (v4root_dirpath));
1533192934Srmacklem				    } else if (strcmp(v4root_dirpath, cp)
1534192934Srmacklem					!= 0) {
1535192934Srmacklem					syslog(LOG_ERR,
1536192934Srmacklem					    "different V4 dirpath %s", cp);
1537192934Srmacklem					getexp_err(ep, tgrp);
1538192934Srmacklem					goto nextline;
1539192934Srmacklem				    }
1540192934Srmacklem				    dirp = cp;
1541192934Srmacklem				    v4root_phase = 2;
1542192934Srmacklem				    got_nondir = 1;
1543192934Srmacklem				    ep = get_exp();
15441558Srgrimes				} else {
1545192934Srmacklem				    if (ep) {
1546192934Srmacklem					if (ep->ex_fs.val[0] !=
1547192934Srmacklem					    fsb.f_fsid.val[0] ||
1548192934Srmacklem					    ep->ex_fs.val[1] !=
1549192934Srmacklem					    fsb.f_fsid.val[1]) {
1550192934Srmacklem						getexp_err(ep, tgrp);
1551192934Srmacklem						goto nextline;
1552192934Srmacklem					}
1553192934Srmacklem				    } else {
1554192934Srmacklem					/*
1555192934Srmacklem					 * See if this directory is already
1556192934Srmacklem					 * in the list.
1557192934Srmacklem					 */
1558192934Srmacklem					ep = ex_search(&fsb.f_fsid);
1559192934Srmacklem					if (ep == (struct exportlist *)NULL) {
1560192934Srmacklem					    ep = get_exp();
1561192934Srmacklem					    ep->ex_fs = fsb.f_fsid;
1562192934Srmacklem					    ep->ex_fsdir = (char *)malloc
1563192934Srmacklem					        (strlen(fsb.f_mntonname) + 1);
1564192934Srmacklem					    if (ep->ex_fsdir)
1565192934Srmacklem						strcpy(ep->ex_fsdir,
1566192934Srmacklem						    fsb.f_mntonname);
1567192934Srmacklem					    else
1568192934Srmacklem						out_of_mem();
1569192934Srmacklem					    if (debug)
1570192934Srmacklem						warnx(
1571192934Srmacklem						  "making new ep fs=0x%x,0x%x",
1572192934Srmacklem						  fsb.f_fsid.val[0],
1573192934Srmacklem						  fsb.f_fsid.val[1]);
1574192934Srmacklem					} else if (debug)
1575192934Srmacklem					    warnx("found ep fs=0x%x,0x%x",
1576192934Srmacklem						fsb.f_fsid.val[0],
1577192934Srmacklem						fsb.f_fsid.val[1]);
1578192934Srmacklem				    }
1579192934Srmacklem
15801558Srgrimes				    /*
1581192934Srmacklem				     * Add dirpath to export mount point.
15821558Srgrimes				     */
1583192934Srmacklem				    dirp = add_expdir(&dirhead, cp, len);
1584192934Srmacklem				    dirplen = len;
15851558Srgrimes				}
15861558Srgrimes			    } else {
15871558Srgrimes				getexp_err(ep, tgrp);
15881558Srgrimes				goto nextline;
15891558Srgrimes			    }
15901558Srgrimes			    *endcp = savedc;
15911558Srgrimes			} else {
15921558Srgrimes			    savedc = *endcp;
15931558Srgrimes			    *endcp = '\0';
15941558Srgrimes			    got_nondir = 1;
15951558Srgrimes			    if (ep == (struct exportlist *)NULL) {
15961558Srgrimes				getexp_err(ep, tgrp);
15971558Srgrimes				goto nextline;
15981558Srgrimes			    }
15991558Srgrimes
16001558Srgrimes			    /*
16011558Srgrimes			     * Get the host or netgroup.
16021558Srgrimes			     */
16031558Srgrimes			    setnetgrent(cp);
16041558Srgrimes			    netgrp = getnetgrent(&hst, &usr, &dom);
16051558Srgrimes			    do {
16061558Srgrimes				if (has_host) {
16071558Srgrimes				    grp->gr_next = get_grp();
16081558Srgrimes				    grp = grp->gr_next;
16091558Srgrimes				}
16101558Srgrimes				if (netgrp) {
161137003Sjoerg				    if (hst == 0) {
161237663Scharnier					syslog(LOG_ERR,
161337663Scharnier				"null hostname in netgroup %s, skipping", cp);
161437004Sjoerg					grp->gr_type = GT_IGNORE;
161537003Sjoerg				    } else if (get_host(hst, grp, tgrp)) {
161637663Scharnier					syslog(LOG_ERR,
161737663Scharnier			"bad host %s in netgroup %s, skipping", hst, cp);
161829317Sjlemon					grp->gr_type = GT_IGNORE;
16191558Srgrimes				    }
16207401Swpaul				} else if (get_host(cp, grp, tgrp)) {
162137663Scharnier				    syslog(LOG_ERR, "bad host %s, skipping", cp);
162229317Sjlemon				    grp->gr_type = GT_IGNORE;
16231558Srgrimes				}
16241558Srgrimes				has_host = TRUE;
16251558Srgrimes			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
16261558Srgrimes			    endnetgrent();
16271558Srgrimes			    *endcp = savedc;
16281558Srgrimes			}
16291558Srgrimes			cp = endcp;
16301558Srgrimes			nextfield(&cp, &endcp);
16311558Srgrimes			len = endcp - cp;
16321558Srgrimes		}
16331558Srgrimes		if (check_options(dirhead)) {
16341558Srgrimes			getexp_err(ep, tgrp);
16351558Srgrimes			goto nextline;
16361558Srgrimes		}
16371558Srgrimes		if (!has_host) {
163875641Siedowse			grp->gr_type = GT_DEFAULT;
16391558Srgrimes			if (debug)
164037663Scharnier				warnx("adding a default entry");
16411558Srgrimes
16421558Srgrimes		/*
16431558Srgrimes		 * Don't allow a network export coincide with a list of
16441558Srgrimes		 * host(s) on the same line.
16451558Srgrimes		 */
16461558Srgrimes		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
164775801Siedowse			syslog(LOG_ERR, "network/host conflict");
16481558Srgrimes			getexp_err(ep, tgrp);
16491558Srgrimes			goto nextline;
165029317Sjlemon
165174462Salfred		/*
165274462Salfred		 * If an export list was specified on this line, make sure
165329317Sjlemon		 * that we have at least one valid entry, otherwise skip it.
165429317Sjlemon		 */
165529317Sjlemon		} else {
165629317Sjlemon			grp = tgrp;
165774462Salfred			while (grp && grp->gr_type == GT_IGNORE)
165829317Sjlemon				grp = grp->gr_next;
165929317Sjlemon			if (! grp) {
166029317Sjlemon			    getexp_err(ep, tgrp);
166129317Sjlemon			    goto nextline;
166229317Sjlemon			}
16631558Srgrimes		}
16641558Srgrimes
1665192934Srmacklem		if (v4root_phase == 1) {
1666192934Srmacklem			syslog(LOG_ERR, "V4:root, no dirp, ignored");
1667192934Srmacklem			getexp_err(ep, tgrp);
1668192934Srmacklem			goto nextline;
1669192934Srmacklem		}
1670192934Srmacklem
16711558Srgrimes		/*
16721558Srgrimes		 * Loop through hosts, pushing the exports into the kernel.
16731558Srgrimes		 * After loop, tgrp points to the start of the list and
16741558Srgrimes		 * grp points to the last entry in the list.
16751558Srgrimes		 */
16761558Srgrimes		grp = tgrp;
16771558Srgrimes		do {
167875635Siedowse			if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
167975635Siedowse			    &fsb)) {
168075635Siedowse				getexp_err(ep, tgrp);
168175635Siedowse				goto nextline;
168275635Siedowse			}
16831558Srgrimes		} while (grp->gr_next && (grp = grp->gr_next));
16841558Srgrimes
16851558Srgrimes		/*
1686192934Srmacklem		 * For V4: don't enter in mount lists.
1687192934Srmacklem		 */
1688194773Srmacklem		if (v4root_phase > 0 && v4root_phase <= 2) {
1689194773Srmacklem			/*
1690194773Srmacklem			 * Since these structures aren't used by mountd,
1691194773Srmacklem			 * free them up now.
1692194773Srmacklem			 */
1693194773Srmacklem			if (ep != NULL)
1694194773Srmacklem				free_exp(ep);
1695194773Srmacklem			while (tgrp != NULL) {
1696194773Srmacklem				grp = tgrp;
1697194773Srmacklem				tgrp = tgrp->gr_next;
1698194773Srmacklem				free_grp(grp);
1699194773Srmacklem			}
1700192934Srmacklem			goto nextline;
1701194773Srmacklem		}
1702192934Srmacklem
1703192934Srmacklem		/*
17041558Srgrimes		 * Success. Update the data structures.
17051558Srgrimes		 */
17061558Srgrimes		if (has_host) {
17079336Sdfr			hang_dirp(dirhead, tgrp, ep, opt_flags);
17081558Srgrimes			grp->gr_next = grphead;
17091558Srgrimes			grphead = tgrp;
17101558Srgrimes		} else {
17111558Srgrimes			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
17129336Sdfr				opt_flags);
17131558Srgrimes			free_grp(grp);
17141558Srgrimes		}
17151558Srgrimes		dirhead = (struct dirlist *)NULL;
17161558Srgrimes		if ((ep->ex_flag & EX_LINKED) == 0) {
17171558Srgrimes			ep2 = exphead;
17181558Srgrimes			epp = &exphead;
17191558Srgrimes
17201558Srgrimes			/*
17211558Srgrimes			 * Insert in the list in alphabetical order.
17221558Srgrimes			 */
17231558Srgrimes			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
17241558Srgrimes				epp = &ep2->ex_next;
17251558Srgrimes				ep2 = ep2->ex_next;
17261558Srgrimes			}
17271558Srgrimes			if (ep2)
17281558Srgrimes				ep->ex_next = ep2;
17291558Srgrimes			*epp = ep;
17301558Srgrimes			ep->ex_flag |= EX_LINKED;
17311558Srgrimes		}
17321558Srgrimesnextline:
1733192934Srmacklem		v4root_phase = 0;
17341558Srgrimes		if (dirhead) {
17351558Srgrimes			free_dir(dirhead);
17361558Srgrimes			dirhead = (struct dirlist *)NULL;
17371558Srgrimes		}
17381558Srgrimes	}
17391558Srgrimes}
17401558Srgrimes
17411558Srgrimes/*
1742166440Spjd * Get the export list from all specified files
1743166440Spjd */
1744166440Spjdvoid
1745216587Scharnierget_exportlist(void)
1746166440Spjd{
1747166440Spjd	struct exportlist *ep, *ep2;
1748166440Spjd	struct grouplist *grp, *tgrp;
1749166440Spjd	struct export_args export;
1750166440Spjd	struct iovec *iov;
1751166440Spjd	struct statfs *fsp, *mntbufp;
1752166440Spjd	struct xvfsconf vfc;
1753166440Spjd	char errmsg[255];
1754230352Seadler	int num, i;
1755166440Spjd	int iovlen;
1756168684Spjd	int done;
1757192934Srmacklem	struct nfsex_args eargs;
1758166440Spjd
1759241568Srmacklem	if (suspend_nfsd != 0)
1760241568Srmacklem		(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL);
1761192934Srmacklem	v4root_dirpath[0] = '\0';
1762166440Spjd	bzero(&export, sizeof(export));
1763166440Spjd	export.ex_flags = MNT_DELEXPORT;
1764166440Spjd	iov = NULL;
1765166440Spjd	iovlen = 0;
1766166440Spjd	bzero(errmsg, sizeof(errmsg));
1767166440Spjd
1768166440Spjd	/*
1769166440Spjd	 * First, get rid of the old list
1770166440Spjd	 */
1771166440Spjd	ep = exphead;
1772166440Spjd	while (ep) {
1773166440Spjd		ep2 = ep;
1774166440Spjd		ep = ep->ex_next;
1775166440Spjd		free_exp(ep2);
1776166440Spjd	}
1777166440Spjd	exphead = (struct exportlist *)NULL;
1778166440Spjd
1779166440Spjd	grp = grphead;
1780166440Spjd	while (grp) {
1781166440Spjd		tgrp = grp;
1782166440Spjd		grp = grp->gr_next;
1783166440Spjd		free_grp(tgrp);
1784166440Spjd	}
1785166440Spjd	grphead = (struct grouplist *)NULL;
1786166440Spjd
1787166440Spjd	/*
1788192934Srmacklem	 * and the old V4 root dir.
1789192934Srmacklem	 */
1790192934Srmacklem	bzero(&eargs, sizeof (eargs));
1791192934Srmacklem	eargs.export.ex_flags = MNT_DELEXPORT;
1792192934Srmacklem	if (run_v4server > 0 &&
1793192934Srmacklem	    nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 &&
1794192934Srmacklem	    errno != ENOENT)
1795192934Srmacklem		syslog(LOG_ERR, "Can't delete exports for V4:");
1796192934Srmacklem
1797192934Srmacklem	/*
1798192934Srmacklem	 * and clear flag that notes if a public fh has been exported.
1799192934Srmacklem	 */
1800192934Srmacklem	has_publicfh = 0;
1801192934Srmacklem
1802192934Srmacklem	/*
1803166440Spjd	 * And delete exports that are in the kernel for all local
1804166440Spjd	 * filesystems.
1805166440Spjd	 * XXX: Should know how to handle all local exportable filesystems.
1806166440Spjd	 */
1807166440Spjd	num = getmntinfo(&mntbufp, MNT_NOWAIT);
1808166440Spjd
1809166440Spjd	if (num > 0) {
1810166440Spjd		build_iovec(&iov, &iovlen, "fstype", NULL, 0);
1811166440Spjd		build_iovec(&iov, &iovlen, "fspath", NULL, 0);
1812166440Spjd		build_iovec(&iov, &iovlen, "from", NULL, 0);
1813166440Spjd		build_iovec(&iov, &iovlen, "update", NULL, 0);
1814166440Spjd		build_iovec(&iov, &iovlen, "export", &export, sizeof(export));
1815166440Spjd		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
1816166440Spjd	}
1817166440Spjd
1818166440Spjd	for (i = 0; i < num; i++) {
1819166440Spjd		fsp = &mntbufp[i];
1820166440Spjd		if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
1821166440Spjd			syslog(LOG_ERR, "getvfsbyname() failed for %s",
1822166440Spjd			    fsp->f_fstypename);
1823166440Spjd			continue;
1824166440Spjd		}
1825166440Spjd
1826166440Spjd		/*
1827282915Ssjg		 * We do not need to delete "export" flag from
1828282915Ssjg		 * filesystems that do not have it set.
1829282915Ssjg		 */
1830282915Ssjg		if (!(fsp->f_flags & MNT_EXPORTED))
1831282915Ssjg		    continue;
1832282915Ssjg		/*
1833166440Spjd		 * Do not delete export for network filesystem by
1834166440Spjd		 * passing "export" arg to nmount().
1835166440Spjd		 * It only makes sense to do this for local filesystems.
1836166440Spjd		 */
1837166440Spjd		if (vfc.vfc_flags & VFCF_NETWORK)
1838166440Spjd			continue;
1839166440Spjd
1840166440Spjd		iov[1].iov_base = fsp->f_fstypename;
1841166440Spjd		iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
1842166440Spjd		iov[3].iov_base = fsp->f_mntonname;
1843166440Spjd		iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
1844166440Spjd		iov[5].iov_base = fsp->f_mntfromname;
1845166440Spjd		iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
1846272428Sbdrewery		errmsg[0] = '\0';
1847166440Spjd
1848279224Skib		/*
1849279224Skib		 * EXDEV is returned when path exists but is not a
1850279224Skib		 * mount point.  May happens if raced with unmount.
1851279224Skib		 */
1852166440Spjd		if (nmount(iov, iovlen, fsp->f_flags) < 0 &&
1853279224Skib		    errno != ENOENT && errno != ENOTSUP && errno != EXDEV) {
1854166440Spjd			syslog(LOG_ERR,
1855166440Spjd			    "can't delete exports for %s: %m %s",
1856166440Spjd			    fsp->f_mntonname, errmsg);
1857166440Spjd		}
1858166440Spjd	}
1859166440Spjd
1860166440Spjd	if (iov != NULL) {
1861166440Spjd		/* Free strings allocated by strdup() in getmntopts.c */
1862166440Spjd		free(iov[0].iov_base); /* fstype */
1863166440Spjd		free(iov[2].iov_base); /* fspath */
1864166440Spjd		free(iov[4].iov_base); /* from */
1865166440Spjd		free(iov[6].iov_base); /* update */
1866166440Spjd		free(iov[8].iov_base); /* export */
1867166440Spjd		free(iov[10].iov_base); /* errmsg */
1868166440Spjd
1869166440Spjd		/* free iov, allocated by realloc() */
1870166440Spjd		free(iov);
1871166440Spjd		iovlen = 0;
1872166440Spjd	}
1873166440Spjd
1874166440Spjd	/*
1875166440Spjd	 * Read in the exports file and build the list, calling
1876166440Spjd	 * nmount() as we go along to push the export rules into the kernel.
1877166440Spjd	 */
1878168684Spjd	done = 0;
1879166440Spjd	for (i = 0; exnames[i] != NULL; i++) {
1880166440Spjd		if (debug)
1881166440Spjd			warnx("reading exports from %s", exnames[i]);
1882166440Spjd		if ((exp_file = fopen(exnames[i], "r")) == NULL) {
1883168684Spjd			syslog(LOG_WARNING, "can't open %s", exnames[i]);
1884168684Spjd			continue;
1885166440Spjd		}
1886166440Spjd		get_exportlist_one();
1887166440Spjd		fclose(exp_file);
1888168684Spjd		done++;
1889166440Spjd	}
1890168684Spjd	if (done == 0) {
1891168684Spjd		syslog(LOG_ERR, "can't open any exports file");
1892168684Spjd		exit(2);
1893168684Spjd	}
1894192934Srmacklem
1895192934Srmacklem	/*
1896192934Srmacklem	 * If there was no public fh, clear any previous one set.
1897192934Srmacklem	 */
1898192934Srmacklem	if (run_v4server > 0 && has_publicfh == 0)
1899192934Srmacklem		(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
1900241568Srmacklem
1901241568Srmacklem	/* Resume the nfsd. If they weren't suspended, this is harmless. */
1902241568Srmacklem	(void)nfssvc(NFSSVC_RESUMENFSD, NULL);
1903166440Spjd}
1904166440Spjd
1905166440Spjd/*
19061558Srgrimes * Allocate an export list element
19071558Srgrimes */
19081558Srgrimesstruct exportlist *
1909216587Scharnierget_exp(void)
19101558Srgrimes{
19111558Srgrimes	struct exportlist *ep;
19121558Srgrimes
1913224003Sdelphij	ep = (struct exportlist *)calloc(1, sizeof (struct exportlist));
19141558Srgrimes	if (ep == (struct exportlist *)NULL)
19151558Srgrimes		out_of_mem();
19161558Srgrimes	return (ep);
19171558Srgrimes}
19181558Srgrimes
19191558Srgrimes/*
19201558Srgrimes * Allocate a group list element
19211558Srgrimes */
19221558Srgrimesstruct grouplist *
1923216587Scharnierget_grp(void)
19241558Srgrimes{
19251558Srgrimes	struct grouplist *gp;
19261558Srgrimes
1927224003Sdelphij	gp = (struct grouplist *)calloc(1, sizeof (struct grouplist));
19281558Srgrimes	if (gp == (struct grouplist *)NULL)
19291558Srgrimes		out_of_mem();
19301558Srgrimes	return (gp);
19311558Srgrimes}
19321558Srgrimes
19331558Srgrimes/*
19341558Srgrimes * Clean up upon an error in get_exportlist().
19351558Srgrimes */
19361558Srgrimesvoid
1937216587Scharniergetexp_err(struct exportlist *ep, struct grouplist *grp)
19381558Srgrimes{
19391558Srgrimes	struct grouplist *tgrp;
19401558Srgrimes
1941100336Sjoerg	if (!(opt_flags & OP_QUIET))
1942100336Sjoerg		syslog(LOG_ERR, "bad exports list line %s", line);
19431558Srgrimes	if (ep && (ep->ex_flag & EX_LINKED) == 0)
19441558Srgrimes		free_exp(ep);
19451558Srgrimes	while (grp) {
19461558Srgrimes		tgrp = grp;
19471558Srgrimes		grp = grp->gr_next;
19481558Srgrimes		free_grp(tgrp);
19491558Srgrimes	}
19501558Srgrimes}
19511558Srgrimes
19521558Srgrimes/*
19531558Srgrimes * Search the export list for a matching fs.
19541558Srgrimes */
19551558Srgrimesstruct exportlist *
1956216587Scharnierex_search(fsid_t *fsid)
19571558Srgrimes{
19581558Srgrimes	struct exportlist *ep;
19591558Srgrimes
19601558Srgrimes	ep = exphead;
19611558Srgrimes	while (ep) {
19621558Srgrimes		if (ep->ex_fs.val[0] == fsid->val[0] &&
19631558Srgrimes		    ep->ex_fs.val[1] == fsid->val[1])
19641558Srgrimes			return (ep);
19651558Srgrimes		ep = ep->ex_next;
19661558Srgrimes	}
19671558Srgrimes	return (ep);
19681558Srgrimes}
19691558Srgrimes
19701558Srgrimes/*
19711558Srgrimes * Add a directory path to the list.
19721558Srgrimes */
19731558Srgrimeschar *
1974216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len)
19751558Srgrimes{
19761558Srgrimes	struct dirlist *dp;
19771558Srgrimes
19781558Srgrimes	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
197937663Scharnier	if (dp == (struct dirlist *)NULL)
198037663Scharnier		out_of_mem();
19811558Srgrimes	dp->dp_left = *dpp;
19821558Srgrimes	dp->dp_right = (struct dirlist *)NULL;
19831558Srgrimes	dp->dp_flag = 0;
19841558Srgrimes	dp->dp_hosts = (struct hostlist *)NULL;
19851558Srgrimes	strcpy(dp->dp_dirp, cp);
19861558Srgrimes	*dpp = dp;
19871558Srgrimes	return (dp->dp_dirp);
19881558Srgrimes}
19891558Srgrimes
19901558Srgrimes/*
19911558Srgrimes * Hang the dir list element off the dirpath binary tree as required
19921558Srgrimes * and update the entry for host.
19931558Srgrimes */
19941558Srgrimesvoid
1995216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
1996216587Scharnier	int flags)
19971558Srgrimes{
19981558Srgrimes	struct hostlist *hp;
19991558Srgrimes	struct dirlist *dp2;
20001558Srgrimes
20019336Sdfr	if (flags & OP_ALLDIRS) {
20021558Srgrimes		if (ep->ex_defdir)
20031558Srgrimes			free((caddr_t)dp);
20041558Srgrimes		else
20051558Srgrimes			ep->ex_defdir = dp;
20069336Sdfr		if (grp == (struct grouplist *)NULL) {
20071558Srgrimes			ep->ex_defdir->dp_flag |= DP_DEFSET;
2008240902Srmacklem			/* Save the default security flavors list. */
2009240902Srmacklem			ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2010240902Srmacklem			if (ep->ex_numsecflavors > 0)
2011240902Srmacklem				memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2012240902Srmacklem				    sizeof(ep->ex_secflavors));
20139336Sdfr		} else while (grp) {
20141558Srgrimes			hp = get_ht();
20151558Srgrimes			hp->ht_grp = grp;
20161558Srgrimes			hp->ht_next = ep->ex_defdir->dp_hosts;
20171558Srgrimes			ep->ex_defdir->dp_hosts = hp;
2018240902Srmacklem			/* Save the security flavors list for this host set. */
2019240902Srmacklem			grp->gr_numsecflavors = ep->ex_numsecflavors;
2020240902Srmacklem			if (ep->ex_numsecflavors > 0)
2021240902Srmacklem				memcpy(grp->gr_secflavors, ep->ex_secflavors,
2022240902Srmacklem				    sizeof(ep->ex_secflavors));
20231558Srgrimes			grp = grp->gr_next;
20241558Srgrimes		}
20251558Srgrimes	} else {
20261558Srgrimes
20271558Srgrimes		/*
202837663Scharnier		 * Loop through the directories adding them to the tree.
20291558Srgrimes		 */
20301558Srgrimes		while (dp) {
20311558Srgrimes			dp2 = dp->dp_left;
2032240902Srmacklem			add_dlist(&ep->ex_dirl, dp, grp, flags, ep);
20331558Srgrimes			dp = dp2;
20341558Srgrimes		}
20351558Srgrimes	}
20361558Srgrimes}
20371558Srgrimes
20381558Srgrimes/*
20391558Srgrimes * Traverse the binary tree either updating a node that is already there
20401558Srgrimes * for the new directory or adding the new node.
20411558Srgrimes */
20421558Srgrimesvoid
2043216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
2044240902Srmacklem	int flags, struct exportlist *ep)
20451558Srgrimes{
20461558Srgrimes	struct dirlist *dp;
20471558Srgrimes	struct hostlist *hp;
20481558Srgrimes	int cmp;
20491558Srgrimes
20501558Srgrimes	dp = *dpp;
20511558Srgrimes	if (dp) {
20521558Srgrimes		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
20531558Srgrimes		if (cmp > 0) {
2054240902Srmacklem			add_dlist(&dp->dp_left, newdp, grp, flags, ep);
20551558Srgrimes			return;
20561558Srgrimes		} else if (cmp < 0) {
2057240902Srmacklem			add_dlist(&dp->dp_right, newdp, grp, flags, ep);
20581558Srgrimes			return;
20591558Srgrimes		} else
20601558Srgrimes			free((caddr_t)newdp);
20611558Srgrimes	} else {
20621558Srgrimes		dp = newdp;
20631558Srgrimes		dp->dp_left = (struct dirlist *)NULL;
20641558Srgrimes		*dpp = dp;
20651558Srgrimes	}
20661558Srgrimes	if (grp) {
20671558Srgrimes
20681558Srgrimes		/*
20691558Srgrimes		 * Hang all of the host(s) off of the directory point.
20701558Srgrimes		 */
20711558Srgrimes		do {
20721558Srgrimes			hp = get_ht();
20731558Srgrimes			hp->ht_grp = grp;
20741558Srgrimes			hp->ht_next = dp->dp_hosts;
20751558Srgrimes			dp->dp_hosts = hp;
2076240902Srmacklem			/* Save the security flavors list for this host set. */
2077240902Srmacklem			grp->gr_numsecflavors = ep->ex_numsecflavors;
2078240902Srmacklem			if (ep->ex_numsecflavors > 0)
2079240902Srmacklem				memcpy(grp->gr_secflavors, ep->ex_secflavors,
2080240902Srmacklem				    sizeof(ep->ex_secflavors));
20811558Srgrimes			grp = grp->gr_next;
20821558Srgrimes		} while (grp);
20839336Sdfr	} else {
20841558Srgrimes		dp->dp_flag |= DP_DEFSET;
2085240902Srmacklem		/* Save the default security flavors list. */
2086240902Srmacklem		ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2087240902Srmacklem		if (ep->ex_numsecflavors > 0)
2088240902Srmacklem			memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2089240902Srmacklem			    sizeof(ep->ex_secflavors));
20909336Sdfr	}
20911558Srgrimes}
20921558Srgrimes
20931558Srgrimes/*
20941558Srgrimes * Search for a dirpath on the export point.
20951558Srgrimes */
20961558Srgrimesstruct dirlist *
2097216587Scharnierdirp_search(struct dirlist *dp, char *dirp)
20981558Srgrimes{
20991558Srgrimes	int cmp;
21001558Srgrimes
21011558Srgrimes	if (dp) {
210274462Salfred		cmp = strcmp(dp->dp_dirp, dirp);
21031558Srgrimes		if (cmp > 0)
210474462Salfred			return (dirp_search(dp->dp_left, dirp));
21051558Srgrimes		else if (cmp < 0)
210674462Salfred			return (dirp_search(dp->dp_right, dirp));
21071558Srgrimes		else
21081558Srgrimes			return (dp);
21091558Srgrimes	}
21101558Srgrimes	return (dp);
21111558Srgrimes}
21121558Srgrimes
21131558Srgrimes/*
21141558Srgrimes * Scan for a host match in a directory tree.
21151558Srgrimes */
21161558Srgrimesint
2117216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp,
2118240902Srmacklem	int *hostsetp, int *numsecflavors, int **secflavorsp)
21191558Srgrimes{
21201558Srgrimes	struct hostlist *hp;
21211558Srgrimes	struct grouplist *grp;
212274462Salfred	struct addrinfo *ai;
21231558Srgrimes
21241558Srgrimes	if (dp) {
21251558Srgrimes		if (dp->dp_flag & DP_DEFSET)
21269336Sdfr			*defsetp = dp->dp_flag;
21271558Srgrimes		hp = dp->dp_hosts;
21281558Srgrimes		while (hp) {
21291558Srgrimes			grp = hp->ht_grp;
21301558Srgrimes			switch (grp->gr_type) {
21311558Srgrimes			case GT_HOST:
213274462Salfred				ai = grp->gr_ptr.gt_addrinfo;
213374462Salfred				for (; ai; ai = ai->ai_next) {
213475801Siedowse					if (!sacmp(ai->ai_addr, saddr, NULL)) {
213574462Salfred						*hostsetp =
213674462Salfred						    (hp->ht_flag | DP_HOSTSET);
2137240902Srmacklem						if (numsecflavors != NULL) {
2138240902Srmacklem							*numsecflavors =
2139240902Srmacklem							    grp->gr_numsecflavors;
2140240902Srmacklem							*secflavorsp =
2141240902Srmacklem							    grp->gr_secflavors;
2142240902Srmacklem						}
214374462Salfred						return (1);
214474462Salfred					}
21459336Sdfr				}
214675801Siedowse				break;
21471558Srgrimes			case GT_NET:
214875801Siedowse				if (!sacmp(saddr, (struct sockaddr *)
214975801Siedowse				    &grp->gr_ptr.gt_net.nt_net,
215075801Siedowse				    (struct sockaddr *)
215175801Siedowse				    &grp->gr_ptr.gt_net.nt_mask)) {
215274462Salfred					*hostsetp = (hp->ht_flag | DP_HOSTSET);
2153240902Srmacklem					if (numsecflavors != NULL) {
2154240902Srmacklem						*numsecflavors =
2155240902Srmacklem						    grp->gr_numsecflavors;
2156240902Srmacklem						*secflavorsp =
2157240902Srmacklem						    grp->gr_secflavors;
2158240902Srmacklem					}
215974462Salfred					return (1);
216074462Salfred				}
216175801Siedowse				break;
216275801Siedowse			}
21631558Srgrimes			hp = hp->ht_next;
21641558Srgrimes		}
21651558Srgrimes	}
21661558Srgrimes	return (0);
21671558Srgrimes}
21681558Srgrimes
21691558Srgrimes/*
21701558Srgrimes * Scan tree for a host that matches the address.
21711558Srgrimes */
21721558Srgrimesint
2173216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr)
21741558Srgrimes{
21759336Sdfr	int defset, hostset;
21761558Srgrimes
21771558Srgrimes	if (dp) {
21781558Srgrimes		if (scan_tree(dp->dp_left, saddr))
21791558Srgrimes			return (1);
2180240902Srmacklem		if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL))
21811558Srgrimes			return (1);
21821558Srgrimes		if (scan_tree(dp->dp_right, saddr))
21831558Srgrimes			return (1);
21841558Srgrimes	}
21851558Srgrimes	return (0);
21861558Srgrimes}
21871558Srgrimes
21881558Srgrimes/*
21891558Srgrimes * Traverse the dirlist tree and free it up.
21901558Srgrimes */
21911558Srgrimesvoid
2192216587Scharnierfree_dir(struct dirlist *dp)
21931558Srgrimes{
21941558Srgrimes
21951558Srgrimes	if (dp) {
21961558Srgrimes		free_dir(dp->dp_left);
21971558Srgrimes		free_dir(dp->dp_right);
21981558Srgrimes		free_host(dp->dp_hosts);
21991558Srgrimes		free((caddr_t)dp);
22001558Srgrimes	}
22011558Srgrimes}
22021558Srgrimes
22031558Srgrimes/*
2204184588Sdfr * Parse a colon separated list of security flavors
2205184588Sdfr */
2206184588Sdfrint
2207216587Scharnierparsesec(char *seclist, struct exportlist *ep)
2208184588Sdfr{
2209184588Sdfr	char *cp, savedc;
2210184588Sdfr	int flavor;
2211184588Sdfr
2212184588Sdfr	ep->ex_numsecflavors = 0;
2213184588Sdfr	for (;;) {
2214184588Sdfr		cp = strchr(seclist, ':');
2215184588Sdfr		if (cp) {
2216184588Sdfr			savedc = *cp;
2217184588Sdfr			*cp = '\0';
2218184588Sdfr		}
2219184588Sdfr
2220184588Sdfr		if (!strcmp(seclist, "sys"))
2221184588Sdfr			flavor = AUTH_SYS;
2222184588Sdfr		else if (!strcmp(seclist, "krb5"))
2223184588Sdfr			flavor = RPCSEC_GSS_KRB5;
2224184588Sdfr		else if (!strcmp(seclist, "krb5i"))
2225184588Sdfr			flavor = RPCSEC_GSS_KRB5I;
2226184588Sdfr		else if (!strcmp(seclist, "krb5p"))
2227184588Sdfr			flavor = RPCSEC_GSS_KRB5P;
2228184588Sdfr		else {
2229184588Sdfr			if (cp)
2230184588Sdfr				*cp = savedc;
2231184588Sdfr			syslog(LOG_ERR, "bad sec flavor: %s", seclist);
2232184588Sdfr			return (1);
2233184588Sdfr		}
2234184588Sdfr		if (ep->ex_numsecflavors == MAXSECFLAVORS) {
2235184588Sdfr			if (cp)
2236184588Sdfr				*cp = savedc;
2237184588Sdfr			syslog(LOG_ERR, "too many sec flavors: %s", seclist);
2238184588Sdfr			return (1);
2239184588Sdfr		}
2240184588Sdfr		ep->ex_secflavors[ep->ex_numsecflavors] = flavor;
2241184588Sdfr		ep->ex_numsecflavors++;
2242184588Sdfr		if (cp) {
2243184588Sdfr			*cp = savedc;
2244184588Sdfr			seclist = cp + 1;
2245184588Sdfr		} else {
2246184588Sdfr			break;
2247184588Sdfr		}
2248184588Sdfr	}
2249184588Sdfr	return (0);
2250184588Sdfr}
2251184588Sdfr
2252184588Sdfr/*
22531558Srgrimes * Parse the option string and update fields.
22541558Srgrimes * Option arguments may either be -<option>=<value> or
22551558Srgrimes * -<option> <value>
22561558Srgrimes */
22571558Srgrimesint
2258216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
2259216587Scharnier	int *has_hostp, int *exflagsp, struct xucred *cr)
22601558Srgrimes{
22611558Srgrimes	char *cpoptarg, *cpoptend;
22621558Srgrimes	char *cp, *endcp, *cpopt, savedc, savedc2;
22631558Srgrimes	int allflag, usedarg;
22641558Srgrimes
226551968Salfred	savedc2 = '\0';
22661558Srgrimes	cpopt = *cpp;
22671558Srgrimes	cpopt++;
22681558Srgrimes	cp = *endcpp;
22691558Srgrimes	savedc = *cp;
22701558Srgrimes	*cp = '\0';
22711558Srgrimes	while (cpopt && *cpopt) {
22721558Srgrimes		allflag = 1;
22731558Srgrimes		usedarg = -2;
227437663Scharnier		if ((cpoptend = strchr(cpopt, ','))) {
22751558Srgrimes			*cpoptend++ = '\0';
227637663Scharnier			if ((cpoptarg = strchr(cpopt, '=')))
22771558Srgrimes				*cpoptarg++ = '\0';
22781558Srgrimes		} else {
227937663Scharnier			if ((cpoptarg = strchr(cpopt, '=')))
22801558Srgrimes				*cpoptarg++ = '\0';
22811558Srgrimes			else {
22821558Srgrimes				*cp = savedc;
22831558Srgrimes				nextfield(&cp, &endcp);
22841558Srgrimes				**endcpp = '\0';
22851558Srgrimes				if (endcp > cp && *cp != '-') {
22861558Srgrimes					cpoptarg = cp;
22871558Srgrimes					savedc2 = *endcp;
22881558Srgrimes					*endcp = '\0';
22891558Srgrimes					usedarg = 0;
22901558Srgrimes				}
22911558Srgrimes			}
22921558Srgrimes		}
22931558Srgrimes		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
22941558Srgrimes			*exflagsp |= MNT_EXRDONLY;
22951558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
22961558Srgrimes		    !(allflag = strcmp(cpopt, "mapall")) ||
22971558Srgrimes		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
22981558Srgrimes			usedarg++;
22991558Srgrimes			parsecred(cpoptarg, cr);
23001558Srgrimes			if (allflag == 0) {
23011558Srgrimes				*exflagsp |= MNT_EXPORTANON;
23021558Srgrimes				opt_flags |= OP_MAPALL;
23031558Srgrimes			} else
23041558Srgrimes				opt_flags |= OP_MAPROOT;
23051558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
230675801Siedowse		    !strcmp(cpopt, "m"))) {
23071558Srgrimes			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
230837663Scharnier				syslog(LOG_ERR, "bad mask: %s", cpoptarg);
23091558Srgrimes				return (1);
23101558Srgrimes			}
23111558Srgrimes			usedarg++;
23121558Srgrimes			opt_flags |= OP_MASK;
23131558Srgrimes		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
23141558Srgrimes			!strcmp(cpopt, "n"))) {
231574462Salfred			if (strchr(cpoptarg, '/') != NULL) {
231674462Salfred				if (debug)
231774462Salfred					fprintf(stderr, "setting OP_MASKLEN\n");
231874462Salfred				opt_flags |= OP_MASKLEN;
231974462Salfred			}
23201558Srgrimes			if (grp->gr_type != GT_NULL) {
232137663Scharnier				syslog(LOG_ERR, "network/host conflict");
23221558Srgrimes				return (1);
23231558Srgrimes			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
232437663Scharnier				syslog(LOG_ERR, "bad net: %s", cpoptarg);
23251558Srgrimes				return (1);
23261558Srgrimes			}
23271558Srgrimes			grp->gr_type = GT_NET;
23281558Srgrimes			*has_hostp = 1;
23291558Srgrimes			usedarg++;
23301558Srgrimes			opt_flags |= OP_NET;
23311558Srgrimes		} else if (!strcmp(cpopt, "alldirs")) {
23321558Srgrimes			opt_flags |= OP_ALLDIRS;
233327447Sdfr		} else if (!strcmp(cpopt, "public")) {
233427447Sdfr			*exflagsp |= MNT_EXPUBLIC;
233527447Sdfr		} else if (!strcmp(cpopt, "webnfs")) {
233627447Sdfr			*exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
233727447Sdfr			opt_flags |= OP_MAPALL;
233827447Sdfr		} else if (cpoptarg && !strcmp(cpopt, "index")) {
233927447Sdfr			ep->ex_indexfile = strdup(cpoptarg);
2340100336Sjoerg		} else if (!strcmp(cpopt, "quiet")) {
2341100336Sjoerg			opt_flags |= OP_QUIET;
2342247034Spluknet		} else if (cpoptarg && !strcmp(cpopt, "sec")) {
2343184588Sdfr			if (parsesec(cpoptarg, ep))
2344184588Sdfr				return (1);
2345184588Sdfr			opt_flags |= OP_SEC;
2346184588Sdfr			usedarg++;
23471558Srgrimes		} else {
234837663Scharnier			syslog(LOG_ERR, "bad opt %s", cpopt);
23491558Srgrimes			return (1);
23501558Srgrimes		}
23511558Srgrimes		if (usedarg >= 0) {
23521558Srgrimes			*endcp = savedc2;
23531558Srgrimes			**endcpp = savedc;
23541558Srgrimes			if (usedarg > 0) {
23551558Srgrimes				*cpp = cp;
23561558Srgrimes				*endcpp = endcp;
23571558Srgrimes			}
23581558Srgrimes			return (0);
23591558Srgrimes		}
23601558Srgrimes		cpopt = cpoptend;
23611558Srgrimes	}
23621558Srgrimes	**endcpp = savedc;
23631558Srgrimes	return (0);
23641558Srgrimes}
23651558Srgrimes
23661558Srgrimes/*
23671558Srgrimes * Translate a character string to the corresponding list of network
23681558Srgrimes * addresses for a hostname.
23691558Srgrimes */
23701558Srgrimesint
2371216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp)
23721558Srgrimes{
23737401Swpaul	struct grouplist *checkgrp;
237475635Siedowse	struct addrinfo *ai, *tai, hints;
237574462Salfred	int ecode;
237674462Salfred	char host[NI_MAXHOST];
23771558Srgrimes
237874462Salfred	if (grp->gr_type != GT_NULL) {
237974462Salfred		syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
23801558Srgrimes		return (1);
23811558Srgrimes	}
238274462Salfred	memset(&hints, 0, sizeof hints);
238374462Salfred	hints.ai_flags = AI_CANONNAME;
238474462Salfred	hints.ai_protocol = IPPROTO_UDP;
238574462Salfred	ecode = getaddrinfo(cp, NULL, &hints, &ai);
238674462Salfred	if (ecode != 0) {
238775635Siedowse		syslog(LOG_ERR,"can't get address info for host %s", cp);
238874462Salfred		return 1;
238974462Salfred	}
239074462Salfred	grp->gr_ptr.gt_addrinfo = ai;
239174462Salfred	while (ai != NULL) {
239274462Salfred		if (ai->ai_canonname == NULL) {
239374462Salfred			if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
2394146187Sume			    sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
239574462Salfred				strlcpy(host, "?", sizeof(host));
239674462Salfred			ai->ai_canonname = strdup(host);
239774462Salfred			ai->ai_flags |= AI_CANONNAME;
239875641Siedowse		}
239974462Salfred		if (debug)
240075635Siedowse			fprintf(stderr, "got host %s\n", ai->ai_canonname);
240175635Siedowse		/*
240275635Siedowse		 * Sanity check: make sure we don't already have an entry
240375635Siedowse		 * for this host in the grouplist.
240475635Siedowse		 */
240575635Siedowse		for (checkgrp = tgrp; checkgrp != NULL;
240675635Siedowse		    checkgrp = checkgrp->gr_next) {
240775635Siedowse			if (checkgrp->gr_type != GT_HOST)
240875635Siedowse				continue;
240975635Siedowse			for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
241075635Siedowse			    tai = tai->ai_next) {
241175801Siedowse				if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
241275635Siedowse					continue;
241375635Siedowse				if (debug)
241475635Siedowse					fprintf(stderr,
241575635Siedowse					    "ignoring duplicate host %s\n",
241675635Siedowse					    ai->ai_canonname);
241775635Siedowse				grp->gr_type = GT_IGNORE;
241875635Siedowse				return (0);
241975635Siedowse			}
242075635Siedowse		}
242174462Salfred		ai = ai->ai_next;
24221558Srgrimes	}
242375635Siedowse	grp->gr_type = GT_HOST;
24241558Srgrimes	return (0);
24251558Srgrimes}
24261558Srgrimes
24271558Srgrimes/*
24281558Srgrimes * Free up an exports list component
24291558Srgrimes */
24301558Srgrimesvoid
2431216587Scharnierfree_exp(struct exportlist *ep)
24321558Srgrimes{
24331558Srgrimes
24341558Srgrimes	if (ep->ex_defdir) {
24351558Srgrimes		free_host(ep->ex_defdir->dp_hosts);
24361558Srgrimes		free((caddr_t)ep->ex_defdir);
24371558Srgrimes	}
24381558Srgrimes	if (ep->ex_fsdir)
24391558Srgrimes		free(ep->ex_fsdir);
244027447Sdfr	if (ep->ex_indexfile)
244127447Sdfr		free(ep->ex_indexfile);
24421558Srgrimes	free_dir(ep->ex_dirl);
24431558Srgrimes	free((caddr_t)ep);
24441558Srgrimes}
24451558Srgrimes
24461558Srgrimes/*
24471558Srgrimes * Free hosts.
24481558Srgrimes */
24491558Srgrimesvoid
2450216587Scharnierfree_host(struct hostlist *hp)
24511558Srgrimes{
24521558Srgrimes	struct hostlist *hp2;
24531558Srgrimes
24541558Srgrimes	while (hp) {
24551558Srgrimes		hp2 = hp;
24561558Srgrimes		hp = hp->ht_next;
24571558Srgrimes		free((caddr_t)hp2);
24581558Srgrimes	}
24591558Srgrimes}
24601558Srgrimes
24611558Srgrimesstruct hostlist *
2462216587Scharnierget_ht(void)
24631558Srgrimes{
24641558Srgrimes	struct hostlist *hp;
24651558Srgrimes
24661558Srgrimes	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
24671558Srgrimes	if (hp == (struct hostlist *)NULL)
24681558Srgrimes		out_of_mem();
24691558Srgrimes	hp->ht_next = (struct hostlist *)NULL;
24709336Sdfr	hp->ht_flag = 0;
24711558Srgrimes	return (hp);
24721558Srgrimes}
24731558Srgrimes
24741558Srgrimes/*
24751558Srgrimes * Out of memory, fatal
24761558Srgrimes */
24771558Srgrimesvoid
2478216587Scharnierout_of_mem(void)
24791558Srgrimes{
24801558Srgrimes
248137663Scharnier	syslog(LOG_ERR, "out of memory");
24821558Srgrimes	exit(2);
24831558Srgrimes}
24841558Srgrimes
24851558Srgrimes/*
2486158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into
24871558Srgrimes * the kernel.
24881558Srgrimes */
24891558Srgrimesint
2490158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
2491158857Srodrigc    struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb)
24921558Srgrimes{
249375841Siedowse	struct statfs fsb1;
249474462Salfred	struct addrinfo *ai;
2495192934Srmacklem	struct export_args ea, *eap;
2496158857Srodrigc	char errmsg[255];
2497158857Srodrigc	char *cp;
24981558Srgrimes	int done;
2499158857Srodrigc	char savedc;
2500158857Srodrigc	struct iovec *iov;
2501184588Sdfr	int i, iovlen;
2502158857Srodrigc	int ret;
2503192934Srmacklem	struct nfsex_args nfsea;
25041558Srgrimes
2505192934Srmacklem	if (run_v4server > 0)
2506192934Srmacklem		eap = &nfsea.export;
2507192934Srmacklem	else
2508192934Srmacklem		eap = &ea;
2509192934Srmacklem
2510158857Srodrigc	cp = NULL;
2511158857Srodrigc	savedc = '\0';
2512158857Srodrigc	iov = NULL;
2513158857Srodrigc	iovlen = 0;
2514158857Srodrigc	ret = 0;
251575801Siedowse
2516192934Srmacklem	bzero(eap, sizeof (struct export_args));
2517158857Srodrigc	bzero(errmsg, sizeof(errmsg));
2518192934Srmacklem	eap->ex_flags = exflags;
2519192934Srmacklem	eap->ex_anon = *anoncrp;
2520192934Srmacklem	eap->ex_indexfile = ep->ex_indexfile;
252175641Siedowse	if (grp->gr_type == GT_HOST)
252274462Salfred		ai = grp->gr_ptr.gt_addrinfo;
252375641Siedowse	else
252475641Siedowse		ai = NULL;
2525192934Srmacklem	eap->ex_numsecflavors = ep->ex_numsecflavors;
2526192934Srmacklem	for (i = 0; i < eap->ex_numsecflavors; i++)
2527192934Srmacklem		eap->ex_secflavors[i] = ep->ex_secflavors[i];
2528192934Srmacklem	if (eap->ex_numsecflavors == 0) {
2529192934Srmacklem		eap->ex_numsecflavors = 1;
2530192934Srmacklem		eap->ex_secflavors[0] = AUTH_SYS;
2531184588Sdfr	}
25321558Srgrimes	done = FALSE;
2533158857Srodrigc
2534192934Srmacklem	if (v4root_phase == 0) {
2535192934Srmacklem		build_iovec(&iov, &iovlen, "fstype", NULL, 0);
2536192934Srmacklem		build_iovec(&iov, &iovlen, "fspath", NULL, 0);
2537192934Srmacklem		build_iovec(&iov, &iovlen, "from", NULL, 0);
2538192934Srmacklem		build_iovec(&iov, &iovlen, "update", NULL, 0);
2539192934Srmacklem		build_iovec(&iov, &iovlen, "export", eap,
2540192934Srmacklem		    sizeof (struct export_args));
2541192934Srmacklem		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
2542192934Srmacklem	}
2543158857Srodrigc
25441558Srgrimes	while (!done) {
25451558Srgrimes		switch (grp->gr_type) {
25461558Srgrimes		case GT_HOST:
254775641Siedowse			if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
254874462Salfred				goto skip;
2549192934Srmacklem			eap->ex_addr = ai->ai_addr;
2550192934Srmacklem			eap->ex_addrlen = ai->ai_addrlen;
2551192934Srmacklem			eap->ex_masklen = 0;
25521558Srgrimes			break;
25531558Srgrimes		case GT_NET:
255475801Siedowse			if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
255574462Salfred			    have_v6 == 0)
255674462Salfred				goto skip;
2557192934Srmacklem			eap->ex_addr =
255875801Siedowse			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
2559192934Srmacklem			eap->ex_addrlen =
2560158857Srodrigc			    ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len;
2561192934Srmacklem			eap->ex_mask =
256275801Siedowse			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
2563192934Srmacklem			eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
25641558Srgrimes			break;
256575641Siedowse		case GT_DEFAULT:
2566192934Srmacklem			eap->ex_addr = NULL;
2567192934Srmacklem			eap->ex_addrlen = 0;
2568192934Srmacklem			eap->ex_mask = NULL;
2569192934Srmacklem			eap->ex_masklen = 0;
257075641Siedowse			break;
25717401Swpaul		case GT_IGNORE:
2572158857Srodrigc			ret = 0;
2573158857Srodrigc			goto error_exit;
25747401Swpaul			break;
25751558Srgrimes		default:
257637663Scharnier			syslog(LOG_ERR, "bad grouptype");
25771558Srgrimes			if (cp)
25781558Srgrimes				*cp = savedc;
2579158857Srodrigc			ret = 1;
2580158857Srodrigc			goto error_exit;
25811558Srgrimes		};
25821558Srgrimes
25831558Srgrimes		/*
2584192934Srmacklem		 * For V4:, use the nfssvc() syscall, instead of mount().
25851558Srgrimes		 */
2586192934Srmacklem		if (v4root_phase == 2) {
2587192934Srmacklem			nfsea.fspec = v4root_dirpath;
2588192934Srmacklem			if (run_v4server > 0 &&
2589192934Srmacklem			    nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) {
2590192934Srmacklem				syslog(LOG_ERR, "Exporting V4: failed");
2591192934Srmacklem				return (2);
2592158857Srodrigc			}
2593192934Srmacklem		} else {
2594192934Srmacklem			/*
2595192934Srmacklem			 * XXX:
2596192934Srmacklem			 * Maybe I should just use the fsb->f_mntonname path
2597192934Srmacklem			 * instead of looping back up the dirp to the mount
2598192934Srmacklem			 * point??
2599192934Srmacklem			 * Also, needs to know how to export all types of local
2600192934Srmacklem			 * exportable filesystems and not just "ufs".
2601192934Srmacklem			 */
2602192934Srmacklem			iov[1].iov_base = fsb->f_fstypename; /* "fstype" */
2603192934Srmacklem			iov[1].iov_len = strlen(fsb->f_fstypename) + 1;
2604192934Srmacklem			iov[3].iov_base = fsb->f_mntonname; /* "fspath" */
2605192934Srmacklem			iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
2606192934Srmacklem			iov[5].iov_base = fsb->f_mntfromname; /* "from" */
2607192934Srmacklem			iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
2608272428Sbdrewery			errmsg[0] = '\0';
2609192934Srmacklem
2610192934Srmacklem			while (nmount(iov, iovlen, fsb->f_flags) < 0) {
2611192934Srmacklem				if (cp)
2612192934Srmacklem					*cp-- = savedc;
2613192934Srmacklem				else
2614192934Srmacklem					cp = dirp + dirplen - 1;
2615192934Srmacklem				if (opt_flags & OP_QUIET) {
2616192934Srmacklem					ret = 1;
2617192934Srmacklem					goto error_exit;
2618192934Srmacklem				}
2619192934Srmacklem				if (errno == EPERM) {
2620192934Srmacklem					if (debug)
2621239744Sdelphij						warnx("can't change attributes for %s: %s",
2622239744Sdelphij						    dirp, errmsg);
2623192934Srmacklem					syslog(LOG_ERR,
2624239744Sdelphij					   "can't change attributes for %s: %s",
2625239744Sdelphij					    dirp, errmsg);
2626192934Srmacklem					ret = 1;
2627192934Srmacklem					goto error_exit;
2628192934Srmacklem				}
2629192934Srmacklem				if (opt_flags & OP_ALLDIRS) {
2630192934Srmacklem					if (errno == EINVAL)
2631192934Srmacklem						syslog(LOG_ERR,
2632100336Sjoerg		"-alldirs requested but %s is not a filesystem mountpoint",
2633192934Srmacklem						    dirp);
2634192934Srmacklem					else
2635192934Srmacklem						syslog(LOG_ERR,
2636192934Srmacklem						    "could not remount %s: %m",
2637192934Srmacklem						    dirp);
2638192934Srmacklem					ret = 1;
2639192934Srmacklem					goto error_exit;
2640192934Srmacklem				}
2641192934Srmacklem				/* back up over the last component */
2642192934Srmacklem				while (*cp == '/' && cp > dirp)
2643192934Srmacklem					cp--;
2644192934Srmacklem				while (*(cp - 1) != '/' && cp > dirp)
2645192934Srmacklem					cp--;
2646192934Srmacklem				if (cp == dirp) {
2647192934Srmacklem					if (debug)
2648192934Srmacklem						warnx("mnt unsucc");
2649192934Srmacklem					syslog(LOG_ERR, "can't export %s %s",
2650192934Srmacklem					    dirp, errmsg);
2651192934Srmacklem					ret = 1;
2652192934Srmacklem					goto error_exit;
2653192934Srmacklem				}
2654192934Srmacklem				savedc = *cp;
2655192934Srmacklem				*cp = '\0';
2656192934Srmacklem				/*
2657192934Srmacklem				 * Check that we're still on the same
2658192934Srmacklem				 * filesystem.
2659192934Srmacklem				 */
2660192934Srmacklem				if (statfs(dirp, &fsb1) != 0 ||
2661192934Srmacklem				    bcmp(&fsb1.f_fsid, &fsb->f_fsid,
2662192934Srmacklem				    sizeof (fsb1.f_fsid)) != 0) {
2663192934Srmacklem					*cp = savedc;
2664100336Sjoerg					syslog(LOG_ERR,
2665192934Srmacklem					    "can't export %s %s", dirp,
2666192934Srmacklem					    errmsg);
2667192934Srmacklem					ret = 1;
2668192934Srmacklem					goto error_exit;
2669192934Srmacklem				}
26701558Srgrimes			}
26711558Srgrimes		}
2672192934Srmacklem
2673192934Srmacklem		/*
2674192934Srmacklem		 * For the experimental server:
2675192934Srmacklem		 * If this is the public directory, get the file handle
2676192934Srmacklem		 * and load it into the kernel via the nfssvc() syscall.
2677192934Srmacklem		 */
2678192934Srmacklem		if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) {
2679192934Srmacklem			fhandle_t fh;
2680192934Srmacklem			char *public_name;
2681192934Srmacklem
2682192934Srmacklem			if (eap->ex_indexfile != NULL)
2683192934Srmacklem				public_name = eap->ex_indexfile;
2684192934Srmacklem			else
2685192934Srmacklem				public_name = dirp;
2686192934Srmacklem			if (getfh(public_name, &fh) < 0)
2687192934Srmacklem				syslog(LOG_ERR,
2688192934Srmacklem				    "Can't get public fh for %s", public_name);
2689192934Srmacklem			else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
2690192934Srmacklem				syslog(LOG_ERR,
2691192934Srmacklem				    "Can't set public fh for %s", public_name);
2692192934Srmacklem			else
2693192934Srmacklem				has_publicfh = 1;
2694192934Srmacklem		}
269574462Salfredskip:
269675641Siedowse		if (ai != NULL)
269774462Salfred			ai = ai->ai_next;
269875641Siedowse		if (ai == NULL)
26991558Srgrimes			done = TRUE;
27001558Srgrimes	}
27011558Srgrimes	if (cp)
27021558Srgrimes		*cp = savedc;
2703158857Srodrigcerror_exit:
2704158857Srodrigc	/* free strings allocated by strdup() in getmntopts.c */
2705158857Srodrigc	if (iov != NULL) {
2706158857Srodrigc		free(iov[0].iov_base); /* fstype */
2707158857Srodrigc		free(iov[2].iov_base); /* fspath */
2708158857Srodrigc		free(iov[4].iov_base); /* from */
2709158857Srodrigc		free(iov[6].iov_base); /* update */
2710158857Srodrigc		free(iov[8].iov_base); /* export */
2711158857Srodrigc		free(iov[10].iov_base); /* errmsg */
2712158857Srodrigc
2713158857Srodrigc		/* free iov, allocated by realloc() */
2714158857Srodrigc		free(iov);
2715158857Srodrigc	}
2716158857Srodrigc	return (ret);
27171558Srgrimes}
27181558Srgrimes
27191558Srgrimes/*
27201558Srgrimes * Translate a net address.
272175801Siedowse *
272275801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
27231558Srgrimes */
27241558Srgrimesint
2725216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg)
27261558Srgrimes{
272775861Siedowse	struct netent *np = NULL;
272874462Salfred	char *name, *p, *prefp;
272975801Siedowse	struct sockaddr_in sin;
273075861Siedowse	struct sockaddr *sa = NULL;
273174462Salfred	struct addrinfo hints, *ai = NULL;
273274462Salfred	char netname[NI_MAXHOST];
273374462Salfred	long preflen;
27341558Srgrimes
273575635Siedowse	p = prefp = NULL;
273674462Salfred	if ((opt_flags & OP_MASKLEN) && !maskflg) {
273774462Salfred		p = strchr(cp, '/');
273874462Salfred		*p = '\0';
273974462Salfred		prefp = p + 1;
274074462Salfred	}
274174462Salfred
274275861Siedowse	/*
274375861Siedowse	 * Check for a numeric address first. We wish to avoid
274475861Siedowse	 * possible DNS lookups in getnetbyname().
274575861Siedowse	 */
274675861Siedowse	if (isxdigit(*cp) || *cp == ':') {
274774462Salfred		memset(&hints, 0, sizeof hints);
274875801Siedowse		/* Ensure the mask and the network have the same family. */
274975801Siedowse		if (maskflg && (opt_flags & OP_NET))
275075801Siedowse			hints.ai_family = net->nt_net.ss_family;
275175801Siedowse		else if (!maskflg && (opt_flags & OP_HAVEMASK))
275275801Siedowse			hints.ai_family = net->nt_mask.ss_family;
275375801Siedowse		else
275475801Siedowse			hints.ai_family = AF_UNSPEC;
275574462Salfred		hints.ai_flags = AI_NUMERICHOST;
275675861Siedowse		if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
275775861Siedowse			sa = ai->ai_addr;
275875861Siedowse		if (sa != NULL && ai->ai_family == AF_INET) {
275974462Salfred			/*
276075801Siedowse			 * The address in `cp' is really a network address, so
276175801Siedowse			 * use inet_network() to re-interpret this correctly.
276275801Siedowse			 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
276374462Salfred			 */
276475801Siedowse			bzero(&sin, sizeof sin);
276574462Salfred			sin.sin_family = AF_INET;
276674462Salfred			sin.sin_len = sizeof sin;
276775801Siedowse			sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
276874462Salfred			if (debug)
276975801Siedowse				fprintf(stderr, "get_net: v4 addr %s\n",
277075801Siedowse				    inet_ntoa(sin.sin_addr));
277174462Salfred			sa = (struct sockaddr *)&sin;
277275861Siedowse		}
277375861Siedowse	}
277475861Siedowse	if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
277575861Siedowse		bzero(&sin, sizeof sin);
277675861Siedowse		sin.sin_family = AF_INET;
277775861Siedowse		sin.sin_len = sizeof sin;
277875861Siedowse		sin.sin_addr = inet_makeaddr(np->n_net, 0);
277975861Siedowse		sa = (struct sockaddr *)&sin;
278075861Siedowse	}
278175861Siedowse	if (sa == NULL)
278274462Salfred		goto fail;
278325318Spst
278475801Siedowse	if (maskflg) {
278575801Siedowse		/* The specified sockaddr is a mask. */
278675801Siedowse		if (checkmask(sa) != 0)
278775801Siedowse			goto fail;
278875801Siedowse		bcopy(sa, &net->nt_mask, sa->sa_len);
278975801Siedowse		opt_flags |= OP_HAVEMASK;
279075801Siedowse	} else {
279175801Siedowse		/* The specified sockaddr is a network address. */
279275801Siedowse		bcopy(sa, &net->nt_net, sa->sa_len);
279374462Salfred
279475801Siedowse		/* Get a network name for the export list. */
279575801Siedowse		if (np) {
279675801Siedowse			name = np->n_name;
279775801Siedowse		} else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
2798146187Sume		   NULL, 0, NI_NUMERICHOST) == 0) {
279975801Siedowse			name = netname;
280075801Siedowse		} else {
280175801Siedowse			goto fail;
280275801Siedowse		}
280375801Siedowse		if ((net->nt_name = strdup(name)) == NULL)
280475801Siedowse			out_of_mem();
280575801Siedowse
280675801Siedowse		/*
280775801Siedowse		 * Extract a mask from either a "/<masklen>" suffix, or
280875801Siedowse		 * from the class of an IPv4 address.
280975801Siedowse		 */
281074462Salfred		if (opt_flags & OP_MASKLEN) {
281174462Salfred			preflen = strtol(prefp, NULL, 10);
281275801Siedowse			if (preflen < 0L || preflen == LONG_MAX)
281374462Salfred				goto fail;
281475801Siedowse			bcopy(sa, &net->nt_mask, sa->sa_len);
281575801Siedowse			if (makemask(&net->nt_mask, (int)preflen) != 0)
281675801Siedowse				goto fail;
281775801Siedowse			opt_flags |= OP_HAVEMASK;
281874462Salfred			*p = '/';
281975801Siedowse		} else if (sa->sa_family == AF_INET &&
282075801Siedowse		    (opt_flags & OP_MASK) == 0) {
282175801Siedowse			in_addr_t addr;
282274462Salfred
282375801Siedowse			addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
282475801Siedowse			if (IN_CLASSA(addr))
282575801Siedowse				preflen = 8;
282675801Siedowse			else if (IN_CLASSB(addr))
282775801Siedowse				preflen = 16;
282875801Siedowse			else if (IN_CLASSC(addr))
282975801Siedowse				preflen = 24;
283075801Siedowse			else if (IN_CLASSD(addr))
283175801Siedowse				preflen = 28;
283275801Siedowse			else
283375801Siedowse				preflen = 32;	/* XXX */
283475801Siedowse
283575801Siedowse			bcopy(sa, &net->nt_mask, sa->sa_len);
283675801Siedowse			makemask(&net->nt_mask, (int)preflen);
283775801Siedowse			opt_flags |= OP_HAVEMASK;
283874462Salfred		}
283974462Salfred	}
284074462Salfred
284174462Salfred	if (ai)
284274462Salfred		freeaddrinfo(ai);
284374462Salfred	return 0;
284474462Salfred
284574462Salfredfail:
284674462Salfred	if (ai)
284774462Salfred		freeaddrinfo(ai);
284874462Salfred	return 1;
28491558Srgrimes}
28501558Srgrimes
28511558Srgrimes/*
28521558Srgrimes * Parse out the next white space separated field
28531558Srgrimes */
28541558Srgrimesvoid
2855216587Scharniernextfield(char **cp, char **endcp)
28561558Srgrimes{
28571558Srgrimes	char *p;
28581558Srgrimes
28591558Srgrimes	p = *cp;
28601558Srgrimes	while (*p == ' ' || *p == '\t')
28611558Srgrimes		p++;
28621558Srgrimes	if (*p == '\n' || *p == '\0')
28631558Srgrimes		*cp = *endcp = p;
28641558Srgrimes	else {
28651558Srgrimes		*cp = p++;
28661558Srgrimes		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
28671558Srgrimes			p++;
28681558Srgrimes		*endcp = p;
28691558Srgrimes	}
28701558Srgrimes}
28711558Srgrimes
28721558Srgrimes/*
28731558Srgrimes * Get an exports file line. Skip over blank lines and handle line
28741558Srgrimes * continuations.
28751558Srgrimes */
28761558Srgrimesint
2877216587Scharnierget_line(void)
28781558Srgrimes{
28791558Srgrimes	char *p, *cp;
288096622Siedowse	size_t len;
28811558Srgrimes	int totlen, cont_line;
28821558Srgrimes
28831558Srgrimes	/*
28841558Srgrimes	 * Loop around ignoring blank lines and getting all continuation lines.
28851558Srgrimes	 */
28861558Srgrimes	p = line;
28871558Srgrimes	totlen = 0;
28881558Srgrimes	do {
288996622Siedowse		if ((p = fgetln(exp_file, &len)) == NULL)
28901558Srgrimes			return (0);
28911558Srgrimes		cp = p + len - 1;
28921558Srgrimes		cont_line = 0;
28931558Srgrimes		while (cp >= p &&
28941558Srgrimes		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
28951558Srgrimes			if (*cp == '\\')
28961558Srgrimes				cont_line = 1;
28971558Srgrimes			cp--;
28981558Srgrimes			len--;
28991558Srgrimes		}
290079117Sdd		if (cont_line) {
290179117Sdd			*++cp = ' ';
290279117Sdd			len++;
290379117Sdd		}
290496622Siedowse		if (linesize < len + totlen + 1) {
290596622Siedowse			linesize = len + totlen + 1;
290696622Siedowse			line = realloc(line, linesize);
290796622Siedowse			if (line == NULL)
290896622Siedowse				out_of_mem();
29091558Srgrimes		}
291096622Siedowse		memcpy(line + totlen, p, len);
291196622Siedowse		totlen += len;
291296622Siedowse		line[totlen] = '\0';
29131558Srgrimes	} while (totlen == 0 || cont_line);
29141558Srgrimes	return (1);
29151558Srgrimes}
29161558Srgrimes
29171558Srgrimes/*
29181558Srgrimes * Parse a description of a credential.
29191558Srgrimes */
29201558Srgrimesvoid
2921216587Scharnierparsecred(char *namelist, struct xucred *cr)
29221558Srgrimes{
29231558Srgrimes	char *name;
29241558Srgrimes	int cnt;
29251558Srgrimes	char *names;
29261558Srgrimes	struct passwd *pw;
29271558Srgrimes	struct group *gr;
2928194498Sbrooks	gid_t groups[XU_NGROUPS + 1];
2929136051Sstefanf	int ngroups;
29301558Srgrimes
293191354Sdd	cr->cr_version = XUCRED_VERSION;
29321558Srgrimes	/*
293337663Scharnier	 * Set up the unprivileged user.
29341558Srgrimes	 */
29351558Srgrimes	cr->cr_uid = -2;
29361558Srgrimes	cr->cr_groups[0] = -2;
29371558Srgrimes	cr->cr_ngroups = 1;
29381558Srgrimes	/*
29391558Srgrimes	 * Get the user's password table entry.
29401558Srgrimes	 */
2941294124Sjpaetzel	names = strsep_quote(&namelist, " \t\n");
29421558Srgrimes	name = strsep(&names, ":");
2943294124Sjpaetzel	/* Bug?  name could be NULL here */
29441558Srgrimes	if (isdigit(*name) || *name == '-')
29451558Srgrimes		pw = getpwuid(atoi(name));
29461558Srgrimes	else
29471558Srgrimes		pw = getpwnam(name);
29481558Srgrimes	/*
29491558Srgrimes	 * Credentials specified as those of a user.
29501558Srgrimes	 */
29511558Srgrimes	if (names == NULL) {
29521558Srgrimes		if (pw == NULL) {
295337663Scharnier			syslog(LOG_ERR, "unknown user: %s", name);
29541558Srgrimes			return;
29551558Srgrimes		}
29561558Srgrimes		cr->cr_uid = pw->pw_uid;
2957194498Sbrooks		ngroups = XU_NGROUPS + 1;
2958333198Savg		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) {
295937663Scharnier			syslog(LOG_ERR, "too many groups");
2960333198Savg			ngroups = XU_NGROUPS + 1;
2961333198Savg		}
2962333198Savg
29631558Srgrimes		/*
2964136051Sstefanf		 * Compress out duplicate.
29651558Srgrimes		 */
29661558Srgrimes		cr->cr_ngroups = ngroups - 1;
29671558Srgrimes		cr->cr_groups[0] = groups[0];
29681558Srgrimes		for (cnt = 2; cnt < ngroups; cnt++)
29691558Srgrimes			cr->cr_groups[cnt - 1] = groups[cnt];
29701558Srgrimes		return;
29711558Srgrimes	}
29721558Srgrimes	/*
29731558Srgrimes	 * Explicit credential specified as a colon separated list:
29741558Srgrimes	 *	uid:gid:gid:...
29751558Srgrimes	 */
29761558Srgrimes	if (pw != NULL)
29771558Srgrimes		cr->cr_uid = pw->pw_uid;
29781558Srgrimes	else if (isdigit(*name) || *name == '-')
29791558Srgrimes		cr->cr_uid = atoi(name);
29801558Srgrimes	else {
298137663Scharnier		syslog(LOG_ERR, "unknown user: %s", name);
29821558Srgrimes		return;
29831558Srgrimes	}
29841558Srgrimes	cr->cr_ngroups = 0;
2985194498Sbrooks	while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) {
29861558Srgrimes		name = strsep(&names, ":");
29871558Srgrimes		if (isdigit(*name) || *name == '-') {
29881558Srgrimes			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
29891558Srgrimes		} else {
29901558Srgrimes			if ((gr = getgrnam(name)) == NULL) {
299137663Scharnier				syslog(LOG_ERR, "unknown group: %s", name);
29921558Srgrimes				continue;
29931558Srgrimes			}
29941558Srgrimes			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
29951558Srgrimes		}
29961558Srgrimes	}
2997194498Sbrooks	if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS)
299837663Scharnier		syslog(LOG_ERR, "too many groups");
29991558Srgrimes}
30001558Srgrimes
3001194880Sdfr#define	STRSIZ	(MNTNAMLEN+MNTPATHLEN+50)
30021558Srgrimes/*
30031558Srgrimes * Routines that maintain the remote mounttab
30041558Srgrimes */
30051558Srgrimesvoid
3006216587Scharnierget_mountlist(void)
30071558Srgrimes{
30081558Srgrimes	struct mountlist *mlp, **mlpp;
300923681Speter	char *host, *dirp, *cp;
30101558Srgrimes	char str[STRSIZ];
30111558Srgrimes	FILE *mlfile;
30121558Srgrimes
30131558Srgrimes	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
301453117Sbillf		if (errno == ENOENT)
301553117Sbillf			return;
301653117Sbillf		else {
301753117Sbillf			syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
301853117Sbillf			return;
301953117Sbillf		}
30201558Srgrimes	}
30211558Srgrimes	mlpp = &mlhead;
30221558Srgrimes	while (fgets(str, STRSIZ, mlfile) != NULL) {
302323681Speter		cp = str;
302423681Speter		host = strsep(&cp, " \t\n");
302523681Speter		dirp = strsep(&cp, " \t\n");
302623681Speter		if (host == NULL || dirp == NULL)
30271558Srgrimes			continue;
30281558Srgrimes		mlp = (struct mountlist *)malloc(sizeof (*mlp));
302937663Scharnier		if (mlp == (struct mountlist *)NULL)
303037663Scharnier			out_of_mem();
3031194880Sdfr		strncpy(mlp->ml_host, host, MNTNAMLEN);
3032194880Sdfr		mlp->ml_host[MNTNAMLEN] = '\0';
3033194880Sdfr		strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
3034194880Sdfr		mlp->ml_dirp[MNTPATHLEN] = '\0';
30351558Srgrimes		mlp->ml_next = (struct mountlist *)NULL;
30361558Srgrimes		*mlpp = mlp;
30371558Srgrimes		mlpp = &mlp->ml_next;
30381558Srgrimes	}
30391558Srgrimes	fclose(mlfile);
30401558Srgrimes}
30411558Srgrimes
304275635Siedowsevoid
304375635Siedowsedel_mlist(char *hostp, char *dirp)
30441558Srgrimes{
30451558Srgrimes	struct mountlist *mlp, **mlpp;
30461558Srgrimes	struct mountlist *mlp2;
30471558Srgrimes	FILE *mlfile;
30481558Srgrimes	int fnd = 0;
30491558Srgrimes
30501558Srgrimes	mlpp = &mlhead;
30511558Srgrimes	mlp = mlhead;
30521558Srgrimes	while (mlp) {
30531558Srgrimes		if (!strcmp(mlp->ml_host, hostp) &&
30541558Srgrimes		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
30551558Srgrimes			fnd = 1;
30561558Srgrimes			mlp2 = mlp;
30571558Srgrimes			*mlpp = mlp = mlp->ml_next;
30581558Srgrimes			free((caddr_t)mlp2);
30591558Srgrimes		} else {
30601558Srgrimes			mlpp = &mlp->ml_next;
30611558Srgrimes			mlp = mlp->ml_next;
30621558Srgrimes		}
30631558Srgrimes	}
30641558Srgrimes	if (fnd) {
30651558Srgrimes		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
306637663Scharnier			syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
30671558Srgrimes			return;
30681558Srgrimes		}
30691558Srgrimes		mlp = mlhead;
30701558Srgrimes		while (mlp) {
30711558Srgrimes			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
30721558Srgrimes			mlp = mlp->ml_next;
30731558Srgrimes		}
30741558Srgrimes		fclose(mlfile);
30751558Srgrimes	}
30761558Srgrimes}
30771558Srgrimes
30781558Srgrimesvoid
3079216587Scharnieradd_mlist(char *hostp, char *dirp)
30801558Srgrimes{
30811558Srgrimes	struct mountlist *mlp, **mlpp;
30821558Srgrimes	FILE *mlfile;
30831558Srgrimes
30841558Srgrimes	mlpp = &mlhead;
30851558Srgrimes	mlp = mlhead;
30861558Srgrimes	while (mlp) {
30871558Srgrimes		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
30881558Srgrimes			return;
30891558Srgrimes		mlpp = &mlp->ml_next;
30901558Srgrimes		mlp = mlp->ml_next;
30911558Srgrimes	}
30921558Srgrimes	mlp = (struct mountlist *)malloc(sizeof (*mlp));
309337663Scharnier	if (mlp == (struct mountlist *)NULL)
309437663Scharnier		out_of_mem();
3095194880Sdfr	strncpy(mlp->ml_host, hostp, MNTNAMLEN);
3096194880Sdfr	mlp->ml_host[MNTNAMLEN] = '\0';
3097194880Sdfr	strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
3098194880Sdfr	mlp->ml_dirp[MNTPATHLEN] = '\0';
30991558Srgrimes	mlp->ml_next = (struct mountlist *)NULL;
31001558Srgrimes	*mlpp = mlp;
31011558Srgrimes	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
310237663Scharnier		syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
31031558Srgrimes		return;
31041558Srgrimes	}
31051558Srgrimes	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
31061558Srgrimes	fclose(mlfile);
31071558Srgrimes}
31081558Srgrimes
31091558Srgrimes/*
31101558Srgrimes * Free up a group list.
31111558Srgrimes */
31121558Srgrimesvoid
3113216587Scharnierfree_grp(struct grouplist *grp)
31141558Srgrimes{
31151558Srgrimes	if (grp->gr_type == GT_HOST) {
311674462Salfred		if (grp->gr_ptr.gt_addrinfo != NULL)
311774462Salfred			freeaddrinfo(grp->gr_ptr.gt_addrinfo);
31181558Srgrimes	} else if (grp->gr_type == GT_NET) {
31191558Srgrimes		if (grp->gr_ptr.gt_net.nt_name)
31201558Srgrimes			free(grp->gr_ptr.gt_net.nt_name);
31211558Srgrimes	}
31221558Srgrimes	free((caddr_t)grp);
31231558Srgrimes}
31241558Srgrimes
31251558Srgrimes#ifdef DEBUG
31261558Srgrimesvoid
31271558SrgrimesSYSLOG(int pri, const char *fmt, ...)
31281558Srgrimes{
31291558Srgrimes	va_list ap;
31301558Srgrimes
31311558Srgrimes	va_start(ap, fmt);
31321558Srgrimes	vfprintf(stderr, fmt, ap);
31331558Srgrimes	va_end(ap);
31341558Srgrimes}
31351558Srgrimes#endif /* DEBUG */
31361558Srgrimes
31371558Srgrimes/*
31381558Srgrimes * Check options for consistency.
31391558Srgrimes */
31401558Srgrimesint
3141216587Scharniercheck_options(struct dirlist *dp)
31421558Srgrimes{
31431558Srgrimes
3144192934Srmacklem	if (v4root_phase == 0 && dp == NULL)
31451558Srgrimes	    return (1);
314683653Speter	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
314783653Speter	    syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
31481558Srgrimes	    return (1);
31491558Srgrimes	}
31501558Srgrimes	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
315175801Siedowse		syslog(LOG_ERR, "-mask requires -network");
315275801Siedowse		return (1);
31531558Srgrimes	}
315475801Siedowse	if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
315575801Siedowse		syslog(LOG_ERR, "-network requires mask specification");
315675801Siedowse		return (1);
315775801Siedowse	}
315875801Siedowse	if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
315975801Siedowse		syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
316075801Siedowse		return (1);
316175801Siedowse	}
3162192934Srmacklem	if (v4root_phase > 0 &&
3163192934Srmacklem	    (opt_flags &
3164192934Srmacklem	     ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) {
3165192934Srmacklem	    syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:");
3166192934Srmacklem	    return (1);
3167192934Srmacklem	}
3168207689Srmacklem	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
3169207689Srmacklem	    syslog(LOG_ERR, "-alldirs has multiple directories");
3170207689Srmacklem	    return (1);
3171207689Srmacklem	}
31721558Srgrimes	return (0);
31731558Srgrimes}
31741558Srgrimes
31751558Srgrimes/*
31761558Srgrimes * Check an absolute directory path for any symbolic links. Return true
31771558Srgrimes */
31781558Srgrimesint
3179216587Scharniercheck_dirpath(char *dirp)
31801558Srgrimes{
31811558Srgrimes	char *cp;
31821558Srgrimes	int ret = 1;
31831558Srgrimes	struct stat sb;
31841558Srgrimes
31851558Srgrimes	cp = dirp + 1;
31861558Srgrimes	while (*cp && ret) {
31871558Srgrimes		if (*cp == '/') {
31881558Srgrimes			*cp = '\0';
31899336Sdfr			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
31901558Srgrimes				ret = 0;
31911558Srgrimes			*cp = '/';
31921558Srgrimes		}
31931558Srgrimes		cp++;
31941558Srgrimes	}
31959336Sdfr	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
31961558Srgrimes		ret = 0;
31971558Srgrimes	return (ret);
31981558Srgrimes}
31999336Sdfr
320075801Siedowse/*
320175801Siedowse * Make a netmask according to the specified prefix length. The ss_family
320275801Siedowse * and other non-address fields must be initialised before calling this.
320375801Siedowse */
320475801Siedowseint
320575801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen)
320674462Salfred{
320775801Siedowse	u_char *p;
320875801Siedowse	int bits, i, len;
320974462Salfred
321075801Siedowse	if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
321175801Siedowse		return (-1);
3212103949Smike	if (bitlen > len * CHAR_BIT)
321375801Siedowse		return (-1);
321474462Salfred
321575801Siedowse	for (i = 0; i < len; i++) {
3216103949Smike		bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen;
3217219125Sru		*p++ = (u_char)~0 << (CHAR_BIT - bits);
321875801Siedowse		bitlen -= bits;
321974462Salfred	}
322075801Siedowse	return 0;
322174462Salfred}
322274462Salfred
322375801Siedowse/*
322475801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask
322575801Siedowse * is acceptable (i.e. of the form 1...10....0).
322675801Siedowse */
322775801Siedowseint
322875801Siedowsecheckmask(struct sockaddr *sa)
322974462Salfred{
323075801Siedowse	u_char *mask;
323175801Siedowse	int i, len;
323274462Salfred
323375801Siedowse	if ((mask = sa_rawaddr(sa, &len)) == NULL)
323475801Siedowse		return (-1);
323575801Siedowse
323675801Siedowse	for (i = 0; i < len; i++)
323775801Siedowse		if (mask[i] != 0xff)
323875801Siedowse			break;
323975801Siedowse	if (i < len) {
324075801Siedowse		if (~mask[i] & (u_char)(~mask[i] + 1))
324175801Siedowse			return (-1);
324275801Siedowse		i++;
324374462Salfred	}
324475801Siedowse	for (; i < len; i++)
324575801Siedowse		if (mask[i] != 0)
324675801Siedowse			return (-1);
324775801Siedowse	return (0);
324874462Salfred}
324974462Salfred
325075801Siedowse/*
325175801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if
325275801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'.
3253228990Suqs * If samask is NULL, perform a full comparison.
325475801Siedowse */
325575801Siedowseint
325675801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
325774462Salfred{
325875801Siedowse	unsigned char *p1, *p2, *mask;
325975801Siedowse	int len, i;
326074462Salfred
326175801Siedowse	if (sa1->sa_family != sa2->sa_family ||
326275801Siedowse	    (p1 = sa_rawaddr(sa1, &len)) == NULL ||
326375801Siedowse	    (p2 = sa_rawaddr(sa2, NULL)) == NULL)
326475801Siedowse		return (1);
326575801Siedowse
326675801Siedowse	switch (sa1->sa_family) {
326774462Salfred	case AF_INET6:
326875801Siedowse		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
326975801Siedowse		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
327075801Siedowse			return (1);
327174462Salfred		break;
327274462Salfred	}
327374462Salfred
327475801Siedowse	/* Simple binary comparison if no mask specified. */
327575801Siedowse	if (samask == NULL)
327675801Siedowse		return (memcmp(p1, p2, len));
327774462Salfred
327875801Siedowse	/* Set up the mask, and do a mask-based comparison. */
327975801Siedowse	if (sa1->sa_family != samask->sa_family ||
328075801Siedowse	    (mask = sa_rawaddr(samask, NULL)) == NULL)
328175801Siedowse		return (1);
328274462Salfred
328375801Siedowse	for (i = 0; i < len; i++)
328475801Siedowse		if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
328575801Siedowse			return (1);
328675801Siedowse	return (0);
328774462Salfred}
328874462Salfred
328975801Siedowse/*
329075801Siedowse * Return a pointer to the part of the sockaddr that contains the
329175801Siedowse * raw address, and set *nbytes to its length in bytes. Returns
329275801Siedowse * NULL if the address family is unknown.
329375801Siedowse */
329475801Siedowsevoid *
329575801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) {
329675801Siedowse	void *p;
329774462Salfred	int len;
329874462Salfred
329975801Siedowse	switch (sa->sa_family) {
330074462Salfred	case AF_INET:
330175801Siedowse		len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
330275801Siedowse		p = &((struct sockaddr_in *)sa)->sin_addr;
330374462Salfred		break;
330474462Salfred	case AF_INET6:
330575801Siedowse		len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
330675801Siedowse		p = &((struct sockaddr_in6 *)sa)->sin6_addr;
330774462Salfred		break;
330874462Salfred	default:
330975801Siedowse		p = NULL;
331075801Siedowse		len = 0;
331174462Salfred	}
331274462Salfred
331375801Siedowse	if (nbytes != NULL)
331475801Siedowse		*nbytes = len;
331575801Siedowse	return (p);
331674462Salfred}
331774462Salfred
331875754Siedowsevoid
3319216587Scharnierhuphandler(int sig __unused)
332075754Siedowse{
332175754Siedowse	got_sighup = 1;
332275754Siedowse}
332375754Siedowse
3324216587Scharniervoid terminate(int sig __unused)
332574462Salfred{
3326149433Spjd	pidfile_remove(pfh);
3327194880Sdfr	rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
3328194880Sdfr	rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
332974462Salfred	exit (0);
333074462Salfred}
3331192934Srmacklem
3332