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>
5139ad463rmacklem#include <sys/conf.h>
52f67e4a8alfred#include <sys/fcntl.h>
5366fe452rmacklem#include <sys/fnv_hash.h>
5436cd292iedowse#include <sys/linker.h>
5536cd292iedowse#include <sys/module.h>
568ca86cdrmacklem#include <sys/mount.h>
57bc78dacmanu#include <sys/queue.h>
588ca86cdrmacklem#include <sys/stat.h>
598ca86cdrmacklem#include <sys/sysctl.h>
608ca86cdrmacklem#include <sys/syslog.h>
61cfcc93ergrimes
62cfcc93ergrimes#include <rpc/rpc.h>
63f4b7d59mbr#include <rpc/rpc_com.h>
64cfcc93ergrimes#include <rpc/pmap_clnt.h>
65f67e4a8alfred#include <rpc/pmap_prot.h>
66f67e4a8alfred#include <rpcsvc/mount.h>
67666343fdfr#include <nfs/nfsproto.h>
688ca86cdrmacklem#include <nfs/nfssvc.h>
6968a5e33peter#include <nfsserver/nfs.h>
70cfcc93ergrimes
718ca86cdrmacklem#include <fs/nfs/nfsport.h>
728ca86cdrmacklem
73cfcc93ergrimes#include <arpa/inet.h>
74cfcc93ergrimes
75cfcc93ergrimes#include <ctype.h>
76118387fcharnier#include <err.h>
77cfcc93ergrimes#include <errno.h>
78cfcc93ergrimes#include <grp.h>
79a834e26pjd#include <libutil.h>
8086a758emike#include <limits.h>
81cfcc93ergrimes#include <netdb.h>
82cfcc93ergrimes#include <pwd.h>
83cfcc93ergrimes#include <signal.h>
84cfcc93ergrimes#include <stdio.h>
85cfcc93ergrimes#include <stdlib.h>
86cfcc93ergrimes#include <string.h>
87cfcc93ergrimes#include <unistd.h>
88cfcc93ergrimes#include "pathnames.h"
8904be51frodrigc#include "mntopts.h"
90cfcc93ergrimes
91cfcc93ergrimes#ifdef DEBUG
92cfcc93ergrimes#include <stdarg.h>
93cfcc93ergrimes#endif
94cfcc93ergrimes
95cfcc93ergrimes/*
96cfcc93ergrimes * Structures for keeping the mount list and export list
97cfcc93ergrimes */
98cfcc93ergrimesstruct mountlist {
99ec9ddecdfr	char	ml_host[MNTNAMLEN+1];
100ec9ddecdfr	char	ml_dirp[MNTPATHLEN+1];
1014dde448manu
1024dde448manu	SLIST_ENTRY(mountlist)	next;
103cfcc93ergrimes};
104cfcc93ergrimes
105cfcc93ergrimesstruct dirlist {
106cfcc93ergrimes	struct dirlist	*dp_left;
107cfcc93ergrimes	struct dirlist	*dp_right;
108cfcc93ergrimes	int		dp_flag;
109cfcc93ergrimes	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
110b5f772emanu	char		*dp_dirp;
111cfcc93ergrimes};
112cfcc93ergrimes/* dp_flag bits */
113cfcc93ergrimes#define	DP_DEFSET	0x1
114666343fdfr#define DP_HOSTSET	0x2
115cfcc93ergrimes
1161bfe4e8rmacklem/*
1171bfe4e8rmacklem * maproot/mapall credentials.
118f573732rmacklem * cr_smallgrps can be used for a group list up to SMALLNGROUPS in size.
119f573732rmacklem * Larger group lists are malloc'd/free'd.
1201bfe4e8rmacklem */
121f573732rmacklem#define	SMALLNGROUPS	32
1221bfe4e8rmacklemstruct expcred {
1231bfe4e8rmacklem	uid_t		cr_uid;
1241bfe4e8rmacklem	int		cr_ngroups;
125f573732rmacklem	gid_t		cr_smallgrps[SMALLNGROUPS];
126f573732rmacklem	gid_t		*cr_groups;
1271bfe4e8rmacklem};
1281bfe4e8rmacklem
129cfcc93ergrimesstruct exportlist {
130cfcc93ergrimes	struct dirlist	*ex_dirl;
131cfcc93ergrimes	struct dirlist	*ex_defdir;
1321d91d4brmacklem	struct grouplist *ex_grphead;
133cfcc93ergrimes	int		ex_flag;
134cfcc93ergrimes	fsid_t		ex_fs;
135cfcc93ergrimes	char		*ex_fsdir;
1364acc83bdfr	char		*ex_indexfile;
1371bfe4e8rmacklem	struct expcred	ex_defanon;
1381bfe4e8rmacklem	uint64_t	ex_defexflags;
1392fb0351dfr	int		ex_numsecflavors;
1402fb0351dfr	int		ex_secflavors[MAXSECFLAVORS];
141b434c51rmacklem	int		ex_defnumsecflavors;
142b434c51rmacklem	int		ex_defsecflavors[MAXSECFLAVORS];
143bc78dacmanu
144bc78dacmanu	SLIST_ENTRY(exportlist) entries;
145cfcc93ergrimes};
146cfcc93ergrimes/* ex_flag bits */
147cfcc93ergrimes#define	EX_LINKED	0x1
1482b3f398rmacklem#define	EX_DONE		0x2
1492b3f398rmacklem#define	EX_DEFSET	0x4
1502b3f398rmacklem#define	EX_PUBLICFH	0x8
151cfcc93ergrimes
152ae62693rmacklemSLIST_HEAD(exportlisthead, exportlist);
153ae62693rmacklem
154cfcc93ergrimesstruct netmsk {
155f67e4a8alfred	struct sockaddr_storage nt_net;
156e293eeciedowse	struct sockaddr_storage nt_mask;
1578502ab2dfr	char		*nt_name;
158cfcc93ergrimes};
159cfcc93ergrimes
160cfcc93ergrimesunion grouptypes {
161f67e4a8alfred	struct addrinfo *gt_addrinfo;
162cfcc93ergrimes	struct netmsk	gt_net;
163cfcc93ergrimes};
164cfcc93ergrimes
165cfcc93ergrimesstruct grouplist {
166cfcc93ergrimes	int gr_type;
167cfcc93ergrimes	union grouptypes gr_ptr;
168cfcc93ergrimes	struct grouplist *gr_next;
1691bfe4e8rmacklem	struct expcred gr_anon;
1701bfe4e8rmacklem	uint64_t gr_exflags;
1712b3f398rmacklem	int gr_flag;
172b434c51rmacklem	int gr_numsecflavors;
173b434c51rmacklem	int gr_secflavors[MAXSECFLAVORS];
174cfcc93ergrimes};
175cfcc93ergrimes/* Group types */
176cfcc93ergrimes#define	GT_NULL		0x0
177cfcc93ergrimes#define	GT_HOST		0x1
178cfcc93ergrimes#define	GT_NET		0x2
1793f3a6a4iedowse#define	GT_DEFAULT	0x3
180af8a974wpaul#define GT_IGNORE	0x5
181cfcc93ergrimes
1822b3f398rmacklem/* Group flags */
1832b3f398rmacklem#define	GR_FND		0x1
1842b3f398rmacklem
185cfcc93ergrimesstruct hostlist {
186666343fdfr	int		 ht_flag;	/* Uses DP_xx bits */
187cfcc93ergrimes	struct grouplist *ht_grp;
188cfcc93ergrimes	struct hostlist	 *ht_next;
189cfcc93ergrimes};
190cfcc93ergrimes
191666343fdfrstruct fhreturn {
192666343fdfr	int	fhr_flag;
193666343fdfr	int	fhr_vers;
194666343fdfr	nfsfh_t	fhr_fh;
1952fb0351dfr	int	fhr_numsecflavors;
1962fb0351dfr	int	*fhr_secflavors;
197666343fdfr};
198666343fdfr
199c0db2e6rmacklem#define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
200c0db2e6rmacklem
201e2cdf84rmacklem/*
202e2cdf84rmacklem * How long to delay a reload of exports when there are RPC request(s)
203e2cdf84rmacklem * to process, in usec.  Must be less than 1second.
204e2cdf84rmacklem */
205e2cdf84rmacklem#define	RELOADDELAY	250000
206e2cdf84rmacklem
207cfcc93ergrimes/* Global defs */
208b8c5808traszstatic char	*add_expdir(struct dirlist **, char *, int);
209b8c5808traszstatic void	add_dlist(struct dirlist **, struct dirlist *,
2102b3f398rmacklem		    struct grouplist *, int, struct exportlist *,
2111bfe4e8rmacklem		    struct expcred *, uint64_t);
212b8c5808traszstatic void	add_mlist(char *, char *);
213b8c5808traszstatic int	check_dirpath(char *);
214b8c5808traszstatic int	check_options(struct dirlist *);
215b8c5808traszstatic int	checkmask(struct sockaddr *sa);
216b8c5808traszstatic int	chk_host(struct dirlist *, struct sockaddr *, int *, int *,
217b8c5808trasz		    int *, int **);
21857f950fjpaetzelstatic char	*strsep_quote(char **stringp, const char *delim);
219c0db2e6rmacklemstatic int	create_service(struct netconfig *nconf);
220c0db2e6rmacklemstatic void	complete_service(struct netconfig *nconf, char *port_str);
221c0db2e6rmacklemstatic void	clearout_service(void);
222b8c5808traszstatic void	del_mlist(char *hostp, char *dirp);
223b8c5808traszstatic struct dirlist	*dirp_search(struct dirlist *, char *);
2242b3f398rmacklemstatic int	do_export_mount(struct exportlist *, struct statfs *);
2251bfe4e8rmacklemstatic int	do_mount(struct exportlist *, struct grouplist *, uint64_t,
2261bfe4e8rmacklem		    struct expcred *, char *, int, struct statfs *, int, int *);
227b8c5808traszstatic int	do_opt(char **, char **, struct exportlist *,
2281bfe4e8rmacklem		    struct grouplist *, int *, uint64_t *, struct expcred *);
229ae62693rmacklemstatic struct exportlist	*ex_search(fsid_t *, struct exportlisthead *);
230b8c5808traszstatic struct exportlist	*get_exp(void);
231b8c5808traszstatic void	free_dir(struct dirlist *);
232b8c5808traszstatic void	free_exp(struct exportlist *);
233b8c5808traszstatic void	free_grp(struct grouplist *);
234b8c5808traszstatic void	free_host(struct hostlist *);
2352b3f398rmacklemstatic void	free_v4rootexp(void);
2362b3f398rmacklemstatic void	get_exportlist_one(int);
2372b3f398rmacklemstatic void	get_exportlist(int);
238ae62693rmacklemstatic void	insert_exports(struct exportlist *, struct exportlisthead *);
239ae62693rmacklemstatic void	free_exports(struct exportlisthead *);
2402b3f398rmacklemstatic void	read_exportfile(int);
2412b3f398rmacklemstatic int	compare_nmount_exportlist(struct iovec *, int, char *);
2422b3f398rmacklemstatic int	compare_export(struct exportlist *, struct exportlist *);
2431bfe4e8rmacklemstatic int	compare_cred(struct expcred *, struct expcred *);
2442b3f398rmacklemstatic int	compare_secflavor(int *, int *, int);
245947c947rmacklemstatic void	delete_export(struct iovec *, int, struct statfs *, char *);
246b8c5808traszstatic int	get_host(char *, struct grouplist *, struct grouplist *);
247b8c5808traszstatic struct hostlist *get_ht(void);
248b8c5808traszstatic int	get_line(void);
249b8c5808traszstatic void	get_mountlist(void);
250b8c5808traszstatic int	get_net(char *, struct netmsk *, int);
251d0186d4cemstatic void	getexp_err(struct exportlist *, struct grouplist *, const char *);
252b8c5808traszstatic struct grouplist	*get_grp(void);
253b8c5808traszstatic void	hang_dirp(struct dirlist *, struct grouplist *,
2541bfe4e8rmacklem		    struct exportlist *, int, struct expcred *, uint64_t);
255b8c5808traszstatic void	huphandler(int sig);
256b8c5808traszstatic int	makemask(struct sockaddr_storage *ssp, int bitlen);
257b8c5808traszstatic void	mntsrv(struct svc_req *, SVCXPRT *);
258b8c5808traszstatic void	nextfield(char **, char **);
259b8c5808traszstatic void	out_of_mem(void);
2601bfe4e8rmacklemstatic void	parsecred(char *, struct expcred *);
261b8c5808traszstatic int	parsesec(char *, struct exportlist *);
262b8c5808traszstatic int	put_exlist(struct dirlist *, XDR *, struct dirlist *,
263b8c5808trasz		    int *, int);
264b8c5808traszstatic void	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
265b8c5808traszstatic int	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
266b8c5808trasz		    struct sockaddr *samask);
267b8c5808traszstatic int	scan_tree(struct dirlist *, struct sockaddr *);
268b8c5808traszstatic void	usage(void);
269b8c5808traszstatic int	xdr_dir(XDR *, char *);
270b8c5808traszstatic int	xdr_explist(XDR *, caddr_t);
271b8c5808traszstatic int	xdr_explist_brief(XDR *, caddr_t);
272b8c5808traszstatic int	xdr_explist_common(XDR *, caddr_t, int);
273b8c5808traszstatic int	xdr_fhs(XDR *, caddr_t);
274b8c5808traszstatic int	xdr_mlist(XDR *, caddr_t);
275b8c5808traszstatic void	terminate(int);
2761bfe4e8rmacklemstatic void	cp_cred(struct expcred *, struct expcred *);
277b8c5808trasz
27866fe452rmacklem#define	EXPHASH(f)	(fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize)
27966fe452rmacklemstatic struct exportlisthead *exphead = NULL;
2802b3f398rmacklemstatic struct exportlisthead *oldexphead = NULL;
28166fe452rmacklemstatic int exphashsize = 0;
282ae62693rmacklemstatic SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead);
283b8c5808traszstatic char *exnames_default[2] = { _PATH_EXPORTS, NULL };
284b8c5808traszstatic char **exnames;
285b8c5808traszstatic char **hosts = NULL;
286b8c5808traszstatic int force_v2 = 0;
287b8c5808traszstatic int resvport_only = 1;
288b8c5808traszstatic int nhosts = 0;
289b8c5808traszstatic int dir_only = 1;
290b8c5808traszstatic int dolog = 0;
291b8c5808traszstatic int got_sighup = 0;
292b8c5808traszstatic int xcreated = 0;
293b8c5808trasz
294b8c5808traszstatic char *svcport_str = NULL;
295b8c5808traszstatic int mallocd_svcport = 0;
296b8c5808traszstatic int *sock_fd;
297b8c5808traszstatic int sock_fdcnt;
298b8c5808traszstatic int sock_fdpos;
299b8c5808traszstatic int suspend_nfsd = 0;
300b8c5808trasz
301b8c5808traszstatic int opt_flags;
302f67e4a8alfredstatic int have_v6 = 1;
303f67e4a8alfred
304b8c5808traszstatic int v4root_phase = 0;
305b8c5808traszstatic char v4root_dirpath[PATH_MAX + 1];
3062b3f398rmacklemstatic struct exportlist *v4root_ep = NULL;
307b8c5808traszstatic int has_publicfh = 0;
3082b3f398rmacklemstatic int has_set_publicfh = 0;
3098ca86cdrmacklem
310b8c5808traszstatic struct pidfh *pfh = NULL;
311e293eeciedowse/* Bits for opt_flags above */
312cfcc93ergrimes#define	OP_MAPROOT	0x01
313cfcc93ergrimes#define	OP_MAPALL	0x02
31468a5e33peter/* 0x4 free */
315cfcc93ergrimes#define	OP_MASK		0x08
316cfcc93ergrimes#define	OP_NET		0x10
317cfcc93ergrimes#define	OP_ALLDIRS	0x40
318e293eeciedowse#define	OP_HAVEMASK	0x80	/* A mask was specified or inferred. */
31963afba9joerg#define	OP_QUIET	0x100
320f67e4a8alfred#define OP_MASKLEN	0x200
3212fb0351dfr#define OP_SEC		0x400
322cfcc93ergrimes
323cfcc93ergrimes#ifdef DEBUG
324b8c5808traszstatic int debug = 1;
325b8c5808traszstatic void	SYSLOG(int, const char *, ...) __printflike(2, 3);
326cfcc93ergrimes#define syslog SYSLOG
327cfcc93ergrimes#else
328b8c5808traszstatic int debug = 0;
329cfcc93ergrimes#endif
330cfcc93ergrimes
331cfcc93ergrimes/*
3322b3f398rmacklem * The LOGDEBUG() syslog() calls are always compiled into the daemon.
3332b3f398rmacklem * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty.
3342b3f398rmacklem * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG.
3352b3f398rmacklem */
3362b3f398rmacklemstatic int logdebug = 0;
3372b3f398rmacklem#define	LOGDEBUG(format, ...)						\
3382b3f398rmacklem    (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0)
3392b3f398rmacklem
3402b3f398rmacklem/*
34157f950fjpaetzel * Similar to strsep(), but it allows for quoted strings
34257f950fjpaetzel * and escaped characters.
34357f950fjpaetzel *
34457f950fjpaetzel * It returns the string (or NULL, if *stringp is NULL),
34557f950fjpaetzel * which is a de-quoted version of the string if necessary.
34657f950fjpaetzel *
34757f950fjpaetzel * It modifies *stringp in place.
34857f950fjpaetzel */
34957f950fjpaetzelstatic char *
35057f950fjpaetzelstrsep_quote(char **stringp, const char *delim)
35157f950fjpaetzel{
35257f950fjpaetzel	char *srcptr, *dstptr, *retval;
35357f950fjpaetzel	char quot = 0;
35457f950fjpaetzel
35557f950fjpaetzel	if (stringp == NULL || *stringp == NULL)
35657f950fjpaetzel		return (NULL);
35757f950fjpaetzel
35857f950fjpaetzel	srcptr = dstptr = retval = *stringp;
35957f950fjpaetzel
36057f950fjpaetzel	while (*srcptr) {
36157f950fjpaetzel		/*
36257f950fjpaetzel		 * We're looking for several edge cases here.
36357f950fjpaetzel		 * First:  if we're in quote state (quot != 0),
36457f950fjpaetzel		 * then we ignore the delim characters, but otherwise
36557f950fjpaetzel		 * process as normal, unless it is the quote character.
36657f950fjpaetzel		 * Second:  if the current character is a backslash,
36757f950fjpaetzel		 * we take the next character as-is, without checking
36857f950fjpaetzel		 * for delim, quote, or backslash.  Exception:  if the
36957f950fjpaetzel		 * next character is a NUL, that's the end of the string.
37057f950fjpaetzel		 * Third:  if the character is a quote character, we toggle
37157f950fjpaetzel		 * quote state.
37257f950fjpaetzel		 * Otherwise:  check the current character for NUL, or
37357f950fjpaetzel		 * being in delim, and end the string if either is true.
37457f950fjpaetzel		 */
37557f950fjpaetzel		if (*srcptr == '\\') {
37657f950fjpaetzel			srcptr++;
37757f950fjpaetzel			/*
37857f950fjpaetzel			 * The edge case here is if the next character
37957f950fjpaetzel			 * is NUL, we want to stop processing.  But if
38057f950fjpaetzel			 * it's not NUL, then we simply want to copy it.
38157f950fjpaetzel			 */
38257f950fjpaetzel			if (*srcptr) {
38357f950fjpaetzel				*dstptr++ = *srcptr++;
38457f950fjpaetzel			}
38557f950fjpaetzel			continue;
38657f950fjpaetzel		}
38757f950fjpaetzel		if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) {
38857f950fjpaetzel			quot = *srcptr++;
38957f950fjpaetzel			continue;
39057f950fjpaetzel		}
39157f950fjpaetzel		if (quot && *srcptr == quot) {
39257f950fjpaetzel			/* End of the quoted part */
39357f950fjpaetzel			quot = 0;
39457f950fjpaetzel			srcptr++;
39557f950fjpaetzel			continue;
39657f950fjpaetzel		}
39757f950fjpaetzel		if (!quot && strchr(delim, *srcptr))
39857f950fjpaetzel			break;
39957f950fjpaetzel		*dstptr++ = *srcptr++;
40057f950fjpaetzel	}
40157f950fjpaetzel
40257f950fjpaetzel	*stringp = (*srcptr == '\0') ? NULL : srcptr + 1;
4031669b01mav	*dstptr = 0; /* Terminate the string */
40457f950fjpaetzel	return (retval);
40557f950fjpaetzel}
40657f950fjpaetzel
40757f950fjpaetzel/*
408cfcc93ergrimes * Mountd server for NFS mount protocol as described in:
409cfcc93ergrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A
410cfcc93ergrimes * The optional arguments are the exports file name
411cfcc93ergrimes * default: _PATH_EXPORTS
412cfcc93ergrimes * and "-n" to allow nonroot mount.
413cfcc93ergrimes */
414cfcc93ergrimesint
415c30b6f1charniermain(int argc, char **argv)
416cfcc93ergrimes{
417439a88eiedowse	fd_set readfds;
418d3d824bmatteo	struct netconfig *nconf;
419d3d824bmatteo	char *endptr, **hosts_bak;
420d3d824bmatteo	void *nc_handle;
421a834e26pjd	pid_t otherpid;
422d3d824bmatteo	in_port_t svcport;
423d3d824bmatteo	int c, k, s;
424f4b7d59mbr	int maxrec = RPC_MAXDATASIZE;
425c0db2e6rmacklem	int attempt_cnt, port_len, port_pos, ret;
426c0db2e6rmacklem	char **port_list;
427e2cdf84rmacklem	uint64_t curtime, nexttime;
428e2cdf84rmacklem	struct timeval tv;
429e2cdf84rmacklem	struct timespec tp;
430e2cdf84rmacklem	sigset_t sighup_mask;
431023d47ciedowse
432f67e4a8alfred	/* Check that another mountd isn't already running. */
433c71407bpjd	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
434a834e26pjd	if (pfh == NULL) {
435a834e26pjd		if (errno == EEXIST)
436a834e26pjd			errx(1, "mountd already running, pid: %d.", otherpid);
437a834e26pjd		warn("cannot open or create pidfile");
438a834e26pjd	}
439f67e4a8alfred
440f67e4a8alfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
441f67e4a8alfred	if (s < 0)
442f67e4a8alfred		have_v6 = 0;
443f67e4a8alfred	else
444f67e4a8alfred		close(s);
445cfcc93ergrimes
4463bcd59atrasz	while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1)
447cfcc93ergrimes		switch (c) {
448a6bde6ddfr		case '2':
449a6bde6ddfr			force_v2 = 1;
450a6bde6ddfr			break;
4518bb7f95rmacklem		case 'e':
4529ed5d72rmacklem			/* now a no-op, since this is the default */
4538ca86cdrmacklem			break;
454666343fdfr		case 'n':
455666343fdfr			resvport_only = 0;
456666343fdfr			break;
457666343fdfr		case 'r':
458666343fdfr			dir_only = 0;
459666343fdfr			break;
4602e4f6d9phk		case 'd':
4612e4f6d9phk			debug = debug ? 0 : 1;
4622e4f6d9phk			break;
4639c59d25guido		case 'l':
464446d2f7peter			dolog = 1;
4659c59d25guido			break;
4669edf770bms		case 'p':
4679edf770bms			endptr = NULL;
4689edf770bms			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
4699edf770bms			if (endptr == NULL || *endptr != '\0' ||
4709edf770bms			    svcport == 0 || svcport >= IPPORT_MAX)
4719edf770bms				usage();
472d3d824bmatteo			svcport_str = strdup(optarg);
473d3d824bmatteo			break;
474d3d824bmatteo		case 'h':
475d3d824bmatteo			++nhosts;
476d3d824bmatteo			hosts_bak = hosts;
477d3d824bmatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
478d3d824bmatteo			if (hosts_bak == NULL) {
479d3d824bmatteo				if (hosts != NULL) {
480d3d824bmatteo					for (k = 0; k < nhosts; k++)
481d3d824bmatteo						free(hosts[k]);
482d3d824bmatteo					free(hosts);
483d3d824bmatteo					out_of_mem();
484d3d824bmatteo				}
485d3d824bmatteo			}
486d3d824bmatteo			hosts = hosts_bak;
487d3d824bmatteo			hosts[nhosts - 1] = strdup(optarg);
488d3d824bmatteo			if (hosts[nhosts - 1] == NULL) {
489d3d824bmatteo				for (k = 0; k < (nhosts - 1); k++)
490d3d824bmatteo					free(hosts[k]);
491d3d824bmatteo				free(hosts);
492d3d824bmatteo				out_of_mem();
493d3d824bmatteo			}
4949edf770bms			break;
4953b67798rmacklem		case 'S':
4963b67798rmacklem			suspend_nfsd = 1;
4973b67798rmacklem			break;
498cfcc93ergrimes		default:
499118387fcharnier			usage();
50026c891fpfg		}
5018ca86cdrmacklem
5023bcd59atrasz	if (modfind("nfsd") < 0) {
5038ca86cdrmacklem		/* Not present in kernel, try loading it */
5043bcd59atrasz		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
5058ca86cdrmacklem			errx(1, "NFS server is not available");
5068ca86cdrmacklem	}
5078ca86cdrmacklem
508cfcc93ergrimes	argc -= optind;
509cfcc93ergrimes	argv += optind;
5108d0230dpjd	if (argc > 0)
5118d0230dpjd		exnames = argv;
5128d0230dpjd	else
5138d0230dpjd		exnames = exnames_default;
514cfcc93ergrimes	openlog("mountd", LOG_PID, LOG_DAEMON);
515cfcc93ergrimes	if (debug)
516118387fcharnier		warnx("getting export list");
5172b3f398rmacklem	get_exportlist(0);
518cfcc93ergrimes	if (debug)
519118387fcharnier		warnx("getting mount list");
520cfcc93ergrimes	get_mountlist();
521cfcc93ergrimes	if (debug)
522118387fcharnier		warnx("here we go");
523cfcc93ergrimes	if (debug == 0) {
524cfcc93ergrimes		daemon(0, 0);
525cfcc93ergrimes		signal(SIGINT, SIG_IGN);
526cfcc93ergrimes		signal(SIGQUIT, SIG_IGN);
527cfcc93ergrimes	}
528439a88eiedowse	signal(SIGHUP, huphandler);
529f67e4a8alfred	signal(SIGTERM, terminate);
5307a2a030rodrigc	signal(SIGPIPE, SIG_IGN);
531a834e26pjd
532a834e26pjd	pidfile_write(pfh);
533a834e26pjd
534ec9ddecdfr	rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
535ec9ddecdfr	rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
536f4b7d59mbr	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
537f4b7d59mbr
538c0dad1fguido	if (!resvport_only) {
53998386c0rmacklem		if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL,
5400bbcfd5peter		    &resvport_only, sizeof(resvport_only)) != 0 &&
5410bbcfd5peter		    errno != ENOENT) {
542c0dad1fguido			syslog(LOG_ERR, "sysctl: %m");
543c0dad1fguido			exit(1);
544c0dad1fguido		}
5458db0f5fguido	}
546f67e4a8alfred
547d3d824bmatteo	/*
548d3d824bmatteo	 * If no hosts were specified, add a wildcard entry to bind to
549d3d824bmatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
550d3d824bmatteo	 * list.
551d3d824bmatteo	 */
552d3d824bmatteo	if (nhosts == 0) {
55311e0dd6uqs		hosts = malloc(sizeof(char *));
554d3d824bmatteo		if (hosts == NULL)
555d3d824bmatteo			out_of_mem();
556d3d824bmatteo		hosts[0] = "*";
557d3d824bmatteo		nhosts = 1;
558d3d824bmatteo	} else {
559d3d824bmatteo		hosts_bak = hosts;
560d3d824bmatteo		if (have_v6) {
561d3d824bmatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
562d3d824bmatteo			    sizeof(char *));
563d3d824bmatteo			if (hosts_bak == NULL) {
564d3d824bmatteo				for (k = 0; k < nhosts; k++)
565d3d824bmatteo					free(hosts[k]);
566d3d824bmatteo		    		free(hosts);
567d3d824bmatteo		    		out_of_mem();
568d3d824bmatteo			} else
569d3d824bmatteo				hosts = hosts_bak;
570d3d824bmatteo			nhosts += 2;
571d3d824bmatteo			hosts[nhosts - 2] = "::1";
572d3d824bmatteo		} else {
573d3d824bmatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
574d3d824bmatteo			if (hosts_bak == NULL) {
575d3d824bmatteo				for (k = 0; k < nhosts; k++)
576d3d824bmatteo					free(hosts[k]);
577d3d824bmatteo				free(hosts);
578d3d824bmatteo				out_of_mem();
579d3d824bmatteo			} else {
580d3d824bmatteo				nhosts += 1;
581d3d824bmatteo				hosts = hosts_bak;
582f67e4a8alfred			}
583d3d824bmatteo		}
584f67e4a8alfred
585d3d824bmatteo		hosts[nhosts - 1] = "127.0.0.1";
586f67e4a8alfred	}
587f67e4a8alfred
588