1872b698pfg/*-
2872b698pfg * SPDX-License-Identifier: BSD-3-Clause
3872b698pfg *
4cfcc93ergrimes * Copyright (c) 1989, 1993
5cfcc93ergrimes *	The Regents of the University of California.  All rights reserved.
6cfcc93ergrimes *
7cfcc93ergrimes * This code is derived from software contributed to Berkeley by
8cfcc93ergrimes * Herb Hasler and Rick Macklem at The University of Guelph.
9cfcc93ergrimes *
10cfcc93ergrimes * Redistribution and use in source and binary forms, with or without
11cfcc93ergrimes * modification, are permitted provided that the following conditions
12cfcc93ergrimes * are met:
13cfcc93ergrimes * 1. Redistributions of source code must retain the above copyright
14cfcc93ergrimes *    notice, this list of conditions and the following disclaimer.
15cfcc93ergrimes * 2. Redistributions in binary form must reproduce the above copyright
16cfcc93ergrimes *    notice, this list of conditions and the following disclaimer in the
17cfcc93ergrimes *    documentation and/or other materials provided with the distribution.
187e6cabdimp * 3. Neither the name of the University nor the names of its contributors
19cfcc93ergrimes *    may be used to endorse or promote products derived from this software
20cfcc93ergrimes *    without specific prior written permission.
21cfcc93ergrimes *
22cfcc93ergrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23cfcc93ergrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24cfcc93ergrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25cfcc93ergrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26cfcc93ergrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27cfcc93ergrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28cfcc93ergrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29cfcc93ergrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30cfcc93ergrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31cfcc93ergrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32cfcc93ergrimes * SUCH DAMAGE.
33cfcc93ergrimes */
34cfcc93ergrimes
35cfcc93ergrimes#ifndef lint
36118387fcharnierstatic const char copyright[] =
37cfcc93ergrimes"@(#) Copyright (c) 1989, 1993\n\
38cfcc93ergrimes	The Regents of the University of California.  All rights reserved.\n";
39eeef795wollman#endif /*not lint*/
40cfcc93ergrimes
41118387fcharnier#if 0
42de3f4fbcharnier#ifndef lint
43118387fcharnierstatic char sccsid[] = "@(#)mountd.c	8.15 (Berkeley) 5/1/95";
44eeef795wollman#endif /*not lint*/
45de3f4fbcharnier#endif
46de3f4fbcharnier
47de3f4fbcharnier#include <sys/cdefs.h>
48de3f4fbcharnier__FBSDID("$FreeBSD$");
49cfcc93ergrimes
50cfcc93ergrimes#include <sys/param.h>
51f67e4a8alfred#include <sys/fcntl.h>
5266fe452rmacklem#include <sys/fnv_hash.h>
5336cd292iedowse#include <sys/linker.h>
5436cd292iedowse#include <sys/module.h>
558ca86cdrmacklem#include <sys/mount.h>
56bc78dacmanu#include <sys/queue.h>
578ca86cdrmacklem#include <sys/stat.h>
588ca86cdrmacklem#include <sys/sysctl.h>
598ca86cdrmacklem#include <sys/syslog.h>
60cfcc93ergrimes
61cfcc93ergrimes#include <rpc/rpc.h>
62f4b7d59mbr#include <rpc/rpc_com.h>
63cfcc93ergrimes#include <rpc/pmap_clnt.h>
64f67e4a8alfred#include <rpc/pmap_prot.h>
65f67e4a8alfred#include <rpcsvc/mount.h>
66666343fdfr#include <nfs/nfsproto.h>
678ca86cdrmacklem#include <nfs/nfssvc.h>
6868a5e33peter#include <nfsserver/nfs.h>
69cfcc93ergrimes
708ca86cdrmacklem#include <fs/nfs/nfsport.h>
718ca86cdrmacklem
72cfcc93ergrimes#include <arpa/inet.h>
73cfcc93ergrimes
74cfcc93ergrimes#include <ctype.h>
75118387fcharnier#include <err.h>
76cfcc93ergrimes#include <errno.h>
77cfcc93ergrimes#include <grp.h>
78a834e26pjd#include <libutil.h>
7986a758emike#include <limits.h>
80cfcc93ergrimes#include <netdb.h>
81cfcc93ergrimes#include <pwd.h>
82cfcc93ergrimes#include <signal.h>
83cfcc93ergrimes#include <stdio.h>
84cfcc93ergrimes#include <stdlib.h>
85cfcc93ergrimes#include <string.h>
86cfcc93ergrimes#include <unistd.h>
87cfcc93ergrimes#include "pathnames.h"
8804be51frodrigc#include "mntopts.h"
89cfcc93ergrimes
90cfcc93ergrimes#ifdef DEBUG
91cfcc93ergrimes#include <stdarg.h>
92cfcc93ergrimes#endif
93cfcc93ergrimes
94cfcc93ergrimes/*
95cfcc93ergrimes * Structures for keeping the mount list and export list
96cfcc93ergrimes */
97cfcc93ergrimesstruct mountlist {
98ec9ddecdfr	char	ml_host[MNTNAMLEN+1];
99ec9ddecdfr	char	ml_dirp[MNTPATHLEN+1];
1004dde448manu
1014dde448manu	SLIST_ENTRY(mountlist)	next;
102cfcc93ergrimes};
103cfcc93ergrimes
104cfcc93ergrimesstruct dirlist {
105cfcc93ergrimes	struct dirlist	*dp_left;
106cfcc93ergrimes	struct dirlist	*dp_right;
107cfcc93ergrimes	int		dp_flag;
108cfcc93ergrimes	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
109b5f772emanu	char		*dp_dirp;
110cfcc93ergrimes};
111cfcc93ergrimes/* dp_flag bits */
112cfcc93ergrimes#define	DP_DEFSET	0x1
113666343fdfr#define DP_HOSTSET	0x2
114cfcc93ergrimes
115cfcc93ergrimesstruct exportlist {
116cfcc93ergrimes	struct dirlist	*ex_dirl;
117cfcc93ergrimes	struct dirlist	*ex_defdir;
1181d91d4brmacklem	struct grouplist *ex_grphead;
119cfcc93ergrimes	int		ex_flag;
120cfcc93ergrimes	fsid_t		ex_fs;
121cfcc93ergrimes	char		*ex_fsdir;
1224acc83bdfr	char		*ex_indexfile;
1232b3f398rmacklem	struct xucred	ex_defanon;
1242b3f398rmacklem	int		ex_defexflags;
1252fb0351dfr	int		ex_numsecflavors;
1262fb0351dfr	int		ex_secflavors[MAXSECFLAVORS];
127b434c51rmacklem	int		ex_defnumsecflavors;
128b434c51rmacklem	int		ex_defsecflavors[MAXSECFLAVORS];
129bc78dacmanu
130bc78dacmanu	SLIST_ENTRY(exportlist) entries;
131cfcc93ergrimes};
132cfcc93ergrimes/* ex_flag bits */
133cfcc93ergrimes#define	EX_LINKED	0x1
1342b3f398rmacklem#define	EX_DONE		0x2
1352b3f398rmacklem#define	EX_DEFSET	0x4
1362b3f398rmacklem#define	EX_PUBLICFH	0x8
137cfcc93ergrimes
138ae62693rmacklemSLIST_HEAD(exportlisthead, exportlist);
139ae62693rmacklem
140cfcc93ergrimesstruct netmsk {
141f67e4a8alfred	struct sockaddr_storage nt_net;
142e293eeciedowse	struct sockaddr_storage nt_mask;
1438502ab2dfr	char		*nt_name;
144cfcc93ergrimes};
145cfcc93ergrimes
146cfcc93ergrimesunion grouptypes {
147f67e4a8alfred	struct addrinfo *gt_addrinfo;
148cfcc93ergrimes	struct netmsk	gt_net;
149cfcc93ergrimes};
150cfcc93ergrimes
151cfcc93ergrimesstruct grouplist {
152cfcc93ergrimes	int gr_type;
153cfcc93ergrimes	union grouptypes gr_ptr;
154cfcc93ergrimes	struct grouplist *gr_next;
1552b3f398rmacklem	struct xucred gr_anon;
1562b3f398rmacklem	int gr_exflags;
1572b3f398rmacklem	int gr_flag;
158b434c51rmacklem	int gr_numsecflavors;
159b434c51rmacklem	int gr_secflavors[MAXSECFLAVORS];
160cfcc93ergrimes};
161cfcc93ergrimes/* Group types */
162cfcc93ergrimes#define	GT_NULL		0x0
163cfcc93ergrimes#define	GT_HOST		0x1
164cfcc93ergrimes#define	GT_NET		0x2
1653f3a6a4iedowse#define	GT_DEFAULT	0x3
166af8a974wpaul#define GT_IGNORE	0x5
167cfcc93ergrimes
1682b3f398rmacklem/* Group flags */
1692b3f398rmacklem#define	GR_FND		0x1
1702b3f398rmacklem
171cfcc93ergrimesstruct hostlist {
172666343fdfr	int		 ht_flag;	/* Uses DP_xx bits */
173cfcc93ergrimes	struct grouplist *ht_grp;
174cfcc93ergrimes	struct hostlist	 *ht_next;
175cfcc93ergrimes};
176cfcc93ergrimes
177666343fdfrstruct fhreturn {
178666343fdfr	int	fhr_flag;
179666343fdfr	int	fhr_vers;
180666343fdfr	nfsfh_t	fhr_fh;
1812fb0351dfr	int	fhr_numsecflavors;
1822fb0351dfr	int	*fhr_secflavors;
183666343fdfr};
184666343fdfr
185c0db2e6rmacklem#define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
186c0db2e6rmacklem
187cfcc93ergrimes/* Global defs */
188b8c5808traszstatic char	*add_expdir(struct dirlist **, char *, int);
189b8c5808traszstatic void	add_dlist(struct dirlist **, struct dirlist *,
1902b3f398rmacklem		    struct grouplist *, int, struct exportlist *,
1912b3f398rmacklem		    struct xucred *, int);
192b8c5808traszstatic void	add_mlist(char *, char *);
193b8c5808traszstatic int	check_dirpath(char *);
194b8c5808traszstatic int	check_options(struct dirlist *);
195b8c5808traszstatic int	checkmask(struct sockaddr *sa);
196b8c5808traszstatic int	chk_host(struct dirlist *, struct sockaddr *, int *, int *,
197b8c5808trasz		    int *, int **);
19857f950fjpaetzelstatic char	*strsep_quote(char **stringp, const char *delim);
199c0db2e6rmacklemstatic int	create_service(struct netconfig *nconf);
200c0db2e6rmacklemstatic void	complete_service(struct netconfig *nconf, char *port_str);
201c0db2e6rmacklemstatic void	clearout_service(void);
202b8c5808traszstatic void	del_mlist(char *hostp, char *dirp);
203b8c5808traszstatic struct dirlist	*dirp_search(struct dirlist *, char *);
2042b3f398rmacklemstatic int	do_export_mount(struct exportlist *, struct statfs *);
205b8c5808traszstatic int	do_mount(struct exportlist *, struct grouplist *, int,
2062b3f398rmacklem		    struct xucred *, char *, int, struct statfs *, int, int *);
207b8c5808traszstatic int	do_opt(char **, char **, struct exportlist *,
208b8c5808trasz		    struct grouplist *, int *, int *, struct xucred *);
209ae62693rmacklemstatic struct exportlist	*ex_search(fsid_t *, struct exportlisthead *);
210b8c5808traszstatic struct exportlist	*get_exp(void);
211b8c5808traszstatic void	free_dir(struct dirlist *);
212b8c5808traszstatic void	free_exp(struct exportlist *);
213b8c5808traszstatic void	free_grp(struct grouplist *);
214b8c5808traszstatic void	free_host(struct hostlist *);
2152b3f398rmacklemstatic void	free_v4rootexp(void);
2162b3f398rmacklemstatic void	get_exportlist_one(int);
2172b3f398rmacklemstatic void	get_exportlist(int);
218ae62693rmacklemstatic void	insert_exports(struct exportlist *, struct exportlisthead *);
219ae62693rmacklemstatic void	free_exports(struct exportlisthead *);
2202b3f398rmacklemstatic void	read_exportfile(int);
2212b3f398rmacklemstatic int	compare_nmount_exportlist(struct iovec *, int, char *);
2222b3f398rmacklemstatic int	compare_export(struct exportlist *, struct exportlist *);
2232b3f398rmacklemstatic int	compare_cred(struct xucred *, struct xucred *);
2242b3f398rmacklemstatic int	compare_secflavor(int *, int *, int);
225947c947rmacklemstatic void	delete_export(struct iovec *, int, struct statfs *, char *);
226b8c5808traszstatic int	get_host(char *, struct grouplist *, struct grouplist *);
227b8c5808traszstatic struct hostlist *get_ht(void);
228b8c5808traszstatic int	get_line(void);
229b8c5808traszstatic void	get_mountlist(void);
230b8c5808traszstatic int	get_net(char *, struct netmsk *, int);
231d0186d4cemstatic void	getexp_err(struct exportlist *, struct grouplist *, const char *);
232b8c5808traszstatic struct grouplist	*get_grp(void);
233b8c5808traszstatic void	hang_dirp(struct dirlist *, struct grouplist *,
2342b3f398rmacklem		    struct exportlist *, int, struct xucred *, int);
235b8c5808traszstatic void	huphandler(int sig);
236b8c5808traszstatic int	makemask(struct sockaddr_storage *ssp, int bitlen);
237b8c5808traszstatic void	mntsrv(struct svc_req *, SVCXPRT *);
238b8c5808traszstatic void	nextfield(char **, char **);
239b8c5808traszstatic void	out_of_mem(void);
240b8c5808traszstatic void	parsecred(char *, struct xucred *);
241b8c5808traszstatic int	parsesec(char *, struct exportlist *);
242b8c5808traszstatic int	put_exlist(struct dirlist *, XDR *, struct dirlist *,
243b8c5808trasz		    int *, int);
244b8c5808traszstatic void	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
245b8c5808traszstatic int	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
246b8c5808trasz		    struct sockaddr *samask);
247b8c5808traszstatic int	scan_tree(struct dirlist *, struct sockaddr *);
248b8c5808traszstatic void	usage(void);
249b8c5808traszstatic int	xdr_dir(XDR *, char *);
250b8c5808traszstatic int	xdr_explist(XDR *, caddr_t);
251b8c5808traszstatic int	xdr_explist_brief(XDR *, caddr_t);
252b8c5808traszstatic int	xdr_explist_common(XDR *, caddr_t, int);
253b8c5808traszstatic int	xdr_fhs(XDR *, caddr_t);
254b8c5808traszstatic int	xdr_mlist(XDR *, caddr_t);
255b8c5808traszstatic void	terminate(int);
256b8c5808trasz
25766fe452rmacklem#define	EXPHASH(f)	(fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize)
25866fe452rmacklemstatic struct exportlisthead *exphead = NULL;
2592b3f398rmacklemstatic struct exportlisthead *oldexphead = NULL;
26066fe452rmacklemstatic int exphashsize = 0;
261ae62693rmacklemstatic SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead);
262b8c5808traszstatic char *exnames_default[2] = { _PATH_EXPORTS, NULL };
263b8c5808traszstatic char **exnames;
264b8c5808traszstatic char **hosts = NULL;
265b8c5808traszstatic struct xucred def_anon = {
266c8a6bd9dd	XUCRED_VERSION,
2678fe18bermacklem	(uid_t)65534,
268cfcc93ergrimes	1,
2698fe18bermacklem	{ (gid_t)65533 },
270a25b408dchagin	{ NULL }
271cfcc93ergrimes};
272b8c5808traszstatic int force_v2 = 0;
273b8c5808traszstatic int resvport_only = 1;
274b8c5808traszstatic int nhosts = 0;
275b8c5808traszstatic int dir_only = 1;
276b8c5808traszstatic int dolog = 0;
277b8c5808traszstatic int got_sighup = 0;
278b8c5808traszstatic int xcreated = 0;
279b8c5808trasz
280b8c5808traszstatic char *svcport_str = NULL;
281b8c5808traszstatic int mallocd_svcport = 0;
282b8c5808traszstatic int *sock_fd;
283b8c5808traszstatic int sock_fdcnt;
284b8c5808traszstatic int sock_fdpos;
285b8c5808traszstatic int suspend_nfsd = 0;
286b8c5808trasz
287b8c5808traszstatic int opt_flags;
288f67e4a8alfredstatic int have_v6 = 1;
289f67e4a8alfred
290b8c5808traszstatic int v4root_phase = 0;
291b8c5808traszstatic char v4root_dirpath[PATH_MAX + 1];
2922b3f398rmacklemstatic struct exportlist *v4root_ep = NULL;
293b8c5808traszstatic int has_publicfh = 0;
2942b3f398rmacklemstatic int has_set_publicfh = 0;
2958ca86cdrmacklem
296b8c5808traszstatic struct pidfh *pfh = NULL;
297e293eeciedowse/* Bits for opt_flags above */
298cfcc93ergrimes#define	OP_MAPROOT	0x01
299cfcc93ergrimes#define	OP_MAPALL	0x02
30068a5e33peter/* 0x4 free */
301cfcc93ergrimes#define	OP_MASK		0x08
302cfcc93ergrimes#define	OP_NET		0x10
303cfcc93ergrimes#define	OP_ALLDIRS	0x40
304e293eeciedowse#define	OP_HAVEMASK	0x80	/* A mask was specified or inferred. */
30563afba9joerg#define	OP_QUIET	0x100
306f67e4a8alfred#define OP_MASKLEN	0x200
3072fb0351dfr#define OP_SEC		0x400
308cfcc93ergrimes
309cfcc93ergrimes#ifdef DEBUG
310b8c5808traszstatic int debug = 1;
311b8c5808traszstatic void	SYSLOG(int, const char *, ...) __printflike(2, 3);
312cfcc93ergrimes#define syslog SYSLOG
313cfcc93ergrimes#else
314b8c5808traszstatic int debug = 0;
315cfcc93ergrimes#endif
316cfcc93ergrimes
317cfcc93ergrimes/*
3182b3f398rmacklem * The LOGDEBUG() syslog() calls are always compiled into the daemon.
3192b3f398rmacklem * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty.
3202b3f398rmacklem * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG.
3212b3f398rmacklem */
3222b3f398rmacklemstatic int logdebug = 0;
3232b3f398rmacklem#define	LOGDEBUG(format, ...)						\
3242b3f398rmacklem    (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0)
3252b3f398rmacklem
3262b3f398rmacklem/*
32757f950fjpaetzel * Similar to strsep(), but it allows for quoted strings
32857f950fjpaetzel * and escaped characters.
32957f950fjpaetzel *
33057f950fjpaetzel * It returns the string (or NULL, if *stringp is NULL),
33157f950fjpaetzel * which is a de-quoted version of the string if necessary.
33257f950fjpaetzel *
33357f950fjpaetzel * It modifies *stringp in place.
33457f950fjpaetzel */
33557f950fjpaetzelstatic char *
33657f950fjpaetzelstrsep_quote(char **stringp, const char *delim)
33757f950fjpaetzel{
33857f950fjpaetzel	char *srcptr, *dstptr, *retval;
33957f950fjpaetzel	char quot = 0;
34057f950fjpaetzel
34157f950fjpaetzel	if (stringp == NULL || *stringp == NULL)
34257f950fjpaetzel		return (NULL);
34357f950fjpaetzel
34457f950fjpaetzel	srcptr = dstptr = retval = *stringp;
34557f950fjpaetzel
34657f950fjpaetzel	while (*srcptr) {
34757f950fjpaetzel		/*
34857f950fjpaetzel		 * We're looking for several edge cases here.
34957f950fjpaetzel		 * First:  if we're in quote state (quot != 0),
35057f950fjpaetzel		 * then we ignore the delim characters, but otherwise
35157f950fjpaetzel		 * process as normal, unless it is the quote character.
35257f950fjpaetzel		 * Second:  if the current character is a backslash,
35357f950fjpaetzel		 * we take the next character as-is, without checking
35457f950fjpaetzel		 * for delim, quote, or backslash.  Exception:  if the
35557f950fjpaetzel		 * next character is a NUL, that's the end of the string.
35657f950fjpaetzel		 * Third:  if the character is a quote character, we toggle
35757f950fjpaetzel		 * quote state.
35857f950fjpaetzel		 * Otherwise:  check the current character for NUL, or
35957f950fjpaetzel		 * being in delim, and end the string if either is true.
36057f950fjpaetzel		 */
36157f950fjpaetzel		if (*srcptr == '\\') {
36257f950fjpaetzel			srcptr++;
36357f950fjpaetzel			/*
36457f950fjpaetzel			 * The edge case here is if the next character
36557f950fjpaetzel			 * is NUL, we want to stop processing.  But if
36657f950fjpaetzel			 * it's not NUL, then we simply want to copy it.
36757f950fjpaetzel			 */
36857f950fjpaetzel			if (*srcptr) {
36957f950fjpaetzel				*dstptr++ = *srcptr++;
37057f950fjpaetzel			}
37157f950fjpaetzel			continue;
37257f950fjpaetzel		}
37357f950fjpaetzel		if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) {
37457f950fjpaetzel			quot = *srcptr++;
37557f950fjpaetzel			continue;
37657f950fjpaetzel		}
37757f950fjpaetzel		if (quot && *srcptr == quot) {
37857f950fjpaetzel			/* End of the quoted part */
37957f950fjpaetzel			quot = 0;
38057f950fjpaetzel			srcptr++;
38157f950fjpaetzel			continue;
38257f950fjpaetzel		}
38357f950fjpaetzel		if (!quot && strchr(delim, *srcptr))
38457f950fjpaetzel			break;
38557f950fjpaetzel		*dstptr++ = *srcptr++;
38657f950fjpaetzel	}
38757f950fjpaetzel
38857f950fjpaetzel	*stringp = (*srcptr == '\0') ? NULL : srcptr + 1;
3891669b01mav	*dstptr = 0; /* Terminate the string */
39057f950fjpaetzel	return (retval);
39157f950fjpaetzel}
39257f950fjpaetzel
39357f950fjpaetzel/*
394cfcc93ergrimes * Mountd server for NFS mount protocol as described in:
395cfcc93ergrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A
396cfcc93ergrimes * The optional arguments are the exports file name
397cfcc93ergrimes * default: _PATH_EXPORTS
398cfcc93ergrimes * and "-n" to allow nonroot mount.
399cfcc93ergrimes */
400cfcc93ergrimesint
401c30b6f1charniermain(int argc, char **argv)
402cfcc93ergrimes{
403439a88eiedowse	fd_set readfds;
404d3d824bmatteo	struct netconfig *nconf;
405d3d824bmatteo	char *endptr, **hosts_bak;
406d3d824bmatteo	void *nc_handle;
407a834e26pjd	pid_t otherpid;
408d3d824bmatteo	in_port_t svcport;
409d3d824bmatteo	int c, k, s;
410f4b7d59mbr	int maxrec = RPC_MAXDATASIZE;
411c0db2e6rmacklem	int attempt_cnt, port_len, port_pos, ret;
412c0db2e6rmacklem	char **port_list;
413023d47ciedowse
414f67e4a8alfred	/* Check that another mountd isn't already running. */
415c71407bpjd	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
416a834e26pjd	if (pfh == NULL) {
417a834e26pjd		if (errno == EEXIST)
418a834e26pjd			errx(1, "mountd already running, pid: %d.", otherpid);
419a834e26pjd		warn("cannot open or create pidfile");
420a834e26pjd	}
421f67e4a8alfred
422f67e4a8alfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
423f67e4a8alfred	if (s < 0)
424f67e4a8alfred		have_v6 = 0;
425f67e4a8alfred	else
426f67e4a8alfred		close(s);
427cfcc93ergrimes
4283bcd59atrasz	while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1)
429cfcc93ergrimes		switch (c) {
430a6bde6ddfr		case '2':
431a6bde6ddfr			force_v2 = 1;
432a6bde6ddfr			break;
4338bb7f95rmacklem		case 'e':
4349ed5d72rmacklem			/* now a no-op, since this is the default */
4358ca86cdrmacklem			break;
436666343fdfr		case 'n':
437666343fdfr			resvport_only = 0;
438666343fdfr			break;
439666343fdfr		case 'r':
440666343fdfr			dir_only = 0;
441666343fdfr			break;
4422e4f6d9phk		case 'd':
4432e4f6d9phk			debug = debug ? 0 : 1;
4442e4f6d9phk			break;
4459c59d25guido		case 'l':
446446d2f7peter			dolog = 1;
4479c59d25guido			break;
4489edf770bms		case 'p':
4499edf770bms			endptr = NULL;
4509edf770bms			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
4519edf770bms			if (endptr == NULL || *endptr != '\0' ||
4529edf770bms			    svcport == 0 || svcport >= IPPORT_MAX)
4539edf770bms				usage();
454d3d824bmatteo			svcport_str = strdup(optarg);
455d3d824bmatteo			break;
456d3d824bmatteo		case 'h':
457d3d824bmatteo			++nhosts;
458d3d824bmatteo			hosts_bak = hosts;
459d3d824bmatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
460d3d824bmatteo			if (hosts_bak == NULL) {
461d3d824bmatteo				if (hosts != NULL) {
462d3d824bmatteo					for (k = 0; k < nhosts; k++)
463d3d824bmatteo						free(hosts[k]);
464d3d824bmatteo					free(hosts);
465d3d824bmatteo					out_of_mem();
466d3d824bmatteo				}
467d3d824bmatteo			}
468d3d824bmatteo			hosts = hosts_bak;
469d3d824bmatteo			hosts[nhosts - 1] = strdup(optarg);
470d3d824bmatteo			if (hosts[nhosts - 1] == NULL) {
471d3d824bmatteo				for (k = 0; k < (nhosts - 1); k++)
472d3d824bmatteo					free(hosts[k]);
473d3d824bmatteo				free(hosts);
474d3d824bmatteo				out_of_mem();
475d3d824bmatteo			}
4769edf770bms			break;
4773b67798rmacklem		case 'S':
4783b67798rmacklem			suspend_nfsd = 1;
4793b67798rmacklem			break;
480cfcc93ergrimes		default:
481118387fcharnier			usage();
48226c891fpfg		}
4838ca86cdrmacklem
4843bcd59atrasz	if (modfind("nfsd") < 0) {
4858ca86cdrmacklem		/* Not present in kernel, try loading it */
4863bcd59atrasz		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
4878ca86cdrmacklem			errx(1, "NFS server is not available");
4888ca86cdrmacklem	}
4898ca86cdrmacklem
490cfcc93ergrimes	argc -= optind;
491cfcc93ergrimes	argv += optind;
4928d0230dpjd	if (argc > 0)
4938d0230dpjd		exnames = argv;
4948d0230dpjd	else
4958d0230dpjd		exnames = exnames_default;
496cfcc93ergrimes	openlog("mountd", LOG_PID, LOG_DAEMON);
497cfcc93ergrimes	if (debug)
498118387fcharnier		warnx("getting export list");
4992b3f398rmacklem	get_exportlist(0);
500cfcc93ergrimes	if (debug)
501118387fcharnier		warnx("getting mount list");
502cfcc93ergrimes	get_mountlist();
503cfcc93ergrimes	if (debug)
504118387fcharnier		warnx("here we go");
505cfcc93ergrimes	if (debug == 0) {
506cfcc93ergrimes		daemon(0, 0);
507cfcc93ergrimes		signal(SIGINT, SIG_IGN);
508cfcc93ergrimes		signal(SIGQUIT, SIG_IGN);
509cfcc93ergrimes	}
510439a88eiedowse	signal(SIGHUP, huphandler);
511f67e4a8alfred	signal(SIGTERM, terminate);
5127a2a030rodrigc	signal(SIGPIPE, SIG_IGN);
513a834e26pjd
514a834e26pjd	pidfile_write(pfh);
515a834e26pjd
516ec9ddecdfr	rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
517ec9ddecdfr	rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
518f4b7d59mbr	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
519f4b7d59mbr
520c0dad1fguido	if (!resvport_only) {
52198386c0rmacklem		if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL,
5220bbcfd5peter		    &resvport_only, sizeof(resvport_only)) != 0 &&
5230bbcfd5peter		    errno != ENOENT) {
524c0dad1fguido			syslog(LOG_ERR, "sysctl: %m");
525c0dad1fguido			exit(1);
526c0dad1fguido		}
5278db0f5fguido	}
528f67e4a8alfred
529d3d824bmatteo	/*
530d3d824bmatteo	 * If no hosts were specified, add a wildcard entry to bind to
531d3d824bmatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
532d3d824bmatteo	 * list.
533d3d824bmatteo	 */
534d3d824bmatteo	if (nhosts == 0) {
53511e0dd6uqs		hosts = malloc(sizeof(char *));
536d3d824bmatteo		if (hosts == NULL)
537d3d824bmatteo			out_of_mem();
538d3d824bmatteo		hosts[0] = "*";
539d3d824bmatteo		nhosts = 1;
540d3d824bmatteo	} else {
541d3d824bmatteo		hosts_bak = hosts;
542d3d824bmatteo		if (have_v6) {
543d3d824bmatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
544d3d824bmatteo			    sizeof(char *));
545d3d824bmatteo			if (hosts_bak == NULL) {
546d3d824bmatteo				for (k = 0; k < nhosts; k++)
547d3d824bmatteo					free(hosts[k]);
548d3d824bmatteo		    		free(hosts);
549d3d824bmatteo		    		out_of_mem();
550d3d824bmatteo			} else
551d3d824bmatteo				hosts = hosts_bak;
552d3d824bmatteo			nhosts += 2;
553d3d824bmatteo			hosts[nhosts - 2] = "::1";
554d3d824bmatteo		} else {
555d3d824bmatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
556d3d824bmatteo			if (hosts_bak == NULL) {
557d3d824bmatteo				for (k = 0; k < nhosts; k++)
558d3d824bmatteo					free(hosts[k]);
559d3d824bmatteo				free(hosts);
560d3d824bmatteo				out_of_mem();
561d3d824bmatteo			} else {
562d3d824bmatteo				nhosts += 1;
563d3d824bmatteo				hosts = hosts_bak;
564f67e4a8alfred			}
565d3d824bmatteo		}
566f67e4a8alfred
567d3d824bmatteo		hosts[nhosts - 1] = "127.0.0.1";
568f67e4a8alfred	}
569f67e4a8alfred
570c0db2e6rmacklem	attempt_cnt = 1;
571c0db2e6rmacklem	sock_fdcnt = 0;
572c0db2e6rmacklem	sock_fd = NULL;
573c0db2e6rmacklem	port_list = NULL;
574c0db2e6rmacklem	port_len = 0;
575c0db2e6rmacklem	nc_handle = setnetconfig();
576c0db2e6rmacklem	while ((nconf = getnetconfig(nc_handle))) {
577