xref: /freebsd/usr.sbin/mountd/mountd.c (revision 3df987c99d1194a0e43a84853e934aa0c0ab09db)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
48fae3551SRodney W. Grimes  * Copyright (c) 1989, 1993
58fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
68fae3551SRodney W. Grimes  *
78fae3551SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
88fae3551SRodney W. Grimes  * Herb Hasler and Rick Macklem at The University of Guelph.
98fae3551SRodney W. Grimes  *
108fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
118fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
128fae3551SRodney W. Grimes  * are met:
138fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
148fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
158fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
168fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
178fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
198fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
208fae3551SRodney W. Grimes  *    without specific prior written permission.
218fae3551SRodney W. Grimes  *
228fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
238fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
268fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
278fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
288fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
298fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
308fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
318fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328fae3551SRodney W. Grimes  * SUCH DAMAGE.
338fae3551SRodney W. Grimes  */
348fae3551SRodney W. Grimes 
358fae3551SRodney W. Grimes #include <sys/param.h>
363e2d36ffSRick Macklem #include <sys/conf.h>
378360efbdSAlfred Perlstein #include <sys/fcntl.h>
3846a6b5c4SRick Macklem #include <sys/fnv_hash.h>
3991ca1a91SIan Dowse #include <sys/linker.h>
4091ca1a91SIan Dowse #include <sys/module.h>
41bcc1d071SRick Macklem #include <sys/mount.h>
42c9ac0f71SEmmanuel Vadot #include <sys/queue.h>
43bcc1d071SRick Macklem #include <sys/stat.h>
44bcc1d071SRick Macklem #include <sys/sysctl.h>
45bcc1d071SRick Macklem #include <sys/syslog.h>
468fae3551SRodney W. Grimes 
478fae3551SRodney W. Grimes #include <rpc/rpc.h>
48bcb53b16SMartin Blapp #include <rpc/rpc_com.h>
498fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h>
508360efbdSAlfred Perlstein #include <rpc/pmap_prot.h>
518360efbdSAlfred Perlstein #include <rpcsvc/mount.h>
52a62dc406SDoug Rabson #include <nfs/nfsproto.h>
53bcc1d071SRick Macklem #include <nfs/nfssvc.h>
5491196234SPeter Wemm #include <nfsserver/nfs.h>
558fae3551SRodney W. Grimes 
56bcc1d071SRick Macklem #include <fs/nfs/nfsport.h>
57bcc1d071SRick Macklem 
588fae3551SRodney W. Grimes #include <arpa/inet.h>
598fae3551SRodney W. Grimes 
608fae3551SRodney W. Grimes #include <ctype.h>
6174853402SPhilippe Charnier #include <err.h>
628fae3551SRodney W. Grimes #include <errno.h>
638fae3551SRodney W. Grimes #include <grp.h>
64a032b226SPawel Jakub Dawidek #include <libutil.h>
6589fdc4e1SMike Barcroft #include <limits.h>
668fae3551SRodney W. Grimes #include <netdb.h>
678fae3551SRodney W. Grimes #include <pwd.h>
688fae3551SRodney W. Grimes #include <signal.h>
698fae3551SRodney W. Grimes #include <stdio.h>
708fae3551SRodney W. Grimes #include <stdlib.h>
718fae3551SRodney W. Grimes #include <string.h>
728fae3551SRodney W. Grimes #include <unistd.h>
737c5146daSDan Mcgregor #include <vis.h>
748fae3551SRodney W. Grimes #include "pathnames.h"
756a09faf2SCraig Rodrigues #include "mntopts.h"
768fae3551SRodney W. Grimes 
778fae3551SRodney W. Grimes #ifdef DEBUG
788fae3551SRodney W. Grimes #include <stdarg.h>
798fae3551SRodney W. Grimes #endif
808fae3551SRodney W. Grimes 
818fae3551SRodney W. Grimes /*
828fae3551SRodney W. Grimes  * Structures for keeping the mount list and export list
838fae3551SRodney W. Grimes  */
848fae3551SRodney W. Grimes struct mountlist {
850775314bSDoug Rabson 	char	ml_host[MNTNAMLEN+1];
860775314bSDoug Rabson 	char	ml_dirp[MNTPATHLEN+1];
871da3e8b0SEmmanuel Vadot 
881da3e8b0SEmmanuel Vadot 	SLIST_ENTRY(mountlist)	next;
898fae3551SRodney W. Grimes };
908fae3551SRodney W. Grimes 
918fae3551SRodney W. Grimes struct dirlist {
928fae3551SRodney W. Grimes 	struct dirlist	*dp_left;
938fae3551SRodney W. Grimes 	struct dirlist	*dp_right;
948fae3551SRodney W. Grimes 	int		dp_flag;
958fae3551SRodney W. Grimes 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
96380a3fcdSEmmanuel Vadot 	char		*dp_dirp;
978fae3551SRodney W. Grimes };
988fae3551SRodney W. Grimes /* dp_flag bits */
998fae3551SRodney W. Grimes #define	DP_DEFSET	0x1
100a62dc406SDoug Rabson #define DP_HOSTSET	0x2
1018fae3551SRodney W. Grimes 
102cc5efddeSRick Macklem /*
103cc5efddeSRick Macklem  * maproot/mapall credentials.
1042ffad162SRick Macklem  * cr_smallgrps can be used for a group list up to SMALLNGROUPS in size.
1052ffad162SRick Macklem  * Larger group lists are malloc'd/free'd.
106cc5efddeSRick Macklem  */
1072ffad162SRick Macklem #define	SMALLNGROUPS	32
108cc5efddeSRick Macklem struct expcred {
109cc5efddeSRick Macklem 	uid_t		cr_uid;
110cc5efddeSRick Macklem 	int		cr_ngroups;
1112ffad162SRick Macklem 	gid_t		cr_smallgrps[SMALLNGROUPS];
1122ffad162SRick Macklem 	gid_t		*cr_groups;
113cc5efddeSRick Macklem };
114cc5efddeSRick Macklem 
1158fae3551SRodney W. Grimes struct exportlist {
1168fae3551SRodney W. Grimes 	struct dirlist	*ex_dirl;
1178fae3551SRodney W. Grimes 	struct dirlist	*ex_defdir;
118711d44eeSRick Macklem 	struct grouplist *ex_grphead;
1198fae3551SRodney W. Grimes 	int		ex_flag;
1208fae3551SRodney W. Grimes 	fsid_t		ex_fs;
1218fae3551SRodney W. Grimes 	char		*ex_fsdir;
122cb3923e0SDoug Rabson 	char		*ex_indexfile;
123cc5efddeSRick Macklem 	struct expcred	ex_defanon;
124cc5efddeSRick Macklem 	uint64_t	ex_defexflags;
125a9148abdSDoug Rabson 	int		ex_numsecflavors;
126a9148abdSDoug Rabson 	int		ex_secflavors[MAXSECFLAVORS];
127c3f86a25SRick Macklem 	int		ex_defnumsecflavors;
128c3f86a25SRick Macklem 	int		ex_defsecflavors[MAXSECFLAVORS];
129c9ac0f71SEmmanuel Vadot 
130c9ac0f71SEmmanuel Vadot 	SLIST_ENTRY(exportlist) entries;
1318fae3551SRodney W. Grimes };
1328fae3551SRodney W. Grimes /* ex_flag bits */
133fefb7c39SRick Macklem #define	EX_LINKED	0x01
134fefb7c39SRick Macklem #define	EX_DONE		0x02
135fefb7c39SRick Macklem #define	EX_DEFSET	0x04
136fefb7c39SRick Macklem #define	EX_PUBLICFH	0x08
137fefb7c39SRick Macklem #define	EX_ADMINWARN	0x10
1388fae3551SRodney W. Grimes 
1391a9a992fSRick Macklem SLIST_HEAD(exportlisthead, exportlist);
1401a9a992fSRick Macklem 
1418fae3551SRodney W. Grimes struct netmsk {
1428360efbdSAlfred Perlstein 	struct sockaddr_storage nt_net;
14360caaee2SIan Dowse 	struct sockaddr_storage nt_mask;
1448fae3551SRodney W. Grimes 	char		*nt_name;
1458fae3551SRodney W. Grimes };
1468fae3551SRodney W. Grimes 
1478fae3551SRodney W. Grimes union grouptypes {
1488360efbdSAlfred Perlstein 	struct addrinfo *gt_addrinfo;
1498fae3551SRodney W. Grimes 	struct netmsk	gt_net;
1508fae3551SRodney W. Grimes };
1518fae3551SRodney W. Grimes 
1528fae3551SRodney W. Grimes struct grouplist {
1538fae3551SRodney W. Grimes 	int gr_type;
1548fae3551SRodney W. Grimes 	union grouptypes gr_ptr;
1558fae3551SRodney W. Grimes 	struct grouplist *gr_next;
156cc5efddeSRick Macklem 	struct expcred gr_anon;
157cc5efddeSRick Macklem 	uint64_t gr_exflags;
1580f0869bcSRick Macklem 	int gr_flag;
159c3f86a25SRick Macklem 	int gr_numsecflavors;
160c3f86a25SRick Macklem 	int gr_secflavors[MAXSECFLAVORS];
1618fae3551SRodney W. Grimes };
1628fae3551SRodney W. Grimes /* Group types */
1638fae3551SRodney W. Grimes #define	GT_NULL		0x0
1648fae3551SRodney W. Grimes #define	GT_HOST		0x1
1658fae3551SRodney W. Grimes #define	GT_NET		0x2
1666d359f31SIan Dowse #define	GT_DEFAULT	0x3
1678b5a6d67SBill Paul #define GT_IGNORE	0x5
1688fae3551SRodney W. Grimes 
1690f0869bcSRick Macklem /* Group flags */
1700f0869bcSRick Macklem #define	GR_FND		0x1
1710f0869bcSRick Macklem 
1728fae3551SRodney W. Grimes struct hostlist {
173a62dc406SDoug Rabson 	int		 ht_flag;	/* Uses DP_xx bits */
1748fae3551SRodney W. Grimes 	struct grouplist *ht_grp;
1758fae3551SRodney W. Grimes 	struct hostlist	 *ht_next;
1768fae3551SRodney W. Grimes };
1778fae3551SRodney W. Grimes 
178a62dc406SDoug Rabson struct fhreturn {
179a62dc406SDoug Rabson 	int	fhr_flag;
180a62dc406SDoug Rabson 	int	fhr_vers;
181a62dc406SDoug Rabson 	nfsfh_t	fhr_fh;
182a9148abdSDoug Rabson 	int	fhr_numsecflavors;
183a9148abdSDoug Rabson 	int	*fhr_secflavors;
184a62dc406SDoug Rabson };
185a62dc406SDoug Rabson 
1868fb6ad5dSRick Macklem #define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
1878fb6ad5dSRick Macklem 
1887674d489SRick Macklem /*
1897674d489SRick Macklem  * How long to delay a reload of exports when there are RPC request(s)
1907674d489SRick Macklem  * to process, in usec.  Must be less than 1second.
1917674d489SRick Macklem  */
1927674d489SRick Macklem #define	RELOADDELAY	250000
1937674d489SRick Macklem 
1948fae3551SRodney W. Grimes /* Global defs */
19519c46d8cSEdward Tomasz Napierala static char	*add_expdir(struct dirlist **, char *, int);
19619c46d8cSEdward Tomasz Napierala static void	add_dlist(struct dirlist **, struct dirlist *,
1970f0869bcSRick Macklem 		    struct grouplist *, int, struct exportlist *,
198cc5efddeSRick Macklem 		    struct expcred *, uint64_t);
19919c46d8cSEdward Tomasz Napierala static void	add_mlist(char *, char *);
200572b77f8SAlexander Motin static int	check_path_component(const char *, char **);
201572b77f8SAlexander Motin static int	check_dirpath(char *, char **);
202572b77f8SAlexander Motin static int	check_statfs(const char *, struct statfs *, char **);
20319c46d8cSEdward Tomasz Napierala static int	check_options(struct dirlist *);
20419c46d8cSEdward Tomasz Napierala static int	checkmask(struct sockaddr *sa);
20519c46d8cSEdward Tomasz Napierala static int	chk_host(struct dirlist *, struct sockaddr *, int *, int *,
20619c46d8cSEdward Tomasz Napierala 		    int *, int **);
207b875c2e9SJosh Paetzel static char	*strsep_quote(char **stringp, const char *delim);
2088fb6ad5dSRick Macklem static int	create_service(struct netconfig *nconf);
2098fb6ad5dSRick Macklem static void	complete_service(struct netconfig *nconf, char *port_str);
2108fb6ad5dSRick Macklem static void	clearout_service(void);
21119c46d8cSEdward Tomasz Napierala static void	del_mlist(char *hostp, char *dirp);
21219c46d8cSEdward Tomasz Napierala static struct dirlist	*dirp_search(struct dirlist *, char *);
2130f0869bcSRick Macklem static int	do_export_mount(struct exportlist *, struct statfs *);
214cc5efddeSRick Macklem static int	do_mount(struct exportlist *, struct grouplist *, uint64_t,
215cc5efddeSRick Macklem 		    struct expcred *, char *, int, struct statfs *, int, int *);
21619c46d8cSEdward Tomasz Napierala static int	do_opt(char **, char **, struct exportlist *,
217cc5efddeSRick Macklem 		    struct grouplist *, int *, uint64_t *, struct expcred *);
2181a9a992fSRick Macklem static struct exportlist	*ex_search(fsid_t *, struct exportlisthead *);
21919c46d8cSEdward Tomasz Napierala static struct exportlist	*get_exp(void);
22019c46d8cSEdward Tomasz Napierala static void	free_dir(struct dirlist *);
22119c46d8cSEdward Tomasz Napierala static void	free_exp(struct exportlist *);
22219c46d8cSEdward Tomasz Napierala static void	free_grp(struct grouplist *);
22319c46d8cSEdward Tomasz Napierala static void	free_host(struct hostlist *);
2240f0869bcSRick Macklem static void	free_v4rootexp(void);
2250f0869bcSRick Macklem static void	get_exportlist_one(int);
2260f0869bcSRick Macklem static void	get_exportlist(int);
2271a9a992fSRick Macklem static void	insert_exports(struct exportlist *, struct exportlisthead *);
2281a9a992fSRick Macklem static void	free_exports(struct exportlisthead *);
2290f0869bcSRick Macklem static void	read_exportfile(int);
2300f0869bcSRick Macklem static int	compare_nmount_exportlist(struct iovec *, int, char *);
2310f0869bcSRick Macklem static int	compare_export(struct exportlist *, struct exportlist *);
232cc5efddeSRick Macklem static int	compare_cred(struct expcred *, struct expcred *);
2330f0869bcSRick Macklem static int	compare_secflavor(int *, int *, int);
2343e08dc74SRick Macklem static void	delete_export(struct iovec *, int, struct statfs *, char *);
23519c46d8cSEdward Tomasz Napierala static int	get_host(char *, struct grouplist *, struct grouplist *);
23619c46d8cSEdward Tomasz Napierala static struct hostlist *get_ht(void);
23719c46d8cSEdward Tomasz Napierala static int	get_line(void);
23819c46d8cSEdward Tomasz Napierala static void	get_mountlist(void);
23919c46d8cSEdward Tomasz Napierala static int	get_net(char *, struct netmsk *, int);
240354fce28SConrad Meyer static void	getexp_err(struct exportlist *, struct grouplist *, const char *);
24119c46d8cSEdward Tomasz Napierala static struct grouplist	*get_grp(void);
24219c46d8cSEdward Tomasz Napierala static void	hang_dirp(struct dirlist *, struct grouplist *,
243cc5efddeSRick Macklem 		    struct exportlist *, int, struct expcred *, uint64_t);
24419c46d8cSEdward Tomasz Napierala static void	huphandler(int sig);
24519c46d8cSEdward Tomasz Napierala static int	makemask(struct sockaddr_storage *ssp, int bitlen);
24619c46d8cSEdward Tomasz Napierala static void	mntsrv(struct svc_req *, SVCXPRT *);
24719c46d8cSEdward Tomasz Napierala static void	nextfield(char **, char **);
24819c46d8cSEdward Tomasz Napierala static void	out_of_mem(void);
249cc5efddeSRick Macklem static void	parsecred(char *, struct expcred *);
25019c46d8cSEdward Tomasz Napierala static int	parsesec(char *, struct exportlist *);
25119c46d8cSEdward Tomasz Napierala static int	put_exlist(struct dirlist *, XDR *, struct dirlist *,
25219c46d8cSEdward Tomasz Napierala 		    int *, int);
25319c46d8cSEdward Tomasz Napierala static void	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
25419c46d8cSEdward Tomasz Napierala static int	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
25560caaee2SIan Dowse 		    struct sockaddr *samask);
25619c46d8cSEdward Tomasz Napierala static int	scan_tree(struct dirlist *, struct sockaddr *);
25785429990SWarner Losh static void	usage(void);
25819c46d8cSEdward Tomasz Napierala static int	xdr_dir(XDR *, char *);
25919c46d8cSEdward Tomasz Napierala static int	xdr_explist(XDR *, caddr_t);
26019c46d8cSEdward Tomasz Napierala static int	xdr_explist_brief(XDR *, caddr_t);
26119c46d8cSEdward Tomasz Napierala static int	xdr_explist_common(XDR *, caddr_t, int);
26219c46d8cSEdward Tomasz Napierala static int	xdr_fhs(XDR *, caddr_t);
26319c46d8cSEdward Tomasz Napierala static int	xdr_mlist(XDR *, caddr_t);
26419c46d8cSEdward Tomasz Napierala static void	terminate(int);
265cc5efddeSRick Macklem static void	cp_cred(struct expcred *, struct expcred *);
2668fae3551SRodney W. Grimes 
26746a6b5c4SRick Macklem #define	EXPHASH(f)	(fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize)
26846a6b5c4SRick Macklem static struct exportlisthead *exphead = NULL;
2690f0869bcSRick Macklem static struct exportlisthead *oldexphead = NULL;
27046a6b5c4SRick Macklem static int exphashsize = 0;
2711a9a992fSRick Macklem static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead);
27219c46d8cSEdward Tomasz Napierala static char *exnames_default[2] = { _PATH_EXPORTS, NULL };
27319c46d8cSEdward Tomasz Napierala static char **exnames;
27419c46d8cSEdward Tomasz Napierala static char **hosts = NULL;
27519c46d8cSEdward Tomasz Napierala static int force_v2 = 0;
276fefb7c39SRick Macklem static int warn_admin = 1;
27719c46d8cSEdward Tomasz Napierala static int resvport_only = 1;
27819c46d8cSEdward Tomasz Napierala static int nhosts = 0;
27919c46d8cSEdward Tomasz Napierala static int dir_only = 1;
28019c46d8cSEdward Tomasz Napierala static int dolog = 0;
28124092311SRick Macklem static _Atomic(int) got_sighup = 0;
28219c46d8cSEdward Tomasz Napierala static int xcreated = 0;
283d11e3645SMatteo Riondato 
28419c46d8cSEdward Tomasz Napierala static char *svcport_str = NULL;
2858fb6ad5dSRick Macklem static int mallocd_svcport = 0;
2868fb6ad5dSRick Macklem static int *sock_fd;
2878fb6ad5dSRick Macklem static int sock_fdcnt;
2888fb6ad5dSRick Macklem static int sock_fdpos;
289c548eb5cSRick Macklem static int suspend_nfsd = 0;
2907c2901b0SJoyu Liao static int nofork = 0;
2917c2901b0SJoyu Liao static int skiplocalhost = 0;
2928360efbdSAlfred Perlstein 
29319c46d8cSEdward Tomasz Napierala static int opt_flags;
2948360efbdSAlfred Perlstein static int have_v6 = 1;
2958360efbdSAlfred Perlstein 
29619c46d8cSEdward Tomasz Napierala static int v4root_phase = 0;
29719c46d8cSEdward Tomasz Napierala static char v4root_dirpath[PATH_MAX + 1];
2980f0869bcSRick Macklem static struct exportlist *v4root_ep = NULL;
29919c46d8cSEdward Tomasz Napierala static int has_publicfh = 0;
3000f0869bcSRick Macklem static int has_set_publicfh = 0;
301bcc1d071SRick Macklem 
30219c46d8cSEdward Tomasz Napierala static struct pidfh *pfh = NULL;
30360caaee2SIan Dowse /* Bits for opt_flags above */
3048fae3551SRodney W. Grimes #define	OP_MAPROOT	0x01
3058fae3551SRodney W. Grimes #define	OP_MAPALL	0x02
30691196234SPeter Wemm /* 0x4 free */
3078fae3551SRodney W. Grimes #define	OP_MASK		0x08
3088fae3551SRodney W. Grimes #define	OP_NET		0x10
3098fae3551SRodney W. Grimes #define	OP_ALLDIRS	0x40
31060caaee2SIan Dowse #define	OP_HAVEMASK	0x80	/* A mask was specified or inferred. */
311288fa14aSJoerg Wunsch #define	OP_QUIET	0x100
3128360efbdSAlfred Perlstein #define OP_MASKLEN	0x200
313a9148abdSDoug Rabson #define OP_SEC		0x400
31448514c57SMike Karels #define OP_CLASSMASK	0x800	/* mask not specified, is Class A/B/C default */
3158fae3551SRodney W. Grimes 
3168fae3551SRodney W. Grimes #ifdef DEBUG
31719c46d8cSEdward Tomasz Napierala static int debug = 1;
31819c46d8cSEdward Tomasz Napierala static void	SYSLOG(int, const char *, ...) __printflike(2, 3);
3198fae3551SRodney W. Grimes #define syslog SYSLOG
3208fae3551SRodney W. Grimes #else
32119c46d8cSEdward Tomasz Napierala static int debug = 0;
3228fae3551SRodney W. Grimes #endif
3238fae3551SRodney W. Grimes 
3248fae3551SRodney W. Grimes /*
3250f0869bcSRick Macklem  * The LOGDEBUG() syslog() calls are always compiled into the daemon.
3260f0869bcSRick Macklem  * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty.
3270f0869bcSRick Macklem  * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG.
3280f0869bcSRick Macklem  */
3290f0869bcSRick Macklem static int logdebug = 0;
3300f0869bcSRick Macklem #define	LOGDEBUG(format, ...)						\
3310f0869bcSRick Macklem     (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0)
3320f0869bcSRick Macklem 
3330f0869bcSRick Macklem /*
334b875c2e9SJosh Paetzel  * Similar to strsep(), but it allows for quoted strings
335b875c2e9SJosh Paetzel  * and escaped characters.
336b875c2e9SJosh Paetzel  *
337b875c2e9SJosh Paetzel  * It returns the string (or NULL, if *stringp is NULL),
338b875c2e9SJosh Paetzel  * which is a de-quoted version of the string if necessary.
339b875c2e9SJosh Paetzel  *
340b875c2e9SJosh Paetzel  * It modifies *stringp in place.
341b875c2e9SJosh Paetzel  */
342b875c2e9SJosh Paetzel static char *
strsep_quote(char ** stringp,const char * delim)343b875c2e9SJosh Paetzel strsep_quote(char **stringp, const char *delim)
344b875c2e9SJosh Paetzel {
345b875c2e9SJosh Paetzel 	char *srcptr, *dstptr, *retval;
346b875c2e9SJosh Paetzel 	char quot = 0;
347b875c2e9SJosh Paetzel 
348b875c2e9SJosh Paetzel 	if (stringp == NULL || *stringp == NULL)
349b875c2e9SJosh Paetzel 		return (NULL);
350b875c2e9SJosh Paetzel 
351b875c2e9SJosh Paetzel 	srcptr = dstptr = retval = *stringp;
352b875c2e9SJosh Paetzel 
353b875c2e9SJosh Paetzel 	while (*srcptr) {
354b875c2e9SJosh Paetzel 		/*
355b875c2e9SJosh Paetzel 		 * We're looking for several edge cases here.
356b875c2e9SJosh Paetzel 		 * First:  if we're in quote state (quot != 0),
357b875c2e9SJosh Paetzel 		 * then we ignore the delim characters, but otherwise
358b875c2e9SJosh Paetzel 		 * process as normal, unless it is the quote character.
359b875c2e9SJosh Paetzel 		 * Second:  if the current character is a backslash,
360b875c2e9SJosh Paetzel 		 * we take the next character as-is, without checking
361b875c2e9SJosh Paetzel 		 * for delim, quote, or backslash.  Exception:  if the
362b875c2e9SJosh Paetzel 		 * next character is a NUL, that's the end of the string.
363b875c2e9SJosh Paetzel 		 * Third:  if the character is a quote character, we toggle
364b875c2e9SJosh Paetzel 		 * quote state.
365b875c2e9SJosh Paetzel 		 * Otherwise:  check the current character for NUL, or
366b875c2e9SJosh Paetzel 		 * being in delim, and end the string if either is true.
367b875c2e9SJosh Paetzel 		 */
368b875c2e9SJosh Paetzel 		if (*srcptr == '\\') {
369b875c2e9SJosh Paetzel 			srcptr++;
370b875c2e9SJosh Paetzel 			/*
371b875c2e9SJosh Paetzel 			 * The edge case here is if the next character
372b875c2e9SJosh Paetzel 			 * is NUL, we want to stop processing.  But if
373b875c2e9SJosh Paetzel 			 * it's not NUL, then we simply want to copy it.
374b875c2e9SJosh Paetzel 			 */
375b875c2e9SJosh Paetzel 			if (*srcptr) {
376b875c2e9SJosh Paetzel 				*dstptr++ = *srcptr++;
377b875c2e9SJosh Paetzel 			}
378b875c2e9SJosh Paetzel 			continue;
379b875c2e9SJosh Paetzel 		}
380b875c2e9SJosh Paetzel 		if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) {
381b875c2e9SJosh Paetzel 			quot = *srcptr++;
382b875c2e9SJosh Paetzel 			continue;
383b875c2e9SJosh Paetzel 		}
384b875c2e9SJosh Paetzel 		if (quot && *srcptr == quot) {
385b875c2e9SJosh Paetzel 			/* End of the quoted part */
386b875c2e9SJosh Paetzel 			quot = 0;
387b875c2e9SJosh Paetzel 			srcptr++;
388b875c2e9SJosh Paetzel 			continue;
389b875c2e9SJosh Paetzel 		}
390b875c2e9SJosh Paetzel 		if (!quot && strchr(delim, *srcptr))
391b875c2e9SJosh Paetzel 			break;
392b875c2e9SJosh Paetzel 		*dstptr++ = *srcptr++;
393b875c2e9SJosh Paetzel 	}
394b875c2e9SJosh Paetzel 
395b875c2e9SJosh Paetzel 	*stringp = (*srcptr == '\0') ? NULL : srcptr + 1;
3964ae6e084SAlexander Motin 	*dstptr = 0; /* Terminate the string */
397b875c2e9SJosh Paetzel 	return (retval);
398b875c2e9SJosh Paetzel }
399b875c2e9SJosh Paetzel 
400b875c2e9SJosh Paetzel /*
4018fae3551SRodney W. Grimes  * Mountd server for NFS mount protocol as described in:
4028fae3551SRodney W. Grimes  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
4038fae3551SRodney W. Grimes  * The optional arguments are the exports file name
4048fae3551SRodney W. Grimes  * default: _PATH_EXPORTS
4058fae3551SRodney W. Grimes  * and "-n" to allow nonroot mount.
4068fae3551SRodney W. Grimes  */
4078fae3551SRodney W. Grimes int
main(int argc,char ** argv)408a7a7d96cSPhilippe Charnier main(int argc, char **argv)
4098fae3551SRodney W. Grimes {
41069d65572SIan Dowse 	fd_set readfds;
411d11e3645SMatteo Riondato 	struct netconfig *nconf;
412d11e3645SMatteo Riondato 	char *endptr, **hosts_bak;
413d11e3645SMatteo Riondato 	void *nc_handle;
414a032b226SPawel Jakub Dawidek 	pid_t otherpid;
415d11e3645SMatteo Riondato 	in_port_t svcport;
416d11e3645SMatteo Riondato 	int c, k, s;
417bcb53b16SMartin Blapp 	int maxrec = RPC_MAXDATASIZE;
4188fb6ad5dSRick Macklem 	int attempt_cnt, port_len, port_pos, ret;
4198fb6ad5dSRick Macklem 	char **port_list;
4207674d489SRick Macklem 	uint64_t curtime, nexttime;
4217674d489SRick Macklem 	struct timeval tv;
4227674d489SRick Macklem 	struct timespec tp;
423bde6f938SRick Macklem 	sigset_t sig_mask, sighup_mask;
424bde6f938SRick Macklem 	int enable_rpcbind;
4258360efbdSAlfred Perlstein 
426bde6f938SRick Macklem 	enable_rpcbind = 1;
42701709abfSIan Dowse 	/* Check that another mountd isn't already running. */
4288b28aef2SPawel Jakub Dawidek 	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
429a032b226SPawel Jakub Dawidek 	if (pfh == NULL) {
430a032b226SPawel Jakub Dawidek 		if (errno == EEXIST)
431a032b226SPawel Jakub Dawidek 			errx(1, "mountd already running, pid: %d.", otherpid);
432a032b226SPawel Jakub Dawidek 		warn("cannot open or create pidfile");
433a032b226SPawel Jakub Dawidek 	}
4348360efbdSAlfred Perlstein 
4358360efbdSAlfred Perlstein 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
4368360efbdSAlfred Perlstein 	if (s < 0)
4378360efbdSAlfred Perlstein 		have_v6 = 0;
4388360efbdSAlfred Perlstein 	else
4398360efbdSAlfred Perlstein 		close(s);
4408fae3551SRodney W. Grimes 
4417c2901b0SJoyu Liao 	while ((c = getopt(argc, argv, "2Adeh:lNnp:RrSs")) != -1)
4428fae3551SRodney W. Grimes 		switch (c) {
4432a66cfc5SDoug Rabson 		case '2':
4442a66cfc5SDoug Rabson 			force_v2 = 1;
4452a66cfc5SDoug Rabson 			break;
446fefb7c39SRick Macklem 		case 'A':
447fefb7c39SRick Macklem 			warn_admin = 0;
448fefb7c39SRick Macklem 			break;
4492179ae1eSRick Macklem 		case 'e':
4502a85df8cSRick Macklem 			/* now a no-op, since this is the default */
451bcc1d071SRick Macklem 			break;
452a62dc406SDoug Rabson 		case 'n':
453a62dc406SDoug Rabson 			resvport_only = 0;
454a62dc406SDoug Rabson 			break;
455bde6f938SRick Macklem 		case 'R':
456bde6f938SRick Macklem 			/* Do not support Mount protocol */
457bde6f938SRick Macklem 			enable_rpcbind = 0;
458bde6f938SRick Macklem 			break;
459a62dc406SDoug Rabson 		case 'r':
460a62dc406SDoug Rabson 			dir_only = 0;
461a62dc406SDoug Rabson 			break;
4626444ef3bSPoul-Henning Kamp 		case 'd':
4636444ef3bSPoul-Henning Kamp 			debug = debug ? 0 : 1;
4646444ef3bSPoul-Henning Kamp 			break;
465f51631d7SGuido van Rooij 		case 'l':
466c903443aSPeter Wemm 			dolog = 1;
467f51631d7SGuido van Rooij 			break;
468c203da27SBruce M Simpson 		case 'p':
469c203da27SBruce M Simpson 			endptr = NULL;
470c203da27SBruce M Simpson 			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
471c203da27SBruce M Simpson 			if (endptr == NULL || *endptr != '\0' ||
472c203da27SBruce M Simpson 			    svcport == 0 || svcport >= IPPORT_MAX)
473c203da27SBruce M Simpson 				usage();
474d11e3645SMatteo Riondato 			svcport_str = strdup(optarg);
475d11e3645SMatteo Riondato 			break;
476d11e3645SMatteo Riondato 		case 'h':
477d11e3645SMatteo Riondato 			++nhosts;
478d11e3645SMatteo Riondato 			hosts_bak = hosts;
479d11e3645SMatteo Riondato 			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
480d11e3645SMatteo Riondato 			if (hosts_bak == NULL) {
481d11e3645SMatteo Riondato 				if (hosts != NULL) {
482d11e3645SMatteo Riondato 					for (k = 0; k < nhosts; k++)
483d11e3645SMatteo Riondato 						free(hosts[k]);
484d11e3645SMatteo Riondato 					free(hosts);
485d11e3645SMatteo Riondato 					out_of_mem();
486d11e3645SMatteo Riondato 				}
487d11e3645SMatteo Riondato 			}
488d11e3645SMatteo Riondato 			hosts = hosts_bak;
489d11e3645SMatteo Riondato 			hosts[nhosts - 1] = strdup(optarg);
490d11e3645SMatteo Riondato 			if (hosts[nhosts - 1] == NULL) {
491d11e3645SMatteo Riondato 				for (k = 0; k < (nhosts - 1); k++)
492d11e3645SMatteo Riondato 					free(hosts[k]);
493d11e3645SMatteo Riondato 				free(hosts);
494d11e3645SMatteo Riondato 				out_of_mem();
495d11e3645SMatteo Riondato 			}
496c203da27SBruce M Simpson 			break;
497c548eb5cSRick Macklem 		case 'S':
498c548eb5cSRick Macklem 			suspend_nfsd = 1;
499c548eb5cSRick Macklem 			break;
5007c2901b0SJoyu Liao 		case 'N':
5017c2901b0SJoyu Liao 			nofork = 1;
5027c2901b0SJoyu Liao 			break;
5037c2901b0SJoyu Liao 		case 's':
5047c2901b0SJoyu Liao 			skiplocalhost = 1;
5057c2901b0SJoyu Liao 			break;
5068fae3551SRodney W. Grimes 		default:
50774853402SPhilippe Charnier 			usage();
50880c7cc1cSPedro F. Giffuni 		}
509bde6f938SRick Macklem 	if (enable_rpcbind == 0) {
510bde6f938SRick Macklem 		if (svcport_str != NULL) {
511bde6f938SRick Macklem 			warnx("-p option not compatible with -R, ignored");
512bde6f938SRick Macklem 			free(svcport_str);
513bde6f938SRick Macklem 			svcport_str = NULL;
514bde6f938SRick Macklem 		}
515bde6f938SRick Macklem 		if (nhosts > 0) {
516bde6f938SRick Macklem 			warnx("-h option not compatible with -R, ignored");
517bde6f938SRick Macklem 			for (k = 0; k < nhosts; k++)
518bde6f938SRick Macklem 				free(hosts[k]);
519bde6f938SRick Macklem 			free(hosts);
520bde6f938SRick Macklem 			hosts = NULL;
521bde6f938SRick Macklem 			nhosts = 0;
522bde6f938SRick Macklem 		}
523bde6f938SRick Macklem 	}
524bcc1d071SRick Macklem 
5257c2901b0SJoyu Liao 	if (nhosts == 0 && skiplocalhost != 0)
5267c2901b0SJoyu Liao 		warnx("-s without -h, ignored");
5277c2901b0SJoyu Liao 
528bcc1d071SRick Macklem 	if (modfind("nfsd") < 0) {
529bcc1d071SRick Macklem 		/* Not present in kernel, try loading it */
530bcc1d071SRick Macklem 		if (kldload("nfsd") < 0 || modfind("nfsd") < 0)
531bcc1d071SRick Macklem 			errx(1, "NFS server is not available");
532bcc1d071SRick Macklem 	}
533bcc1d071SRick Macklem 
5348fae3551SRodney W. Grimes 	argc -= optind;
5358fae3551SRodney W. Grimes 	argv += optind;
53696968c22SPawel Jakub Dawidek 	if (argc > 0)
53796968c22SPawel Jakub Dawidek 		exnames = argv;
53896968c22SPawel Jakub Dawidek 	else
53996968c22SPawel Jakub Dawidek 		exnames = exnames_default;
5408fae3551SRodney W. Grimes 	openlog("mountd", LOG_PID, LOG_DAEMON);
5418fae3551SRodney W. Grimes 	if (debug)
54274853402SPhilippe Charnier 		warnx("getting export list");
5430f0869bcSRick Macklem 	get_exportlist(0);
5448fae3551SRodney W. Grimes 	if (debug)
54574853402SPhilippe Charnier 		warnx("getting mount list");
5468fae3551SRodney W. Grimes 	get_mountlist();
5478fae3551SRodney W. Grimes 	if (debug)
54874853402SPhilippe Charnier 		warnx("here we go");
5497c2901b0SJoyu Liao 	if (debug == 0 && nofork == 0) {
5508fae3551SRodney W. Grimes 		daemon(0, 0);
5518fae3551SRodney W. Grimes 		signal(SIGINT, SIG_IGN);
5528fae3551SRodney W. Grimes 		signal(SIGQUIT, SIG_IGN);
5538fae3551SRodney W. Grimes 	}
55469d65572SIan Dowse 	signal(SIGHUP, huphandler);
5558360efbdSAlfred Perlstein 	signal(SIGTERM, terminate);
55609fc9dc6SCraig Rodrigues 	signal(SIGPIPE, SIG_IGN);
557a032b226SPawel Jakub Dawidek 
558a032b226SPawel Jakub Dawidek 	pidfile_write(pfh);
559a032b226SPawel Jakub Dawidek 
560bde6f938SRick Macklem 	if (enable_rpcbind != 0) {
5610775314bSDoug Rabson 		rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
5620775314bSDoug Rabson 		rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
563bcb53b16SMartin Blapp 		rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
564bcb53b16SMartin Blapp 
565c6e5e158SGuido van Rooij 		if (!resvport_only) {
5665ebee88dSRick Macklem 			if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL,
5674a0785aaSPeter Wemm 			    &resvport_only, sizeof(resvport_only)) != 0 &&
5684a0785aaSPeter Wemm 			    errno != ENOENT) {
569394da4c1SGuido van Rooij 				syslog(LOG_ERR, "sysctl: %m");
570394da4c1SGuido van Rooij 				exit(1);
571394da4c1SGuido van Rooij 			}
572c6e5e158SGuido van Rooij 		}
573c203da27SBruce M Simpson 
574d11e3645SMatteo Riondato 		/*
575d11e3645SMatteo Riondato 		 * If no hosts were specified, add a wildcard entry to bind to
576bde6f938SRick Macklem 		 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added
577bde6f938SRick Macklem 		 * to the list.
578d11e3645SMatteo Riondato 		 */
579d11e3645SMatteo Riondato 		if (nhosts == 0) {
580c9e1c304SUlrich Spörlein 			hosts = malloc(sizeof(char *));
581d11e3645SMatteo Riondato 			if (hosts == NULL)
582d11e3645SMatteo Riondato 				out_of_mem();
583d11e3645SMatteo Riondato 			hosts[0] = "*";
584d11e3645SMatteo Riondato 			nhosts = 1;
5857c2901b0SJoyu Liao 		} else if (skiplocalhost == 0) {
586d11e3645SMatteo Riondato 			hosts_bak = hosts;
587d11e3645SMatteo Riondato 			if (have_v6) {
588d11e3645SMatteo Riondato 				hosts_bak = realloc(hosts, (nhosts + 2) *
589d11e3645SMatteo Riondato 				    sizeof(char *));
590d11e3645SMatteo Riondato 				if (hosts_bak == NULL) {
591d11e3645SMatteo Riondato 					for (k = 0; k < nhosts; k++)
592d11e3645SMatteo Riondato 						free(hosts[k]);
593d11e3645SMatteo Riondato 			    		free(hosts);
594d11e3645SMatteo Riondato 			    		out_of_mem();
595c203da27SBruce M Simpson 				} else
596d11e3645SMatteo Riondato 					hosts = hosts_bak;
597d11e3645SMatteo Riondato 				nhosts += 2;
598d11e3645SMatteo Riondato 				hosts[nhosts - 2] = "::1";
599d11e3645SMatteo Riondato 			} else {
600bde6f938SRick Macklem 				hosts_bak = realloc(hosts, (nhosts + 1) *
601bde6f938SRick Macklem 				    sizeof(char *));
602d11e3645SMatteo Riondato 				if (hosts_bak == NULL) {
603d11e3645SMatteo Riondato 					for (k = 0; k < nhosts; k++)
604d11e3645SMatteo Riondato 						free(hosts[k]);
605d11e3645SMatteo Riondato 					free(hosts);
606d11e3645SMatteo Riondato 					out_of_mem();
607d11e3645SMatteo Riondato 				} else {
608d11e3645SMatteo Riondato 					nhosts += 1;
609d11e3645SMatteo Riondato 					hosts = hosts_bak;
6108fae3551SRodney W. Grimes 				}
611d11e3645SMatteo Riondato 			}
6128360efbdSAlfred Perlstein 
613d11e3645SMatteo Riondato 			hosts[nhosts - 1] = "127.0.0.1";
6148360efbdSAlfred Perlstein 		}
615bde6f938SRick Macklem 	}
6168360efbdSAlfred Perlstein 
6178fb6ad5dSRick Macklem 	attempt_cnt = 1;
6188fb6ad5dSRick Macklem 	sock_fdcnt = 0;
6198fb6ad5dSRick Macklem 	sock_fd = NULL;
6208fb6ad5dSRick Macklem 	port_list = NULL;
6218fb6ad5dSRick Macklem 	port_len = 0;
622bde6f938SRick Macklem 	if (enable_rpcbind != 0) {
623d11e3645SMatteo Riondato 		nc_handle = setnetconfig();
624d11e3645SMatteo Riondato 		while ((nconf = getnetconfig(nc_handle))) {
625d11e3645SMatteo Riondato 			if (nconf->nc_flag & NC_VISIBLE) {
626d11e3645SMatteo Riondato 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
627d11e3645SMatteo Riondato 				    "inet6") == 0) {
628d11e3645SMatteo Riondato 					/* DO NOTHING */
6298fb6ad5dSRick Macklem 				} else {
6308fb6ad5dSRick Macklem 					ret = create_service(nconf);
6318fb6ad5dSRick Macklem 					if (ret == 1)
6328fb6ad5dSRick Macklem 						/* Ignore this call */
6338fb6ad5dSRick Macklem 						continue;
6348fb6ad5dSRick Macklem 					if (ret < 0) {
6358fb6ad5dSRick Macklem 						/*
636bde6f938SRick Macklem 						 * Failed to bind port, so close
637bde6f938SRick Macklem 						 * off all sockets created and
638bde6f938SRick Macklem 						 * try again if the port# was
639bde6f938SRick Macklem 						 * dynamically assigned via
640bde6f938SRick Macklem 						 * bind(2).
6418fb6ad5dSRick Macklem 						 */
6428fb6ad5dSRick Macklem 						clearout_service();
6438fb6ad5dSRick Macklem 						if (mallocd_svcport != 0 &&
644bde6f938SRick Macklem 						    attempt_cnt <
645bde6f938SRick Macklem 						    GETPORT_MAXTRY) {
6468fb6ad5dSRick Macklem 							free(svcport_str);
6478fb6ad5dSRick Macklem 							svcport_str = NULL;
6488fb6ad5dSRick Macklem 							mallocd_svcport = 0;
6498fb6ad5dSRick Macklem 						} else {
6508fb6ad5dSRick Macklem 							errno = EADDRINUSE;
6518fb6ad5dSRick Macklem 							syslog(LOG_ERR,
652bde6f938SRick Macklem 							    "bindresvport_sa:"
653bde6f938SRick Macklem 							    " %m");
6548fb6ad5dSRick Macklem 							exit(1);
6558fb6ad5dSRick Macklem 						}
6568fb6ad5dSRick Macklem 
657bde6f938SRick Macklem 						/*
658bde6f938SRick Macklem 						 * Start over at the first
659bde6f938SRick Macklem 						 * service.
660bde6f938SRick Macklem 						 */
6618fb6ad5dSRick Macklem 						free(sock_fd);
6628fb6ad5dSRick Macklem 						sock_fdcnt = 0;
6638fb6ad5dSRick Macklem 						sock_fd = NULL;
6648fb6ad5dSRick Macklem 						nc_handle = setnetconfig();
6658fb6ad5dSRick Macklem 						attempt_cnt++;
6668fb6ad5dSRick Macklem 					} else if (mallocd_svcport != 0 &&
6678fb6ad5dSRick Macklem 					    attempt_cnt == GETPORT_MAXTRY) {
6688fb6ad5dSRick Macklem 						/*
6698fb6ad5dSRick Macklem 						 * For the last attempt, allow
670bde6f938SRick Macklem 						 * different port #s for each
671bde6f938SRick Macklem 						 * nconf by saving the
672bde6f938SRick Macklem 						 * svcport_str setting it back
673bde6f938SRick Macklem 						 * to NULL.
6748fb6ad5dSRick Macklem 						 */
6758fb6ad5dSRick Macklem 						port_list = realloc(port_list,
676bde6f938SRick Macklem 						    (port_len + 1) *
677bde6f938SRick Macklem 						    sizeof(char *));
6788fb6ad5dSRick Macklem 						if (port_list == NULL)
6798fb6ad5dSRick Macklem 							out_of_mem();
680bde6f938SRick Macklem 						port_list[port_len++] =
681bde6f938SRick Macklem 						    svcport_str;
6828fb6ad5dSRick Macklem 						svcport_str = NULL;
6838fb6ad5dSRick Macklem 						mallocd_svcport = 0;
6848fb6ad5dSRick Macklem 					}
6858fb6ad5dSRick Macklem 				}
6868fb6ad5dSRick Macklem 			}
6878fb6ad5dSRick Macklem 		}
6888fb6ad5dSRick Macklem 
6898fb6ad5dSRick Macklem 		/*
6908fb6ad5dSRick Macklem 		 * Successfully bound the ports, so call complete_service() to
6918fb6ad5dSRick Macklem 		 * do the rest of the setup on the service(s).
6928fb6ad5dSRick Macklem 		 */
6938fb6ad5dSRick Macklem 		sock_fdpos = 0;
6948fb6ad5dSRick Macklem 		port_pos = 0;
6958fb6ad5dSRick Macklem 		nc_handle = setnetconfig();
6968fb6ad5dSRick Macklem 		while ((nconf = getnetconfig(nc_handle))) {
6978fb6ad5dSRick Macklem 			if (nconf->nc_flag & NC_VISIBLE) {
6988fb6ad5dSRick Macklem 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
6998fb6ad5dSRick Macklem 				    "inet6") == 0) {
7008fb6ad5dSRick Macklem 					/* DO NOTHING */
7018fb6ad5dSRick Macklem 				} else if (port_list != NULL) {
7028fb6ad5dSRick Macklem 					if (port_pos >= port_len) {
703bde6f938SRick Macklem 						syslog(LOG_ERR, "too many"
704bde6f938SRick Macklem 						    " port#s");
7058fb6ad5dSRick Macklem 						exit(1);
7068fb6ad5dSRick Macklem 					}
707bde6f938SRick Macklem 					complete_service(nconf,
708bde6f938SRick Macklem 					    port_list[port_pos++]);
709c203da27SBruce M Simpson 				} else
7108fb6ad5dSRick Macklem 					complete_service(nconf, svcport_str);
7118360efbdSAlfred Perlstein 			}
712d11e3645SMatteo Riondato 		}
713d11e3645SMatteo Riondato 		endnetconfig(nc_handle);
7148fb6ad5dSRick Macklem 		free(sock_fd);
7158fb6ad5dSRick Macklem 		if (port_list != NULL) {
7168fb6ad5dSRick Macklem 			for (port_pos = 0; port_pos < port_len; port_pos++)
7178fb6ad5dSRick Macklem 				free(port_list[port_pos]);
7188fb6ad5dSRick Macklem 			free(port_list);
7198fb6ad5dSRick Macklem 		}
7208360efbdSAlfred Perlstein 
7218360efbdSAlfred Perlstein 		if (xcreated == 0) {
7228360efbdSAlfred Perlstein 			syslog(LOG_ERR, "could not create any services");
7232a66cfc5SDoug Rabson 			exit(1);
7242a66cfc5SDoug Rabson 		}
725bde6f938SRick Macklem 	}
72669d65572SIan Dowse 
72769d65572SIan Dowse 	/* Expand svc_run() here so that we can call get_exportlist(). */
7287674d489SRick Macklem 	curtime = nexttime = 0;
7297674d489SRick Macklem 	sigemptyset(&sighup_mask);
7307674d489SRick Macklem 	sigaddset(&sighup_mask, SIGHUP);
73169d65572SIan Dowse 	for (;;) {
7327674d489SRick Macklem 		clock_gettime(CLOCK_MONOTONIC, &tp);
7337674d489SRick Macklem 		curtime = tp.tv_sec;
7347674d489SRick Macklem 		curtime = curtime * 1000000 + tp.tv_nsec / 1000;
735bde6f938SRick Macklem 		sigprocmask(SIG_BLOCK, &sighup_mask, &sig_mask);
7367674d489SRick Macklem 		if (got_sighup && curtime >= nexttime) {
73769d65572SIan Dowse 			got_sighup = 0;
7387674d489SRick Macklem 			sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
7397674d489SRick Macklem 			get_exportlist(1);
7407674d489SRick Macklem 			clock_gettime(CLOCK_MONOTONIC, &tp);
7417674d489SRick Macklem 			nexttime = tp.tv_sec;
7427674d489SRick Macklem 			nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 +
7437674d489SRick Macklem 			    RELOADDELAY;
7447674d489SRick Macklem 		} else
7457674d489SRick Macklem 			sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
7467674d489SRick Macklem 
7477674d489SRick Macklem 		/*
7487674d489SRick Macklem 		 * If a reload is pending, poll for received request(s),
7497674d489SRick Macklem 		 * otherwise set a RELOADDELAY timeout, since a SIGHUP
7507674d489SRick Macklem 		 * could be processed between the got_sighup test and
7517674d489SRick Macklem 		 * the select() system call.
7527674d489SRick Macklem 		 */
7537674d489SRick Macklem 		tv.tv_sec = 0;
7547674d489SRick Macklem 		if (got_sighup)
7557674d489SRick Macklem 			tv.tv_usec = 0;
7567674d489SRick Macklem 		else
7577674d489SRick Macklem 			tv.tv_usec = RELOADDELAY;
758bde6f938SRick Macklem 		if (enable_rpcbind != 0) {
75969d65572SIan Dowse 			readfds = svc_fdset;
760bde6f938SRick Macklem 			switch (select(svc_maxfd + 1, &readfds, NULL, NULL,
761bde6f938SRick Macklem 			    &tv)) {
76269d65572SIan Dowse 			case -1:
7637674d489SRick Macklem 				if (errno == EINTR) {
7647674d489SRick Macklem 					/* Allow a reload now. */
7657674d489SRick Macklem 					nexttime = 0;
76669d65572SIan Dowse 					continue;
7677674d489SRick Macklem 				}
76869d65572SIan Dowse 				syslog(LOG_ERR, "mountd died: select: %m");
76974853402SPhilippe Charnier 				exit(1);
77069d65572SIan Dowse 			case 0:
7717674d489SRick Macklem 				/* Allow a reload now. */
7727674d489SRick Macklem 				nexttime = 0;
77369d65572SIan Dowse 				continue;
77469d65572SIan Dowse 			default:
77569d65572SIan Dowse 				svc_getreqset(&readfds);
77669d65572SIan Dowse 			}
777bde6f938SRick Macklem 		} else {
778bde6f938SRick Macklem 			/* Simply wait for a signal. */
779bde6f938SRick Macklem 			sigsuspend(&sig_mask);
780bde6f938SRick Macklem 		}
78169d65572SIan Dowse 	}
78274853402SPhilippe Charnier }
78374853402SPhilippe Charnier 
784d11e3645SMatteo Riondato /*
785d11e3645SMatteo Riondato  * This routine creates and binds sockets on the appropriate
7868fb6ad5dSRick Macklem  * addresses. It gets called one time for each transport.
787afc55510SGordon Bergling  * It returns 0 upon success, 1 for ignore the call and -1 to indicate
7888fb6ad5dSRick Macklem  * bind failed with EADDRINUSE.
7898fb6ad5dSRick Macklem  * Any file descriptors that have been created are stored in sock_fd and
7908fb6ad5dSRick Macklem  * the total count of them is maintained in sock_fdcnt.
791d11e3645SMatteo Riondato  */
7928fb6ad5dSRick Macklem static int
create_service(struct netconfig * nconf)793d11e3645SMatteo Riondato create_service(struct netconfig *nconf)
794d11e3645SMatteo Riondato {
795d11e3645SMatteo Riondato 	struct addrinfo hints, *res = NULL;
796d11e3645SMatteo Riondato 	struct sockaddr_in *sin;
797d11e3645SMatteo Riondato 	struct sockaddr_in6 *sin6;
798d11e3645SMatteo Riondato 	struct __rpc_sockinfo si;
799d11e3645SMatteo Riondato 	int aicode;
800d11e3645SMatteo Riondato 	int fd;
801d11e3645SMatteo Riondato 	int nhostsbak;
802d11e3645SMatteo Riondato 	int one = 1;
803d11e3645SMatteo Riondato 	int r;
804d11e3645SMatteo Riondato 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
8058fb6ad5dSRick Macklem 	int mallocd_res;
806d11e3645SMatteo Riondato 
807d11e3645SMatteo Riondato 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
808d11e3645SMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS) &&
809d11e3645SMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
8108fb6ad5dSRick Macklem 		return (1);	/* not my type */
811d11e3645SMatteo Riondato 
812d11e3645SMatteo Riondato 	/*
813d11e3645SMatteo Riondato 	 * XXX - using RPC library internal functions.
814d11e3645SMatteo Riondato 	 */
815d11e3645SMatteo Riondato 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
816d11e3645SMatteo Riondato 		syslog(LOG_ERR, "cannot get information for %s",
817d11e3645SMatteo Riondato 		    nconf->nc_netid);
8188fb6ad5dSRick Macklem 		return (1);
819d11e3645SMatteo Riondato 	}
820d11e3645SMatteo Riondato 
821d11e3645SMatteo Riondato 	/* Get mountd's address on this transport */
822d11e3645SMatteo Riondato 	memset(&hints, 0, sizeof hints);
823d11e3645SMatteo Riondato 	hints.ai_family = si.si_af;
824d11e3645SMatteo Riondato 	hints.ai_socktype = si.si_socktype;
825d11e3645SMatteo Riondato 	hints.ai_protocol = si.si_proto;
826d11e3645SMatteo Riondato 
827d11e3645SMatteo Riondato 	/*
828d11e3645SMatteo Riondato 	 * Bind to specific IPs if asked to
829d11e3645SMatteo Riondato 	 */
830d11e3645SMatteo Riondato 	nhostsbak = nhosts;
831d11e3645SMatteo Riondato 	while (nhostsbak > 0) {
832d11e3645SMatteo Riondato 		--nhostsbak;
8338fb6ad5dSRick Macklem 		sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
8348fb6ad5dSRick Macklem 		if (sock_fd == NULL)
8358fb6ad5dSRick Macklem 			out_of_mem();
8368fb6ad5dSRick Macklem 		sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
8378fb6ad5dSRick Macklem 		mallocd_res = 0;
8388fb6ad5dSRick Macklem 
8399745de4cSRyan Stone 		hints.ai_flags = AI_PASSIVE;
8409745de4cSRyan Stone 
841d11e3645SMatteo Riondato 		/*
842d11e3645SMatteo Riondato 		 * XXX - using RPC library internal functions.
843d11e3645SMatteo Riondato 		 */
844d11e3645SMatteo Riondato 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
845d11e3645SMatteo Riondato 			int non_fatal = 0;
846a5752d55SKevin Lo 	    		if (errno == EAFNOSUPPORT &&
847d11e3645SMatteo Riondato 			    nconf->nc_semantics != NC_TPI_CLTS)
848d11e3645SMatteo Riondato 				non_fatal = 1;
849d11e3645SMatteo Riondato 
850d11e3645SMatteo Riondato 			syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
851d11e3645SMatteo Riondato 			    "cannot create socket for %s", nconf->nc_netid);
8528fb6ad5dSRick Macklem 			if (non_fatal != 0)
8538fb6ad5dSRick Macklem 				continue;
8548fb6ad5dSRick Macklem 			exit(1);
855d11e3645SMatteo Riondato 		}
856d11e3645SMatteo Riondato 
857d11e3645SMatteo Riondato 		switch (hints.ai_family) {
858d11e3645SMatteo Riondato 		case AF_INET:
859d11e3645SMatteo Riondato 			if (inet_pton(AF_INET, hosts[nhostsbak],
860d11e3645SMatteo Riondato 			    host_addr) == 1) {
8618fb6ad5dSRick Macklem 				hints.ai_flags |= AI_NUMERICHOST;
862d11e3645SMatteo Riondato 			} else {
863d11e3645SMatteo Riondato 				/*
864d11e3645SMatteo Riondato 				 * Skip if we have an AF_INET6 address.
865d11e3645SMatteo Riondato 				 */
866d11e3645SMatteo Riondato 				if (inet_pton(AF_INET6, hosts[nhostsbak],
867d11e3645SMatteo Riondato 				    host_addr) == 1) {
868d11e3645SMatteo Riondato 					close(fd);
869d11e3645SMatteo Riondato 					continue;
870d11e3645SMatteo Riondato 				}
871d11e3645SMatteo Riondato 			}
872d11e3645SMatteo Riondato 			break;
873d11e3645SMatteo Riondato 		case AF_INET6:
874d11e3645SMatteo Riondato 			if (inet_pton(AF_INET6, hosts[nhostsbak],
875d11e3645SMatteo Riondato 			    host_addr) == 1) {
8768fb6ad5dSRick Macklem 				hints.ai_flags |= AI_NUMERICHOST;
877d11e3645SMatteo Riondato 			} else {
878d11e3645SMatteo Riondato 				/*
879d11e3645SMatteo Riondato 				 * Skip if we have an AF_INET address.
880d11e3645SMatteo Riondato 				 */
881d11e3645SMatteo Riondato 				if (inet_pton(AF_INET, hosts[nhostsbak],
882d11e3645SMatteo Riondato 				    host_addr) == 1) {
883d11e3645SMatteo Riondato 					close(fd);
884d11e3645SMatteo Riondato 					continue;
885d11e3645SMatteo Riondato 				}
886d11e3645SMatteo Riondato 			}
887d11e3645SMatteo Riondato 
888d11e3645SMatteo Riondato 			/*
889d11e3645SMatteo Riondato 			 * We're doing host-based access checks here, so don't
890d11e3645SMatteo Riondato 			 * allow v4-in-v6 to confuse things. The kernel will
891d11e3645SMatteo Riondato 			 * disable it by default on NFS sockets too.
892d11e3645SMatteo Riondato 			 */
893d11e3645SMatteo Riondato 			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
894d11e3645SMatteo Riondato 			    sizeof one) < 0) {
895d11e3645SMatteo Riondato 				syslog(LOG_ERR,
896d11e3645SMatteo Riondato 				    "can't disable v4-in-v6 on IPv6 socket");
897d11e3645SMatteo Riondato 				exit(1);
898d11e3645SMatteo Riondato 			}
899d11e3645SMatteo Riondato 			break;
900d11e3645SMatteo Riondato 		default:
901d11e3645SMatteo Riondato 			break;
902d11e3645SMatteo Riondato 		}
903d11e3645SMatteo Riondato 
904d11e3645SMatteo Riondato 		/*
905d11e3645SMatteo Riondato 		 * If no hosts were specified, just bind to INADDR_ANY
906d11e3645SMatteo Riondato 		 */
907d11e3645SMatteo Riondato 		if (strcmp("*", hosts[nhostsbak]) == 0) {
908d11e3645SMatteo Riondato 			if (svcport_str == NULL) {
909d11e3645SMatteo Riondato 				res = malloc(sizeof(struct addrinfo));
910d11e3645SMatteo Riondato 				if (res == NULL)
911d11e3645SMatteo Riondato 					out_of_mem();
9128fb6ad5dSRick Macklem 				mallocd_res = 1;
913d11e3645SMatteo Riondato 				res->ai_flags = hints.ai_flags;
914d11e3645SMatteo Riondato 				res->ai_family = hints.ai_family;
915d11e3645SMatteo Riondato 				res->ai_protocol = hints.ai_protocol;
916d11e3645SMatteo Riondato 				switch (res->ai_family) {
917d11e3645SMatteo Riondato 				case AF_INET:
918d11e3645SMatteo Riondato 					sin = malloc(sizeof(struct sockaddr_in));
919d11e3645SMatteo Riondato 					if (sin == NULL)
920d11e3645SMatteo Riondato 						out_of_mem();
921d11e3645SMatteo Riondato 					sin->sin_family = AF_INET;
922d11e3645SMatteo Riondato 					sin->sin_port = htons(0);
923d11e3645SMatteo Riondato 					sin->sin_addr.s_addr = htonl(INADDR_ANY);
924d11e3645SMatteo Riondato 					res->ai_addr = (struct sockaddr*) sin;
925d11e3645SMatteo Riondato 					res->ai_addrlen = (socklen_t)
9268fb6ad5dSRick Macklem 					    sizeof(struct sockaddr_in);
927d11e3645SMatteo Riondato 					break;
928d11e3645SMatteo Riondato 				case AF_INET6:
929d11e3645SMatteo Riondato 					sin6 = malloc(sizeof(struct sockaddr_in6));
93089ca9145SSimon L. B. Nielsen 					if (sin6 == NULL)
931d11e3645SMatteo Riondato 						out_of_mem();
932d11e3645SMatteo Riondato 					sin6->sin6_family = AF_INET6;
933d11e3645SMatteo Riondato 					sin6->sin6_port = htons(0);
934d11e3645SMatteo Riondato 					sin6->sin6_addr = in6addr_any;
935d11e3645SMatteo Riondato 					res->ai_addr = (struct sockaddr*) sin6;
936d11e3645SMatteo Riondato 					res->ai_addrlen = (socklen_t)
9378fb6ad5dSRick Macklem 					    sizeof(struct sockaddr_in6);
938d11e3645SMatteo Riondato 					break;
939d11e3645SMatteo Riondato 				default:
9408fb6ad5dSRick Macklem 					syslog(LOG_ERR, "bad addr fam %d",
9418fb6ad5dSRick Macklem 					    res->ai_family);
9428fb6ad5dSRick Macklem 					exit(1);
943d11e3645SMatteo Riondato 				}
944d11e3645SMatteo Riondato 			} else {
945d11e3645SMatteo Riondato 				if ((aicode = getaddrinfo(NULL, svcport_str,
946d11e3645SMatteo Riondato 				    &hints, &res)) != 0) {
947d11e3645SMatteo Riondato 					syslog(LOG_ERR,
948d11e3645SMatteo Riondato 					    "cannot get local address for %s: %s",
949d11e3645SMatteo Riondato 					    nconf->nc_netid,
950d11e3645SMatteo Riondato 					    gai_strerror(aicode));
9518fb6ad5dSRick Macklem 					close(fd);
952d11e3645SMatteo Riondato 					continue;
953d11e3645SMatteo Riondato 				}
954d11e3645SMatteo Riondato 			}
955d11e3645SMatteo Riondato 		} else {
956d11e3645SMatteo Riondato 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
957d11e3645SMatteo Riondato 			    &hints, &res)) != 0) {
958d11e3645SMatteo Riondato 				syslog(LOG_ERR,
959d11e3645SMatteo Riondato 				    "cannot get local address for %s: %s",
960d11e3645SMatteo Riondato 				    nconf->nc_netid, gai_strerror(aicode));
9618fb6ad5dSRick Macklem 				close(fd);
962d11e3645SMatteo Riondato 				continue;
963d11e3645SMatteo Riondato 			}
964d11e3645SMatteo Riondato 		}
965d11e3645SMatteo Riondato 
9668fb6ad5dSRick Macklem 		/* Store the fd. */
9678fb6ad5dSRick Macklem 		sock_fd[sock_fdcnt - 1] = fd;
9688fb6ad5dSRick Macklem 
9698fb6ad5dSRick Macklem 		/* Now, attempt the bind. */
970d11e3645SMatteo Riondato 		r = bindresvport_sa(fd, res->ai_addr);
971d11e3645SMatteo Riondato 		if (r != 0) {
9728fb6ad5dSRick Macklem 			if (errno == EADDRINUSE && mallocd_svcport != 0) {
9738fb6ad5dSRick Macklem 				if (mallocd_res != 0) {
9748fb6ad5dSRick Macklem 					free(res->ai_addr);
9758fb6ad5dSRick Macklem 					free(res);
9768fb6ad5dSRick Macklem 				} else
9778fb6ad5dSRick Macklem 					freeaddrinfo(res);
9788fb6ad5dSRick Macklem 				return (-1);
9798fb6ad5dSRick Macklem 			}
980d11e3645SMatteo Riondato 			syslog(LOG_ERR, "bindresvport_sa: %m");
981d11e3645SMatteo Riondato 			exit(1);
982d11e3645SMatteo Riondato 		}
983d11e3645SMatteo Riondato 
9848fb6ad5dSRick Macklem 		if (svcport_str == NULL) {
9858fb6ad5dSRick Macklem 			svcport_str = malloc(NI_MAXSERV * sizeof(char));
9868fb6ad5dSRick Macklem 			if (svcport_str == NULL)
9878fb6ad5dSRick Macklem 				out_of_mem();
9888fb6ad5dSRick Macklem 			mallocd_svcport = 1;
9898fb6ad5dSRick Macklem 
9908fb6ad5dSRick Macklem 			if (getnameinfo(res->ai_addr,
9918fb6ad5dSRick Macklem 			    res->ai_addr->sa_len, NULL, NI_MAXHOST,
9928fb6ad5dSRick Macklem 			    svcport_str, NI_MAXSERV * sizeof(char),
9938fb6ad5dSRick Macklem 			    NI_NUMERICHOST | NI_NUMERICSERV))
9948fb6ad5dSRick Macklem 				errx(1, "Cannot get port number");
9958fb6ad5dSRick Macklem 		}
9968fb6ad5dSRick Macklem 		if (mallocd_res != 0) {
9978fb6ad5dSRick Macklem 			free(res->ai_addr);
9988fb6ad5dSRick Macklem 			free(res);
9998fb6ad5dSRick Macklem 		} else
10008fb6ad5dSRick Macklem 			freeaddrinfo(res);
10018fb6ad5dSRick Macklem 		res = NULL;
10028fb6ad5dSRick Macklem 	}
10038fb6ad5dSRick Macklem 	return (0);
10048fb6ad5dSRick Macklem }
10058fb6ad5dSRick Macklem 
10068fb6ad5dSRick Macklem /*
10078fb6ad5dSRick Macklem  * Called after all the create_service() calls have succeeded, to complete
10088fb6ad5dSRick Macklem  * the setup and registration.
10098fb6ad5dSRick Macklem  */
10108fb6ad5dSRick Macklem static void
complete_service(struct netconfig * nconf,char * port_str)10118fb6ad5dSRick Macklem complete_service(struct netconfig *nconf, char *port_str)
10128fb6ad5dSRick Macklem {
10138fb6ad5dSRick Macklem 	struct addrinfo hints, *res = NULL;
10148fb6ad5dSRick Macklem 	struct __rpc_sockinfo si;
10158fb6ad5dSRick Macklem 	struct netbuf servaddr;
10168fb6ad5dSRick Macklem 	SVCXPRT	*transp = NULL;
10178fb6ad5dSRick Macklem 	int aicode, fd, nhostsbak;
10188fb6ad5dSRick Macklem 	int registered = 0;
10198fb6ad5dSRick Macklem 
10208fb6ad5dSRick Macklem 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
10218fb6ad5dSRick Macklem 	    (nconf->nc_semantics != NC_TPI_COTS) &&
10228fb6ad5dSRick Macklem 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
10238fb6ad5dSRick Macklem 		return;	/* not my type */
10248fb6ad5dSRick Macklem 
10258fb6ad5dSRick Macklem 	/*
10268fb6ad5dSRick Macklem 	 * XXX - using RPC library internal functions.
10278fb6ad5dSRick Macklem 	 */
10288fb6ad5dSRick Macklem 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
10298fb6ad5dSRick Macklem 		syslog(LOG_ERR, "cannot get information for %s",
10308fb6ad5dSRick Macklem 		    nconf->nc_netid);
10318fb6ad5dSRick Macklem 		return;
10328fb6ad5dSRick Macklem 	}
10338fb6ad5dSRick Macklem 
10348fb6ad5dSRick Macklem 	nhostsbak = nhosts;
10358fb6ad5dSRick Macklem 	while (nhostsbak > 0) {
10368fb6ad5dSRick Macklem 		--nhostsbak;
10378fb6ad5dSRick Macklem 		if (sock_fdpos >= sock_fdcnt) {
10388fb6ad5dSRick Macklem 			/* Should never happen. */
10398fb6ad5dSRick Macklem 			syslog(LOG_ERR, "Ran out of socket fd's");
10408fb6ad5dSRick Macklem 			return;
10418fb6ad5dSRick Macklem 		}
10428fb6ad5dSRick Macklem 		fd = sock_fd[sock_fdpos++];
10438fb6ad5dSRick Macklem 		if (fd < 0)
10448fb6ad5dSRick Macklem 			continue;
10458fb6ad5dSRick Macklem 
104693840fdeSSean Eric Fagan 		/*
104793840fdeSSean Eric Fagan 		 * Using -1 tells listen(2) to use
104893840fdeSSean Eric Fagan 		 * kern.ipc.soacceptqueue for the backlog.
104993840fdeSSean Eric Fagan 		 */
1050d11e3645SMatteo Riondato 		if (nconf->nc_semantics != NC_TPI_CLTS)
105193840fdeSSean Eric Fagan 			listen(fd, -1);
1052d11e3645SMatteo Riondato 
1053d11e3645SMatteo Riondato 		if (nconf->nc_semantics == NC_TPI_CLTS )
1054d11e3645SMatteo Riondato 			transp = svc_dg_create(fd, 0, 0);
1055d11e3645SMatteo Riondato 		else
1056d11e3645SMatteo Riondato 			transp = svc_vc_create(fd, RPC_MAXDATASIZE,
1057d11e3645SMatteo Riondato 			    RPC_MAXDATASIZE);
1058d11e3645SMatteo Riondato 
1059d11e3645SMatteo Riondato 		if (transp != (SVCXPRT *) NULL) {
10600775314bSDoug Rabson 			if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv,
1061d11e3645SMatteo Riondato 			    NULL))
1062d11e3645SMatteo Riondato 				syslog(LOG_ERR,
10630775314bSDoug Rabson 				    "can't register %s MOUNTVERS service",
1064d11e3645SMatteo Riondato 				    nconf->nc_netid);
1065d11e3645SMatteo Riondato 			if (!force_v2) {
10660775314bSDoug Rabson 				if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3,
1067d11e3645SMatteo Riondato 				    mntsrv, NULL))
1068d11e3645SMatteo Riondato 					syslog(LOG_ERR,
10690775314bSDoug Rabson 					    "can't register %s MOUNTVERS3 service",
1070d11e3645SMatteo Riondato 					    nconf->nc_netid);
1071d11e3645SMatteo Riondato 			}
1072d11e3645SMatteo Riondato 		} else
1073d11e3645SMatteo Riondato 			syslog(LOG_WARNING, "can't create %s services",
1074d11e3645SMatteo Riondato 			    nconf->nc_netid);
1075d11e3645SMatteo Riondato 
1076d11e3645SMatteo Riondato 		if (registered == 0) {
1077d11e3645SMatteo Riondato 			registered = 1;
1078d11e3645SMatteo Riondato 			memset(&hints, 0, sizeof hints);
1079d11e3645SMatteo Riondato 			hints.ai_flags = AI_PASSIVE;
1080d11e3645SMatteo Riondato 			hints.ai_family = si.si_af;
1081d11e3645SMatteo Riondato 			hints.ai_socktype = si.si_socktype;
1082d11e3645SMatteo Riondato 			hints.ai_protocol = si.si_proto;
1083d11e3645SMatteo Riondato 
10848fb6ad5dSRick Macklem 			if ((aicode = getaddrinfo(NULL, port_str, &hints,
1085d11e3645SMatteo Riondato 			    &res)) != 0) {
1086d11e3645SMatteo Riondato 				syslog(LOG_ERR, "cannot get local address: %s",
1087d11e3645SMatteo Riondato 				    gai_strerror(aicode));
1088d11e3645SMatteo Riondato 				exit(1);
1089d11e3645SMatteo Riondato 			}
1090d11e3645SMatteo Riondato 
1091d11e3645SMatteo Riondato 			servaddr.buf = malloc(res->ai_addrlen);
1092d11e3645SMatteo Riondato 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
1093d11e3645SMatteo Riondato 			servaddr.len = res->ai_addrlen;
1094d11e3645SMatteo Riondato 
10950775314bSDoug Rabson 			rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr);
10960775314bSDoug Rabson 			rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr);
1097d11e3645SMatteo Riondato 
1098d11e3645SMatteo Riondato 			xcreated++;
1099d11e3645SMatteo Riondato 			freeaddrinfo(res);
1100d11e3645SMatteo Riondato 		}
1101d11e3645SMatteo Riondato 	} /* end while */
1102d11e3645SMatteo Riondato }
1103d11e3645SMatteo Riondato 
11048fb6ad5dSRick Macklem /*
11058fb6ad5dSRick Macklem  * Clear out sockets after a failure to bind one of them, so that the
11068fb6ad5dSRick Macklem  * cycle of socket creation/binding can start anew.
11078fb6ad5dSRick Macklem  */
11088fb6ad5dSRick Macklem static void
clearout_service(void)11098fb6ad5dSRick Macklem clearout_service(void)
11108fb6ad5dSRick Macklem {
11118fb6ad5dSRick Macklem 	int i;
11128fb6ad5dSRick Macklem 
11138fb6ad5dSRick Macklem 	for (i = 0; i < sock_fdcnt; i++) {
11148fb6ad5dSRick Macklem 		if (sock_fd[i] >= 0) {
11158fb6ad5dSRick Macklem 			shutdown(sock_fd[i], SHUT_RDWR);
11168fb6ad5dSRick Macklem 			close(sock_fd[i]);
11178fb6ad5dSRick Macklem 		}
11188fb6ad5dSRick Macklem 	}
11198fb6ad5dSRick Macklem }
11208fb6ad5dSRick Macklem 
112174853402SPhilippe Charnier static void
usage(void)1122a7a7d96cSPhilippe Charnier usage(void)
112374853402SPhilippe Charnier {
112474853402SPhilippe Charnier 	fprintf(stderr,
11257c2901b0SJoyu Liao 	    "usage: mountd [-2] [-d] [-e] [-l] [-N] [-n] [-p <port>] [-r] [-S] "
11267c2901b0SJoyu Liao 	    "[-s] [-h <bindip>] [export_file ...]\n");
11278fae3551SRodney W. Grimes 	exit(1);
11288fae3551SRodney W. Grimes }
11298fae3551SRodney W. Grimes 
11308fae3551SRodney W. Grimes /*
11318fae3551SRodney W. Grimes  * The mount rpc service
11328fae3551SRodney W. Grimes  */
11338fae3551SRodney W. Grimes void
mntsrv(struct svc_req * rqstp,SVCXPRT * transp)1134a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp)
11358fae3551SRodney W. Grimes {
11368fae3551SRodney W. Grimes 	struct exportlist *ep;
11378fae3551SRodney W. Grimes 	struct dirlist *dp;
1138a62dc406SDoug Rabson 	struct fhreturn fhr;
11398fae3551SRodney W. Grimes 	struct stat stb;
11408fae3551SRodney W. Grimes 	struct statfs fsb;
11418360efbdSAlfred Perlstein 	char host[NI_MAXHOST], numerichost[NI_MAXHOST];
11428360efbdSAlfred Perlstein 	int lookup_failed = 1;
11438360efbdSAlfred Perlstein 	struct sockaddr *saddr;
1144a62dc406SDoug Rabson 	u_short sport;
11450775314bSDoug Rabson 	char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN];
1146e9b21d43SBrooks Davis 	int defset, hostset;
1147e9b21d43SBrooks Davis 	long bad = 0;
1148a62dc406SDoug Rabson 	sigset_t sighup_mask;
1149c3f86a25SRick Macklem 	int numsecflavors, *secflavorsp;
11508fae3551SRodney W. Grimes 
1151a62dc406SDoug Rabson 	sigemptyset(&sighup_mask);
1152a62dc406SDoug Rabson 	sigaddset(&sighup_mask, SIGHUP);
11538360efbdSAlfred Perlstein 	saddr = svc_getrpccaller(transp)->buf;
11548360efbdSAlfred Perlstein 	switch (saddr->sa_family) {
11558360efbdSAlfred Perlstein 	case AF_INET6:
115601709abfSIan Dowse 		sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
11578360efbdSAlfred Perlstein 		break;
11588360efbdSAlfred Perlstein 	case AF_INET:
115901709abfSIan Dowse 		sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
11608360efbdSAlfred Perlstein 		break;
11618360efbdSAlfred Perlstein 	default:
11628360efbdSAlfred Perlstein 		syslog(LOG_ERR, "request from unknown address family");
11638360efbdSAlfred Perlstein 		return;
11648360efbdSAlfred Perlstein 	}
116554ff4a6aSSean Eric Fagan 	switch (rqstp->rq_proc) {
116654ff4a6aSSean Eric Fagan 	case MOUNTPROC_MNT:
116754ff4a6aSSean Eric Fagan 	case MOUNTPROC_UMNT:
116854ff4a6aSSean Eric Fagan 	case MOUNTPROC_UMNTALL:
116954ff4a6aSSean Eric Fagan 		lookup_failed = getnameinfo(saddr, saddr->sa_len, host,
117054ff4a6aSSean Eric Fagan 		    sizeof host, NULL, 0, 0);
117154ff4a6aSSean Eric Fagan 	}
11728360efbdSAlfred Perlstein 	getnameinfo(saddr, saddr->sa_len, numerichost,
11738360efbdSAlfred Perlstein 	    sizeof numerichost, NULL, 0, NI_NUMERICHOST);
11748fae3551SRodney W. Grimes 	switch (rqstp->rq_proc) {
11758fae3551SRodney W. Grimes 	case NULLPROC:
1176389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
117774853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
11788fae3551SRodney W. Grimes 		return;
11790775314bSDoug Rabson 	case MOUNTPROC_MNT:
1180a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
1181f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1182f51631d7SGuido van Rooij 			    "mount request from %s from unprivileged port",
11838360efbdSAlfred Perlstein 			    numerichost);
11848fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
11858fae3551SRodney W. Grimes 			return;
11868fae3551SRodney W. Grimes 		}
1187389b8446SPeter Wemm 		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
1188f51631d7SGuido van Rooij 			syslog(LOG_NOTICE, "undecodable mount request from %s",
11898360efbdSAlfred Perlstein 			    numerichost);
11908fae3551SRodney W. Grimes 			svcerr_decode(transp);
11918fae3551SRodney W. Grimes 			return;
11928fae3551SRodney W. Grimes 		}
11938fae3551SRodney W. Grimes 
11948fae3551SRodney W. Grimes 		/*
11958fae3551SRodney W. Grimes 		 * Get the real pathname and make sure it is a directory
1196a62dc406SDoug Rabson 		 * or a regular file if the -r option was specified
1197a62dc406SDoug Rabson 		 * and it exists.
11988fae3551SRodney W. Grimes 		 */
1199cb479b11SAlfred Perlstein 		if (realpath(rpcpath, dirpath) == NULL ||
12008fae3551SRodney W. Grimes 		    stat(dirpath, &stb) < 0 ||
12018fae3551SRodney W. Grimes 		    statfs(dirpath, &fsb) < 0) {
12028fae3551SRodney W. Grimes 			chdir("/");	/* Just in case realpath doesn't */
1203f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
120474853402SPhilippe Charnier 			    "mount request from %s for non existent path %s",
12058360efbdSAlfred Perlstein 			    numerichost, dirpath);
12068fae3551SRodney W. Grimes 			if (debug)
120774853402SPhilippe Charnier 				warnx("stat failed on %s", dirpath);
1208e90cdb54SGuido van Rooij 			bad = ENOENT;	/* We will send error reply later */
12098fae3551SRodney W. Grimes 		}
1210b235f015SRavi Pokala 		if (!bad &&
1211b235f015SRavi Pokala 		    !S_ISDIR(stb.st_mode) &&
1212b235f015SRavi Pokala 		    (dir_only || !S_ISREG(stb.st_mode))) {
1213b235f015SRavi Pokala 			syslog(LOG_NOTICE,
1214b235f015SRavi Pokala 			    "mount request from %s for non-directory path %s",
1215b235f015SRavi Pokala 			    numerichost, dirpath);
1216b235f015SRavi Pokala 			if (debug)
1217b235f015SRavi Pokala 				warnx("mounting non-directory %s", dirpath);
1218b235f015SRavi Pokala 			bad = ENOTDIR;	/* We will send error reply later */
1219b235f015SRavi Pokala 		}
12208fae3551SRodney W. Grimes 
12218fae3551SRodney W. Grimes 		/* Check in the exports list */
1222a62dc406SDoug Rabson 		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1223b235f015SRavi Pokala 		if (bad)
1224b235f015SRavi Pokala 			ep = NULL;
1225b235f015SRavi Pokala 		else
122646a6b5c4SRick Macklem 			ep = ex_search(&fsb.f_fsid, exphead);
1227a62dc406SDoug Rabson 		hostset = defset = 0;
1228c3f86a25SRick Macklem 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset,
1229c3f86a25SRick Macklem 		    &numsecflavors, &secflavorsp) ||
12308fae3551SRodney W. Grimes 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
1231c3f86a25SRick Macklem 		      chk_host(dp, saddr, &defset, &hostset, &numsecflavors,
1232c3f86a25SRick Macklem 		       &secflavorsp)) ||
12338fae3551SRodney W. Grimes 		    (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
12348fae3551SRodney W. Grimes 		     scan_tree(ep->ex_dirl, saddr) == 0))) {
1235e90cdb54SGuido van Rooij 			if (bad) {
1236389b8446SPeter Wemm 				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
1237e90cdb54SGuido van Rooij 				    (caddr_t)&bad))
123874853402SPhilippe Charnier 					syslog(LOG_ERR, "can't send reply");
1239e90cdb54SGuido van Rooij 				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
1240e90cdb54SGuido van Rooij 				return;
1241e90cdb54SGuido van Rooij 			}
1242c3f86a25SRick Macklem 			if (hostset & DP_HOSTSET) {
1243a62dc406SDoug Rabson 				fhr.fhr_flag = hostset;
1244c3f86a25SRick Macklem 				fhr.fhr_numsecflavors = numsecflavors;
1245c3f86a25SRick Macklem 				fhr.fhr_secflavors = secflavorsp;
1246c3f86a25SRick Macklem 			} else {
1247a62dc406SDoug Rabson 				fhr.fhr_flag = defset;
1248c3f86a25SRick Macklem 				fhr.fhr_numsecflavors = ep->ex_defnumsecflavors;
1249c3f86a25SRick Macklem 				fhr.fhr_secflavors = ep->ex_defsecflavors;
1250c3f86a25SRick Macklem 			}
1251a62dc406SDoug Rabson 			fhr.fhr_vers = rqstp->rq_vers;
12528fae3551SRodney W. Grimes 			/* Get the file handle */
125387564113SPeter Wemm 			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
1254a62dc406SDoug Rabson 			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
12558fae3551SRodney W. Grimes 				bad = errno;
125674853402SPhilippe Charnier 				syslog(LOG_ERR, "can't get fh for %s", dirpath);
1257389b8446SPeter Wemm 				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
12588fae3551SRodney W. Grimes 				    (caddr_t)&bad))
125974853402SPhilippe Charnier 					syslog(LOG_ERR, "can't send reply");
1260a62dc406SDoug Rabson 				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
12618fae3551SRodney W. Grimes 				return;
12628fae3551SRodney W. Grimes 			}
1263389b8446SPeter Wemm 			if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
1264389b8446SPeter Wemm 			    (caddr_t)&fhr))
126574853402SPhilippe Charnier 				syslog(LOG_ERR, "can't send reply");
12668360efbdSAlfred Perlstein 			if (!lookup_failed)
12678360efbdSAlfred Perlstein 				add_mlist(host, dirpath);
12688fae3551SRodney W. Grimes 			else
12698360efbdSAlfred Perlstein 				add_mlist(numerichost, dirpath);
12708fae3551SRodney W. Grimes 			if (debug)
127174853402SPhilippe Charnier 				warnx("mount successful");
1272c903443aSPeter Wemm 			if (dolog)
1273f51631d7SGuido van Rooij 				syslog(LOG_NOTICE,
1274f51631d7SGuido van Rooij 				    "mount request succeeded from %s for %s",
12758360efbdSAlfred Perlstein 				    numerichost, dirpath);
1276f51631d7SGuido van Rooij 		} else {
1277b235f015SRavi Pokala 			if (!bad)
12788fae3551SRodney W. Grimes 				bad = EACCES;
1279f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1280f51631d7SGuido van Rooij 			    "mount request denied from %s for %s",
12818360efbdSAlfred Perlstein 			    numerichost, dirpath);
1282f51631d7SGuido van Rooij 		}
1283e90cdb54SGuido van Rooij 
1284389b8446SPeter Wemm 		if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
1285389b8446SPeter Wemm 		    (caddr_t)&bad))
128674853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
1287a62dc406SDoug Rabson 		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
12888fae3551SRodney W. Grimes 		return;
12890775314bSDoug Rabson 	case MOUNTPROC_DUMP:
1290389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
129174853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
1292c903443aSPeter Wemm 		else if (dolog)
1293f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1294f51631d7SGuido van Rooij 			    "dump request succeeded from %s",
12958360efbdSAlfred Perlstein 			    numerichost);
12968fae3551SRodney W. Grimes 		return;
12970775314bSDoug Rabson 	case MOUNTPROC_UMNT:
1298a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
1299f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1300f51631d7SGuido van Rooij 			    "umount request from %s from unprivileged port",
13018360efbdSAlfred Perlstein 			    numerichost);
13028fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
13038fae3551SRodney W. Grimes 			return;
13048fae3551SRodney W. Grimes 		}
1305389b8446SPeter Wemm 		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
1306f51631d7SGuido van Rooij 			syslog(LOG_NOTICE, "undecodable umount request from %s",
13078360efbdSAlfred Perlstein 			    numerichost);
13088fae3551SRodney W. Grimes 			svcerr_decode(transp);
13098fae3551SRodney W. Grimes 			return;
13108fae3551SRodney W. Grimes 		}
1311cb479b11SAlfred Perlstein 		if (realpath(rpcpath, dirpath) == NULL) {
1312cb479b11SAlfred Perlstein 			syslog(LOG_NOTICE, "umount request from %s "
1313cb479b11SAlfred Perlstein 			    "for non existent path %s",
13148360efbdSAlfred Perlstein 			    numerichost, dirpath);
1315cb479b11SAlfred Perlstein 		}
1316389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
131774853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
13188360efbdSAlfred Perlstein 		if (!lookup_failed)
131901709abfSIan Dowse 			del_mlist(host, dirpath);
132001709abfSIan Dowse 		del_mlist(numerichost, dirpath);
1321c903443aSPeter Wemm 		if (dolog)
1322f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1323f51631d7SGuido van Rooij 			    "umount request succeeded from %s for %s",
13248360efbdSAlfred Perlstein 			    numerichost, dirpath);
13258fae3551SRodney W. Grimes 		return;
13260775314bSDoug Rabson 	case MOUNTPROC_UMNTALL:
1327a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
1328f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1329f51631d7SGuido van Rooij 			    "umountall request from %s from unprivileged port",
13308360efbdSAlfred Perlstein 			    numerichost);
13318fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
13328fae3551SRodney W. Grimes 			return;
13338fae3551SRodney W. Grimes 		}
1334389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
133574853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
13368360efbdSAlfred Perlstein 		if (!lookup_failed)
133701709abfSIan Dowse 			del_mlist(host, NULL);
133801709abfSIan Dowse 		del_mlist(numerichost, NULL);
1339c903443aSPeter Wemm 		if (dolog)
1340f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1341f51631d7SGuido van Rooij 			    "umountall request succeeded from %s",
13428360efbdSAlfred Perlstein 			    numerichost);
13438fae3551SRodney W. Grimes 		return;
13440775314bSDoug Rabson 	case MOUNTPROC_EXPORT:
1345389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
1346389b8446SPeter Wemm 			if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
1347389b8446SPeter Wemm 			    (caddr_t)NULL))
134874853402SPhilippe Charnier 				syslog(LOG_ERR, "can't send reply");
1349c903443aSPeter Wemm 		if (dolog)
1350f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
1351f51631d7SGuido van Rooij 			    "export request succeeded from %s",
13528360efbdSAlfred Perlstein 			    numerichost);
13538fae3551SRodney W. Grimes 		return;
13548fae3551SRodney W. Grimes 	default:
13558fae3551SRodney W. Grimes 		svcerr_noproc(transp);
13568fae3551SRodney W. Grimes 		return;
13578fae3551SRodney W. Grimes 	}
13588fae3551SRodney W. Grimes }
13598fae3551SRodney W. Grimes 
13608fae3551SRodney W. Grimes /*
13618fae3551SRodney W. Grimes  * Xdr conversion for a dirpath string
13628fae3551SRodney W. Grimes  */
136319c46d8cSEdward Tomasz Napierala static int
xdr_dir(XDR * xdrsp,char * dirp)1364a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp)
13658fae3551SRodney W. Grimes {
13660775314bSDoug Rabson 	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
13678fae3551SRodney W. Grimes }
13688fae3551SRodney W. Grimes 
13698fae3551SRodney W. Grimes /*
1370a62dc406SDoug Rabson  * Xdr routine to generate file handle reply
13718fae3551SRodney W. Grimes  */
137219c46d8cSEdward Tomasz Napierala static int
xdr_fhs(XDR * xdrsp,caddr_t cp)1373a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp)
13748fae3551SRodney W. Grimes {
13753d438ad6SDavid E. O'Brien 	struct fhreturn *fhrp = (struct fhreturn *)cp;
1376a62dc406SDoug Rabson 	u_long ok = 0, len, auth;
1377a9148abdSDoug Rabson 	int i;
13788fae3551SRodney W. Grimes 
13798fae3551SRodney W. Grimes 	if (!xdr_long(xdrsp, &ok))
13808fae3551SRodney W. Grimes 		return (0);
1381a62dc406SDoug Rabson 	switch (fhrp->fhr_vers) {
1382a62dc406SDoug Rabson 	case 1:
1383a62dc406SDoug Rabson 		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
1384a62dc406SDoug Rabson 	case 3:
1385a62dc406SDoug Rabson 		len = NFSX_V3FH;
1386a62dc406SDoug Rabson 		if (!xdr_long(xdrsp, &len))
1387a62dc406SDoug Rabson 			return (0);
1388a62dc406SDoug Rabson 		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
1389a62dc406SDoug Rabson 			return (0);
1390a9148abdSDoug Rabson 		if (fhrp->fhr_numsecflavors) {
1391a9148abdSDoug Rabson 			if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors))
1392a9148abdSDoug Rabson 				return (0);
1393a9148abdSDoug Rabson 			for (i = 0; i < fhrp->fhr_numsecflavors; i++)
1394a9148abdSDoug Rabson 				if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i]))
1395a9148abdSDoug Rabson 					return (0);
1396a9148abdSDoug Rabson 			return (1);
1397a9148abdSDoug Rabson 		} else {
1398a9148abdSDoug Rabson 			auth = AUTH_SYS;
1399a62dc406SDoug Rabson 			len = 1;
1400a62dc406SDoug Rabson 			if (!xdr_long(xdrsp, &len))
1401a62dc406SDoug Rabson 				return (0);
1402a62dc406SDoug Rabson 			return (xdr_long(xdrsp, &auth));
1403a9148abdSDoug Rabson 		}
140480c7cc1cSPedro F. Giffuni 	}
1405a62dc406SDoug Rabson 	return (0);
14068fae3551SRodney W. Grimes }
14078fae3551SRodney W. Grimes 
140819c46d8cSEdward Tomasz Napierala static int
xdr_mlist(XDR * xdrsp,caddr_t cp __unused)1409a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused)
14108fae3551SRodney W. Grimes {
14118fae3551SRodney W. Grimes 	struct mountlist *mlp;
14128fae3551SRodney W. Grimes 	int true = 1;
14138fae3551SRodney W. Grimes 	int false = 0;
14148fae3551SRodney W. Grimes 	char *strp;
14158fae3551SRodney W. Grimes 
14161da3e8b0SEmmanuel Vadot 	SLIST_FOREACH(mlp, &mlhead, next) {
14178fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &true))
14188fae3551SRodney W. Grimes 			return (0);
14198fae3551SRodney W. Grimes 		strp = &mlp->ml_host[0];
14200775314bSDoug Rabson 		if (!xdr_string(xdrsp, &strp, MNTNAMLEN))
14218fae3551SRodney W. Grimes 			return (0);
14228fae3551SRodney W. Grimes 		strp = &mlp->ml_dirp[0];
14230775314bSDoug Rabson 		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
14248fae3551SRodney W. Grimes 			return (0);
14258fae3551SRodney W. Grimes 	}
14268fae3551SRodney W. Grimes 	if (!xdr_bool(xdrsp, &false))
14278fae3551SRodney W. Grimes 		return (0);
14288fae3551SRodney W. Grimes 	return (1);
14298fae3551SRodney W. Grimes }
14308fae3551SRodney W. Grimes 
14318fae3551SRodney W. Grimes /*
14328fae3551SRodney W. Grimes  * Xdr conversion for export list
14338fae3551SRodney W. Grimes  */
143419c46d8cSEdward Tomasz Napierala static int
xdr_explist_common(XDR * xdrsp,caddr_t cp __unused,int brief)1435a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief)
14368fae3551SRodney W. Grimes {
14378fae3551SRodney W. Grimes 	struct exportlist *ep;
14388fae3551SRodney W. Grimes 	int false = 0;
1439a62dc406SDoug Rabson 	int putdef;
1440a62dc406SDoug Rabson 	sigset_t sighup_mask;
144146a6b5c4SRick Macklem 	int i;
14428fae3551SRodney W. Grimes 
1443a62dc406SDoug Rabson 	sigemptyset(&sighup_mask);
1444a62dc406SDoug Rabson 	sigaddset(&sighup_mask, SIGHUP);
1445a62dc406SDoug Rabson 	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
1446c9ac0f71SEmmanuel Vadot 
144746a6b5c4SRick Macklem 	for (i = 0; i < exphashsize; i++)
144846a6b5c4SRick Macklem 		SLIST_FOREACH(ep, &exphead[i], entries) {
14498fae3551SRodney W. Grimes 			putdef = 0;
145091acb349SAlfred Perlstein 			if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
145191acb349SAlfred Perlstein 				       &putdef, brief))
14528fae3551SRodney W. Grimes 				goto errout;
14538fae3551SRodney W. Grimes 			if (ep->ex_defdir && putdef == 0 &&
145446a6b5c4SRick Macklem 				put_exlist(ep->ex_defdir, xdrsp, NULL,
145591acb349SAlfred Perlstein 				&putdef, brief))
14568fae3551SRodney W. Grimes 				goto errout;
14578fae3551SRodney W. Grimes 		}
1458a62dc406SDoug Rabson 	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
14598fae3551SRodney W. Grimes 	if (!xdr_bool(xdrsp, &false))
14608fae3551SRodney W. Grimes 		return (0);
14618fae3551SRodney W. Grimes 	return (1);
14628fae3551SRodney W. Grimes errout:
1463a62dc406SDoug Rabson 	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
14648fae3551SRodney W. Grimes 	return (0);
14658fae3551SRodney W. Grimes }
14668fae3551SRodney W. Grimes 
14678fae3551SRodney W. Grimes /*
14688fae3551SRodney W. Grimes  * Called from xdr_explist() to traverse the tree and export the
14698fae3551SRodney W. Grimes  * directory paths.
14708fae3551SRodney W. Grimes  */
147119c46d8cSEdward Tomasz Napierala static int
put_exlist(struct dirlist * dp,XDR * xdrsp,struct dirlist * adp,int * putdefp,int brief)1472a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp,
1473a7a7d96cSPhilippe Charnier 	int brief)
14748fae3551SRodney W. Grimes {
14758fae3551SRodney W. Grimes 	struct grouplist *grp;
14768fae3551SRodney W. Grimes 	struct hostlist *hp;
14778fae3551SRodney W. Grimes 	int true = 1;
14788fae3551SRodney W. Grimes 	int false = 0;
14798fae3551SRodney W. Grimes 	int gotalldir = 0;
14808fae3551SRodney W. Grimes 	char *strp;
14818fae3551SRodney W. Grimes 
14828fae3551SRodney W. Grimes 	if (dp) {
148391acb349SAlfred Perlstein 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
14848fae3551SRodney W. Grimes 			return (1);
14858fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &true))
14868fae3551SRodney W. Grimes 			return (1);
14878fae3551SRodney W. Grimes 		strp = dp->dp_dirp;
14880775314bSDoug Rabson 		if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
14898fae3551SRodney W. Grimes 			return (1);
14908fae3551SRodney W. Grimes 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
14918fae3551SRodney W. Grimes 			gotalldir = 1;
14928fae3551SRodney W. Grimes 			*putdefp = 1;
14938fae3551SRodney W. Grimes 		}
149491acb349SAlfred Perlstein 		if (brief) {
149591acb349SAlfred Perlstein 			if (!xdr_bool(xdrsp, &true))
149691acb349SAlfred Perlstein 				return (1);
149791acb349SAlfred Perlstein 			strp = "(...)";
14980775314bSDoug Rabson 			if (!xdr_string(xdrsp, &strp, MNTPATHLEN))
149991acb349SAlfred Perlstein 				return (1);
150091acb349SAlfred Perlstein 		} else if ((dp->dp_flag & DP_DEFSET) == 0 &&
15018fae3551SRodney W. Grimes 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
15028fae3551SRodney W. Grimes 			hp = dp->dp_hosts;
15038fae3551SRodney W. Grimes 			while (hp) {
15048fae3551SRodney W. Grimes 				grp = hp->ht_grp;
15058fae3551SRodney W. Grimes 				if (grp->gr_type == GT_HOST) {
15068fae3551SRodney W. Grimes 					if (!xdr_bool(xdrsp, &true))
15078fae3551SRodney W. Grimes 						return (1);
15088360efbdSAlfred Perlstein 					strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
15098fae3551SRodney W. Grimes 					if (!xdr_string(xdrsp, &strp,
15100775314bSDoug Rabson 					    MNTNAMLEN))
15118fae3551SRodney W. Grimes 						return (1);
15128fae3551SRodney W. Grimes 				} else if (grp->gr_type == GT_NET) {
15138fae3551SRodney W. Grimes 					if (!xdr_bool(xdrsp, &true))
15148fae3551SRodney W. Grimes 						return (1);
15158fae3551SRodney W. Grimes 					strp = grp->gr_ptr.gt_net.nt_name;
15168fae3551SRodney W. Grimes 					if (!xdr_string(xdrsp, &strp,
15170775314bSDoug Rabson 					    MNTNAMLEN))
15188fae3551SRodney W. Grimes 						return (1);
15198fae3551SRodney W. Grimes 				}
15208fae3551SRodney W. Grimes 				hp = hp->ht_next;
15218fae3551SRodney W. Grimes 				if (gotalldir && hp == (struct hostlist *)NULL) {
15228fae3551SRodney W. Grimes 					hp = adp->dp_hosts;
15238fae3551SRodney W. Grimes 					gotalldir = 0;
15248fae3551SRodney W. Grimes 				}
15258fae3551SRodney W. Grimes 			}
15268fae3551SRodney W. Grimes 		}
15278fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &false))
15288fae3551SRodney W. Grimes 			return (1);
152991acb349SAlfred Perlstein 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
15308fae3551SRodney W. Grimes 			return (1);
15318fae3551SRodney W. Grimes 	}
15328fae3551SRodney W. Grimes 	return (0);
15338fae3551SRodney W. Grimes }
15348fae3551SRodney W. Grimes 
153519c46d8cSEdward Tomasz Napierala static int
xdr_explist(XDR * xdrsp,caddr_t cp)1536a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp)
153791acb349SAlfred Perlstein {
153891acb349SAlfred Perlstein 
153991acb349SAlfred Perlstein 	return xdr_explist_common(xdrsp, cp, 0);
154091acb349SAlfred Perlstein }
154191acb349SAlfred Perlstein 
154219c46d8cSEdward Tomasz Napierala static int
xdr_explist_brief(XDR * xdrsp,caddr_t cp)1543a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp)
154491acb349SAlfred Perlstein {
154591acb349SAlfred Perlstein 
154691acb349SAlfred Perlstein 	return xdr_explist_common(xdrsp, cp, 1);
154791acb349SAlfred Perlstein }
154891acb349SAlfred Perlstein 
154919c46d8cSEdward Tomasz Napierala static char *line;
155019c46d8cSEdward Tomasz Napierala static size_t linesize;
155119c46d8cSEdward Tomasz Napierala static FILE *exp_file;
15528fae3551SRodney W. Grimes 
15538fae3551SRodney W. Grimes /*
155496968c22SPawel Jakub Dawidek  * Get the export list from one, currently open file
15558fae3551SRodney W. Grimes  */
155696968c22SPawel Jakub Dawidek static void
get_exportlist_one(int passno)15570f0869bcSRick Macklem get_exportlist_one(int passno)
15588fae3551SRodney W. Grimes {
1559c9ac0f71SEmmanuel Vadot 	struct exportlist *ep;
15600f0869bcSRick Macklem 	struct grouplist *grp, *tgrp, *savgrp;
15618fae3551SRodney W. Grimes 	struct dirlist *dirhead;
156296968c22SPawel Jakub Dawidek 	struct statfs fsb;
1563cc5efddeSRick Macklem 	struct expcred anon;
15648fae3551SRodney W. Grimes 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
1565572b77f8SAlexander Motin 	char *err_msg = NULL;
1566cc5efddeSRick Macklem 	int len, has_host, got_nondir, dirplen, netgrp;
1567cc5efddeSRick Macklem 	uint64_t exflags;
15687c5146daSDan Mcgregor 	char unvis_dir[PATH_MAX + 1];
15697c5146daSDan Mcgregor 	int unvis_len;
15708fae3551SRodney W. Grimes 
1571bcc1d071SRick Macklem 	v4root_phase = 0;
15722ffad162SRick Macklem 	anon.cr_groups = NULL;
15738fae3551SRodney W. Grimes 	dirhead = (struct dirlist *)NULL;
15747c5146daSDan Mcgregor 	unvis_dir[0] = '\0';
15758fae3551SRodney W. Grimes 	while (get_line()) {
15768fae3551SRodney W. Grimes 		if (debug)
157774853402SPhilippe Charnier 			warnx("got line %s", line);
15788fae3551SRodney W. Grimes 		cp = line;
15798fae3551SRodney W. Grimes 		nextfield(&cp, &endcp);
15808fae3551SRodney W. Grimes 		if (*cp == '#')
15818fae3551SRodney W. Grimes 			goto nextline;
15828fae3551SRodney W. Grimes 
15838fae3551SRodney W. Grimes 		/*
15848fae3551SRodney W. Grimes 		 * Set defaults.
15858fae3551SRodney W. Grimes 		 */
15868fae3551SRodney W. Grimes 		has_host = FALSE;
15872ffad162SRick Macklem 		anon.cr_groups = anon.cr_smallgrps;
15883e2d36ffSRick Macklem 		anon.cr_uid = UID_NOBODY;
1589cc5efddeSRick Macklem 		anon.cr_ngroups = 1;
15903e2d36ffSRick Macklem 		anon.cr_groups[0] = GID_NOGROUP;
15918fae3551SRodney W. Grimes 		exflags = MNT_EXPORTED;
15928fae3551SRodney W. Grimes 		got_nondir = 0;
15938fae3551SRodney W. Grimes 		opt_flags = 0;
15948fae3551SRodney W. Grimes 		ep = (struct exportlist *)NULL;
1595bcc1d071SRick Macklem 		dirp = NULL;
1596bcc1d071SRick Macklem 
1597bcc1d071SRick Macklem 		/*
1598bcc1d071SRick Macklem 		 * Handle the V4 root dir.
1599bcc1d071SRick Macklem 		 */
1600bcc1d071SRick Macklem 		if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') {
1601bcc1d071SRick Macklem 			/*
1602bcc1d071SRick Macklem 			 * V4: just indicates that it is the v4 root point,
1603bcc1d071SRick Macklem 			 * so skip over that and set v4root_phase.
1604bcc1d071SRick Macklem 			 */
1605bcc1d071SRick Macklem 			if (v4root_phase > 0) {
1606bcc1d071SRick Macklem 				syslog(LOG_ERR, "V4:duplicate line, ignored");
1607bcc1d071SRick Macklem 				goto nextline;
1608bcc1d071SRick Macklem 			}
1609bcc1d071SRick Macklem 			v4root_phase = 1;
1610bcc1d071SRick Macklem 			cp += 3;
1611bcc1d071SRick Macklem 			nextfield(&cp, &endcp);
1612bcc1d071SRick Macklem 		}
16138fae3551SRodney W. Grimes 
16148fae3551SRodney W. Grimes 		/*
16158fae3551SRodney W. Grimes 		 * Create new exports list entry
16168fae3551SRodney W. Grimes 		 */
16178fae3551SRodney W. Grimes 		len = endcp-cp;
16188fae3551SRodney W. Grimes 		tgrp = grp = get_grp();
16198fae3551SRodney W. Grimes 		while (len > 0) {
16200775314bSDoug Rabson 			if (len > MNTNAMLEN) {
1621354fce28SConrad Meyer 			    getexp_err(ep, tgrp, "mountpoint too long");
16228fae3551SRodney W. Grimes 			    goto nextline;
16238fae3551SRodney W. Grimes 			}
16248fae3551SRodney W. Grimes 			if (*cp == '-') {
16258fae3551SRodney W. Grimes 			    if (ep == (struct exportlist *)NULL) {
1626354fce28SConrad Meyer 				getexp_err(ep, tgrp,
1627354fce28SConrad Meyer 				    "flag before export path definition");
16288fae3551SRodney W. Grimes 				goto nextline;
16298fae3551SRodney W. Grimes 			    }
16308fae3551SRodney W. Grimes 			    if (debug)
163174853402SPhilippe Charnier 				warnx("doing opt %s", cp);
16328fae3551SRodney W. Grimes 			    got_nondir = 1;
16338fae3551SRodney W. Grimes 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
16348fae3551SRodney W. Grimes 				&exflags, &anon)) {
1635354fce28SConrad Meyer 				getexp_err(ep, tgrp, NULL);
16368fae3551SRodney W. Grimes 				goto nextline;
16378fae3551SRodney W. Grimes 			    }
16388fae3551SRodney W. Grimes 			} else if (*cp == '/') {
16398fae3551SRodney W. Grimes 			    savedc = *endcp;
16408fae3551SRodney W. Grimes 			    *endcp = '\0';
16417c5146daSDan Mcgregor 			    unvis_len = strnunvis(unvis_dir, sizeof(unvis_dir),
16427c5146daSDan Mcgregor 				cp);
16437c5146daSDan Mcgregor 			    if (unvis_len <= 0) {
16447c5146daSDan Mcgregor 				getexp_err(ep, tgrp, "Cannot strunvis "
16457c5146daSDan Mcgregor 				    "decode dir");
16467c5146daSDan Mcgregor 				goto nextline;
16477c5146daSDan Mcgregor 			    }
1648bcc1d071SRick Macklem 			    if (v4root_phase > 1) {
1649bcc1d071SRick Macklem 				    if (dirp != NULL) {
1650354fce28SConrad Meyer 					getexp_err(ep, tgrp, "Multiple V4 dirs");
1651bcc1d071SRick Macklem 					goto nextline;
1652bcc1d071SRick Macklem 				    }
1653bcc1d071SRick Macklem 			    }
16547c5146daSDan Mcgregor 			    if (check_dirpath(unvis_dir, &err_msg) &&
16557c5146daSDan Mcgregor 				check_statfs(unvis_dir, &fsb, &err_msg)) {
16569896584aSRick Macklem 				if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0)
16579896584aSRick Macklem 				    syslog(LOG_ERR, "Warning: exporting of "
16587c5146daSDan Mcgregor 					"automounted fs %s not supported",
16597c5146daSDan Mcgregor 					unvis_dir);
16608fae3551SRodney W. Grimes 				if (got_nondir) {
1661354fce28SConrad Meyer 				    getexp_err(ep, tgrp, "dirs must be first");
16628fae3551SRodney W. Grimes 				    goto nextline;
16638fae3551SRodney W. Grimes 				}
1664bcc1d071SRick Macklem 				if (v4root_phase == 1) {
1665bcc1d071SRick Macklem 				    if (dirp != NULL) {
1666354fce28SConrad Meyer 					getexp_err(ep, tgrp, "Multiple V4 dirs");
1667bcc1d071SRick Macklem 					goto nextline;
1668bcc1d071SRick Macklem 				    }
1669bcc1d071SRick Macklem 				    if (strlen(v4root_dirpath) == 0) {
16707c5146daSDan Mcgregor 					strlcpy(v4root_dirpath, unvis_dir,
1671bcc1d071SRick Macklem 					    sizeof (v4root_dirpath));
16727c5146daSDan Mcgregor 				    } else if (strcmp(v4root_dirpath, unvis_dir)
1673bcc1d071SRick Macklem 					!= 0) {
1674bcc1d071SRick Macklem 					syslog(LOG_ERR,
16757c5146daSDan Mcgregor 					    "different V4 dirpath %s",
16767c5146daSDan Mcgregor 					    unvis_dir);
1677354fce28SConrad Meyer 					getexp_err(ep, tgrp, NULL);
1678bcc1d071SRick Macklem 					goto nextline;
1679bcc1d071SRick Macklem 				    }
16807c5146daSDan Mcgregor 				    dirp = unvis_dir;
1681bcc1d071SRick Macklem 				    v4root_phase = 2;
1682bcc1d071SRick Macklem 				    got_nondir = 1;
1683bcc1d071SRick Macklem 				    ep = get_exp();
1684bcc1d071SRick Macklem 				} else {
16858fae3551SRodney W. Grimes 				    if (ep) {
1686245bfd34SRyan Moeller 					if (fsidcmp(&ep->ex_fs, &fsb.f_fsid)
1687245bfd34SRyan Moeller 					    != 0) {
1688354fce28SConrad Meyer 						getexp_err(ep, tgrp,
1689354fce28SConrad Meyer 						    "fsid mismatch");
16908fae3551SRodney W. Grimes 						goto nextline;
16918fae3551SRodney W. Grimes 					}
16928fae3551SRodney W. Grimes 				    } else {
16938fae3551SRodney W. Grimes 					/*
16948fae3551SRodney W. Grimes 					 * See if this directory is already
16958fae3551SRodney W. Grimes 					 * in the list.
16968fae3551SRodney W. Grimes 					 */
169746a6b5c4SRick Macklem 					ep = ex_search(&fsb.f_fsid, exphead);
16988fae3551SRodney W. Grimes 					if (ep == (struct exportlist *)NULL) {
16998fae3551SRodney W. Grimes 					    ep = get_exp();
17008fae3551SRodney W. Grimes 					    ep->ex_fs = fsb.f_fsid;
1701380a3fcdSEmmanuel Vadot 					    ep->ex_fsdir = strdup(fsb.f_mntonname);
1702380a3fcdSEmmanuel Vadot 					    if (ep->ex_fsdir == NULL)
17038fae3551SRodney W. Grimes 						out_of_mem();
17048fae3551SRodney W. Grimes 					    if (debug)
1705bcc1d071SRick Macklem 						warnx(
1706bcc1d071SRick Macklem 						  "making new ep fs=0x%x,0x%x",
17078fae3551SRodney W. Grimes 						  fsb.f_fsid.val[0],
17088fae3551SRodney W. Grimes 						  fsb.f_fsid.val[1]);
17098fae3551SRodney W. Grimes 					} else if (debug)
171074853402SPhilippe Charnier 					    warnx("found ep fs=0x%x,0x%x",
17118fae3551SRodney W. Grimes 						fsb.f_fsid.val[0],
17128fae3551SRodney W. Grimes 						fsb.f_fsid.val[1]);
17138fae3551SRodney W. Grimes 				    }
17148fae3551SRodney W. Grimes 
1715fefb7c39SRick Macklem 				    if (warn_admin != 0 &&
1716fefb7c39SRick Macklem 					(ep->ex_flag & EX_ADMINWARN) == 0 &&
1717fefb7c39SRick Macklem 					strcmp(unvis_dir, fsb.f_mntonname) !=
1718fefb7c39SRick Macklem 					0) {
1719fefb7c39SRick Macklem 					if (debug)
1720fefb7c39SRick Macklem 					    warnx("exporting %s exports entire "
1721fefb7c39SRick Macklem 						"%s file system", unvis_dir,
1722fefb7c39SRick Macklem 						    fsb.f_mntonname);
1723fefb7c39SRick Macklem 					syslog(LOG_ERR, "Warning: exporting %s "
1724fefb7c39SRick Macklem 					    "exports entire %s file system",
1725fefb7c39SRick Macklem 					    unvis_dir, fsb.f_mntonname);
1726fefb7c39SRick Macklem 					ep->ex_flag |= EX_ADMINWARN;
1727fefb7c39SRick Macklem 				    }
1728fefb7c39SRick Macklem 
17298fae3551SRodney W. Grimes 				    /*
17308fae3551SRodney W. Grimes 				     * Add dirpath to export mount point.
17318fae3551SRodney W. Grimes 				     */
17327c5146daSDan Mcgregor 				    dirp = add_expdir(&dirhead, unvis_dir,
17337c5146daSDan Mcgregor 					unvis_len);
17347c5146daSDan Mcgregor 				    dirplen = unvis_len;
1735bcc1d071SRick Macklem 				}
17368fae3551SRodney W. Grimes 			    } else {
1737572b77f8SAlexander Motin 				if (err_msg != NULL) {
1738572b77f8SAlexander Motin 					getexp_err(ep, tgrp, err_msg);
1739572b77f8SAlexander Motin 					free(err_msg);
1740572b77f8SAlexander Motin 					err_msg = NULL;
1741572b77f8SAlexander Motin 				} else {
1742354fce28SConrad Meyer 					getexp_err(ep, tgrp,
1743572b77f8SAlexander Motin 					    "symbolic link in export path or "
1744572b77f8SAlexander Motin 					    "statfs failed");
1745572b77f8SAlexander Motin 				}
17468fae3551SRodney W. Grimes 				goto nextline;
17478fae3551SRodney W. Grimes 			    }
17488fae3551SRodney W. Grimes 			    *endcp = savedc;
17498fae3551SRodney W. Grimes 			} else {
17508fae3551SRodney W. Grimes 			    savedc = *endcp;
17518fae3551SRodney W. Grimes 			    *endcp = '\0';
17528fae3551SRodney W. Grimes 			    got_nondir = 1;
17538fae3551SRodney W. Grimes 			    if (ep == (struct exportlist *)NULL) {
1754354fce28SConrad Meyer 				getexp_err(ep, tgrp,
1755354fce28SConrad Meyer 				    "host(s) before export path definition");
17568fae3551SRodney W. Grimes 				goto nextline;
17578fae3551SRodney W. Grimes 			    }
17588fae3551SRodney W. Grimes 
17598fae3551SRodney W. Grimes 			    /*
17608fae3551SRodney W. Grimes 			     * Get the host or netgroup.
17618fae3551SRodney W. Grimes 			     */
17628fae3551SRodney W. Grimes 			    setnetgrent(cp);
17638fae3551SRodney W. Grimes 			    netgrp = getnetgrent(&hst, &usr, &dom);
17648fae3551SRodney W. Grimes 			    do {
17658fae3551SRodney W. Grimes 				if (has_host) {
17668fae3551SRodney W. Grimes 				    grp->gr_next = get_grp();
17678fae3551SRodney W. Grimes 				    grp = grp->gr_next;
17688fae3551SRodney W. Grimes 				}
17698fae3551SRodney W. Grimes 				if (netgrp) {
17709d70a156SJoerg Wunsch 				    if (hst == 0) {
177174853402SPhilippe Charnier 					syslog(LOG_ERR,
177274853402SPhilippe Charnier 				"null hostname in netgroup %s, skipping", cp);
177301d48801SJoerg Wunsch 					grp->gr_type = GT_IGNORE;
17749d70a156SJoerg Wunsch 				    } else if (get_host(hst, grp, tgrp)) {
177574853402SPhilippe Charnier 					syslog(LOG_ERR,
177674853402SPhilippe Charnier 			"bad host %s in netgroup %s, skipping", hst, cp);
1777a968cfd8SJonathan Lemon 					grp->gr_type = GT_IGNORE;
17788fae3551SRodney W. Grimes 				    }
17798b5a6d67SBill Paul 				} else if (get_host(cp, grp, tgrp)) {
178074853402SPhilippe Charnier 				    syslog(LOG_ERR, "bad host %s, skipping", cp);
1781a968cfd8SJonathan Lemon 				    grp->gr_type = GT_IGNORE;
17828fae3551SRodney W. Grimes 				}
17838fae3551SRodney W. Grimes 				has_host = TRUE;
17848fae3551SRodney W. Grimes 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
17858fae3551SRodney W. Grimes 			    endnetgrent();
17868fae3551SRodney W. Grimes 			    *endcp = savedc;
17878fae3551SRodney W. Grimes 			}
17888fae3551SRodney W. Grimes 			cp = endcp;
17898fae3551SRodney W. Grimes 			nextfield(&cp, &endcp);
17908fae3551SRodney W. Grimes 			len = endcp - cp;
17918fae3551SRodney W. Grimes 		}
179248514c57SMike Karels 		if (opt_flags & OP_CLASSMASK)
179348514c57SMike Karels 			syslog(LOG_WARNING,
179448514c57SMike Karels 			    "WARNING: No mask specified for %s, "
179548514c57SMike Karels 			    "using out-of-date default",
179648514c57SMike Karels 			    (&grp->gr_ptr.gt_net)->nt_name);
17978fae3551SRodney W. Grimes 		if (check_options(dirhead)) {
1798354fce28SConrad Meyer 			getexp_err(ep, tgrp, NULL);
17998fae3551SRodney W. Grimes 			goto nextline;
18008fae3551SRodney W. Grimes 		}
18018fae3551SRodney W. Grimes 		if (!has_host) {
18026d359f31SIan Dowse 			grp->gr_type = GT_DEFAULT;
18038fae3551SRodney W. Grimes 			if (debug)
180474853402SPhilippe Charnier 				warnx("adding a default entry");
18058fae3551SRodney W. Grimes 
18068fae3551SRodney W. Grimes 		/*
18078fae3551SRodney W. Grimes 		 * Don't allow a network export coincide with a list of
18088fae3551SRodney W. Grimes 		 * host(s) on the same line.
18098fae3551SRodney W. Grimes 		 */
18108fae3551SRodney W. Grimes 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
1811354fce28SConrad Meyer 			getexp_err(ep, tgrp, "network/host conflict");
18128fae3551SRodney W. Grimes 			goto nextline;
1813a968cfd8SJonathan Lemon 
1814a968cfd8SJonathan Lemon 		/*
1815a968cfd8SJonathan Lemon 		 * If an export list was specified on this line, make sure
1816a968cfd8SJonathan Lemon 		 * that we have at least one valid entry, otherwise skip it.
1817a968cfd8SJonathan Lemon 		 */
1818a968cfd8SJonathan Lemon 		} else {
1819a968cfd8SJonathan Lemon 			grp = tgrp;
1820a968cfd8SJonathan Lemon 			while (grp && grp->gr_type == GT_IGNORE)
1821a968cfd8SJonathan Lemon 				grp = grp->gr_next;
1822a968cfd8SJonathan Lemon 			if (! grp) {
1823354fce28SConrad Meyer 			    getexp_err(ep, tgrp, "no valid entries");
1824a968cfd8SJonathan Lemon 			    goto nextline;
1825a968cfd8SJonathan Lemon 			}
18268fae3551SRodney W. Grimes 		}
18278fae3551SRodney W. Grimes 
1828bcc1d071SRick Macklem 		if (v4root_phase == 1) {
1829354fce28SConrad Meyer 			getexp_err(ep, tgrp, "V4:root, no dirp, ignored");
1830bcc1d071SRick Macklem 			goto nextline;
1831bcc1d071SRick Macklem 		}
1832bcc1d071SRick Macklem 
18338fae3551SRodney W. Grimes 		/*
18348fae3551SRodney W. Grimes 		 * Loop through hosts, pushing the exports into the kernel.
18358fae3551SRodney W. Grimes 		 * After loop, tgrp points to the start of the list and
18368fae3551SRodney W. Grimes 		 * grp points to the last entry in the list.
18370f0869bcSRick Macklem 		 * Do not do the do_mount() for passno == 1, since the
18380f0869bcSRick Macklem 		 * second pass will do it, as required.
18398fae3551SRodney W. Grimes 		 */
18408fae3551SRodney W. Grimes 		grp = tgrp;
18418fae3551SRodney W. Grimes 		do {
18420f0869bcSRick Macklem 			grp->gr_exflags = exflags;
1843cc5efddeSRick Macklem 			cp_cred(&grp->gr_anon, &anon);
18440f0869bcSRick Macklem 			if (v4root_phase == 2 && passno == 0)
18450f0869bcSRick Macklem 				LOGDEBUG("do_mount v4root");
18460f0869bcSRick Macklem 			if (passno == 0 && do_mount(ep, grp, exflags, &anon,
18470f0869bcSRick Macklem 			    dirp, dirplen, &fsb, ep->ex_numsecflavors,
18480f0869bcSRick Macklem 			    ep->ex_secflavors)) {
1849354fce28SConrad Meyer 				getexp_err(ep, tgrp, NULL);
18508fae3551SRodney W. Grimes 				goto nextline;
18518fae3551SRodney W. Grimes 			}
18528fae3551SRodney W. Grimes 		} while (grp->gr_next && (grp = grp->gr_next));
18538fae3551SRodney W. Grimes 
18548fae3551SRodney W. Grimes 		/*
1855bcc1d071SRick Macklem 		 * For V4: don't enter in mount lists.
1856bcc1d071SRick Macklem 		 */
185773f4ccbdSRick Macklem 		if (v4root_phase > 0 && v4root_phase <= 2) {
185873f4ccbdSRick Macklem 			/*
1859c2ec1113SRick Macklem 			 * These structures are used for the reload,
18600f0869bcSRick Macklem 			 * so save them for that case.  Otherwise, just
186173f4ccbdSRick Macklem 			 * free them up now.
186273f4ccbdSRick Macklem 			 */
18630f0869bcSRick Macklem 			if (passno == 1 && ep != NULL) {
18640f0869bcSRick Macklem 				savgrp = tgrp;
18650f0869bcSRick Macklem 				while (tgrp != NULL) {
18660f0869bcSRick Macklem 					/*
18670f0869bcSRick Macklem 					 * Save the security flavors and exflags
18680f0869bcSRick Macklem 					 * for this host set in the groups.
18690f0869bcSRick Macklem 					 */
18700f0869bcSRick Macklem 					tgrp->gr_numsecflavors =
18710f0869bcSRick Macklem 					    ep->ex_numsecflavors;
18720f0869bcSRick Macklem 					if (ep->ex_numsecflavors > 0)
18730f0869bcSRick Macklem 						memcpy(tgrp->gr_secflavors,
18740f0869bcSRick Macklem 						    ep->ex_secflavors,
18750f0869bcSRick Macklem 						    sizeof(ep->ex_secflavors));
18760f0869bcSRick Macklem 					tgrp = tgrp->gr_next;
18770f0869bcSRick Macklem 				}
18780f0869bcSRick Macklem 				if (v4root_ep == NULL) {
18790f0869bcSRick Macklem 					v4root_ep = ep;
18800f0869bcSRick Macklem 					ep = NULL;	/* Don't free below. */
18810f0869bcSRick Macklem 				}
18820f0869bcSRick Macklem 				grp->gr_next = v4root_ep->ex_grphead;
18830f0869bcSRick Macklem 				v4root_ep->ex_grphead = savgrp;
18840f0869bcSRick Macklem 			}
188573f4ccbdSRick Macklem 			if (ep != NULL)
188673f4ccbdSRick Macklem 				free_exp(ep);
188773f4ccbdSRick Macklem 			while (tgrp != NULL) {
188873f4ccbdSRick Macklem 				grp = tgrp;
188973f4ccbdSRick Macklem 				tgrp = tgrp->gr_next;
189073f4ccbdSRick Macklem 				free_grp(grp);
189173f4ccbdSRick Macklem 			}
1892bcc1d071SRick Macklem 			goto nextline;
189373f4ccbdSRick Macklem 		}
1894bcc1d071SRick Macklem 
1895bcc1d071SRick Macklem 		/*
18968fae3551SRodney W. Grimes 		 * Success. Update the data structures.
18978fae3551SRodney W. Grimes 		 */
18988fae3551SRodney W. Grimes 		if (has_host) {
18990f0869bcSRick Macklem 			hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags);
1900711d44eeSRick Macklem 			grp->gr_next = ep->ex_grphead;
1901711d44eeSRick Macklem 			ep->ex_grphead = tgrp;
19028fae3551SRodney W. Grimes 		} else {
19038fae3551SRodney W. Grimes 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
19040f0869bcSRick Macklem 				opt_flags, &anon, exflags);
19058fae3551SRodney W. Grimes 			free_grp(grp);
19068fae3551SRodney W. Grimes 		}
19078fae3551SRodney W. Grimes 		dirhead = (struct dirlist *)NULL;
19088fae3551SRodney W. Grimes 		if ((ep->ex_flag & EX_LINKED) == 0) {
190946a6b5c4SRick Macklem 			insert_exports(ep, exphead);
19108fae3551SRodney W. Grimes 
19118fae3551SRodney W. Grimes 			ep->ex_flag |= EX_LINKED;
19128fae3551SRodney W. Grimes 		}
19138fae3551SRodney W. Grimes nextline:
1914bcc1d071SRick Macklem 		v4root_phase = 0;
19158fae3551SRodney W. Grimes 		if (dirhead) {
19168fae3551SRodney W. Grimes 			free_dir(dirhead);
19178fae3551SRodney W. Grimes 			dirhead = (struct dirlist *)NULL;
19188fae3551SRodney W. Grimes 		}
19192ffad162SRick Macklem 		if (anon.cr_groups != anon.cr_smallgrps) {
19202ffad162SRick Macklem 			free(anon.cr_groups);
19212ffad162SRick Macklem 			anon.cr_groups = NULL;
19222ffad162SRick Macklem 		}
19238fae3551SRodney W. Grimes 	}
192496968c22SPawel Jakub Dawidek }
192596968c22SPawel Jakub Dawidek 
192696968c22SPawel Jakub Dawidek /*
192796968c22SPawel Jakub Dawidek  * Get the export list from all specified files
192896968c22SPawel Jakub Dawidek  */
192919c46d8cSEdward Tomasz Napierala static void
get_exportlist(int passno)19300f0869bcSRick Macklem get_exportlist(int passno)
193196968c22SPawel Jakub Dawidek {
193296968c22SPawel Jakub Dawidek 	struct export_args export;
193396968c22SPawel Jakub Dawidek 	struct iovec *iov;
19343e08dc74SRick Macklem 	struct statfs *mntbufp;
193596968c22SPawel Jakub Dawidek 	char errmsg[255];
193609673fc0SRick Macklem 	int error, i, nfs_maxvers, num;
193796968c22SPawel Jakub Dawidek 	int iovlen;
1938bcc1d071SRick Macklem 	struct nfsex_args eargs;
19390f0869bcSRick Macklem 	FILE *debug_file;
194009673fc0SRick Macklem 	size_t nfs_maxvers_size;
194196968c22SPawel Jakub Dawidek 
19420f0869bcSRick Macklem 	if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) {
19430f0869bcSRick Macklem 		fclose(debug_file);
19440f0869bcSRick Macklem 		logdebug = 1;
19450f0869bcSRick Macklem 	} else
19460f0869bcSRick Macklem 		logdebug = 0;
19470f0869bcSRick Macklem 	LOGDEBUG("passno=%d", passno);
1948bcc1d071SRick Macklem 	v4root_dirpath[0] = '\0';
19490f0869bcSRick Macklem 	free_v4rootexp();
19500f0869bcSRick Macklem 	if (passno == 1) {
19510f0869bcSRick Macklem 		/*
19520f0869bcSRick Macklem 		 * Save the current lists as old ones, so that the new lists
19530f0869bcSRick Macklem 		 * can be compared with the old ones in the 2nd pass.
19540f0869bcSRick Macklem 		 */
19550f0869bcSRick Macklem 		for (i = 0; i < exphashsize; i++) {
19560f0869bcSRick Macklem 			SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]);
19570f0869bcSRick Macklem 			SLIST_INIT(&exphead[i]);
19580f0869bcSRick Macklem 		}
19590f0869bcSRick Macklem 
19600f0869bcSRick Macklem 		/* Note that the public fh has not yet been set. */
19610f0869bcSRick Macklem 		has_set_publicfh = 0;
19620f0869bcSRick Macklem 
19630f0869bcSRick Macklem 		/* Read the export file(s) and process them */
19640f0869bcSRick Macklem 		read_exportfile(passno);
19650f0869bcSRick Macklem 	} else {
19660f0869bcSRick Macklem 		/*
19670f0869bcSRick Macklem 		 * Just make the old lists empty.
19680f0869bcSRick Macklem 		 * exphashsize == 0 for the first call, before oldexphead
19690f0869bcSRick Macklem 		 * has been initialized-->loop won't be executed.
19700f0869bcSRick Macklem 		 */
19710f0869bcSRick Macklem 		for (i = 0; i < exphashsize; i++)
19720f0869bcSRick Macklem 			SLIST_INIT(&oldexphead[i]);
19730f0869bcSRick Macklem 	}
19740f0869bcSRick Macklem 
197596968c22SPawel Jakub Dawidek 	bzero(&export, sizeof(export));
197696968c22SPawel Jakub Dawidek 	export.ex_flags = MNT_DELEXPORT;
197796968c22SPawel Jakub Dawidek 	iov = NULL;
197896968c22SPawel Jakub Dawidek 	iovlen = 0;
197996968c22SPawel Jakub Dawidek 	bzero(errmsg, sizeof(errmsg));
198096968c22SPawel Jakub Dawidek 
19810f0869bcSRick Macklem 	if (suspend_nfsd != 0)
19820f0869bcSRick Macklem 		(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL);
198396968c22SPawel Jakub Dawidek 	/*
19840f0869bcSRick Macklem 	 * Delete the old V4 root dir.
1985bcc1d071SRick Macklem 	 */
1986bcc1d071SRick Macklem 	bzero(&eargs, sizeof (eargs));
1987bcc1d071SRick Macklem 	eargs.export.ex_flags = MNT_DELEXPORT;
1988cc5efddeSRick Macklem 	if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, (caddr_t)&eargs) < 0 &&
1989bcc1d071SRick Macklem 	    errno != ENOENT)
1990bcc1d071SRick Macklem 		syslog(LOG_ERR, "Can't delete exports for V4:");
1991bcc1d071SRick Macklem 
19920f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "fstype", NULL, 0);
19930f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "fspath", NULL, 0);
19940f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "from", NULL, 0);
19950f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "update", NULL, 0);
19960f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "export", &export,
19970f0869bcSRick Macklem 	    sizeof(export));
19980f0869bcSRick Macklem 	build_iovec(&iov, &iovlen, "errmsg", errmsg,
19990f0869bcSRick Macklem 	    sizeof(errmsg));
20000f0869bcSRick Macklem 
2001bcc1d071SRick Macklem 	/*
20020f0869bcSRick Macklem 	 * For passno == 1, compare the old and new lists updating the kernel
20030f0869bcSRick Macklem 	 * exports for any cases that have changed.
20040f0869bcSRick Macklem 	 * This call is doing the second pass through the lists.
20050f0869bcSRick Macklem 	 * If it fails, fall back on the bulk reload.
20060f0869bcSRick Macklem 	 */
20070f0869bcSRick Macklem 	if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) ==
20080f0869bcSRick Macklem 	    0) {
20090f0869bcSRick Macklem 		LOGDEBUG("compareok");
20100f0869bcSRick Macklem 		/* Free up the old lists. */
20110f0869bcSRick Macklem 		free_exports(oldexphead);
20120f0869bcSRick Macklem 	} else {
20130f0869bcSRick Macklem 		LOGDEBUG("doing passno=0");
20140f0869bcSRick Macklem 		/*
20150f0869bcSRick Macklem 		 * Clear flag that notes if a public fh has been exported.
20160f0869bcSRick Macklem 		 * It is set by do_mount() if MNT_EXPUBLIC is set for the entry.
2017bcc1d071SRick Macklem 		 */
2018bcc1d071SRick Macklem 		has_publicfh = 0;
2019bcc1d071SRick Macklem 
20200f0869bcSRick Macklem 		/* exphead == NULL if not yet allocated (first call). */
20210f0869bcSRick Macklem 		if (exphead != NULL) {
20220f0869bcSRick Macklem 			/*
20230f0869bcSRick Macklem 			 * First, get rid of the old lists.
20240f0869bcSRick Macklem 			 */
20250f0869bcSRick Macklem 			free_exports(exphead);
20260f0869bcSRick Macklem 			free_exports(oldexphead);
20270f0869bcSRick Macklem 		}
20280f0869bcSRick Macklem 
2029bcc1d071SRick Macklem 		/*
203096968c22SPawel Jakub Dawidek 		 * And delete exports that are in the kernel for all local
203196968c22SPawel Jakub Dawidek 		 * filesystems.
20320f0869bcSRick Macklem 		 * XXX: Should know how to handle all local exportable
20330f0869bcSRick Macklem 		 * filesystems.
203496968c22SPawel Jakub Dawidek 		 */
203596968c22SPawel Jakub Dawidek 		num = getmntinfo(&mntbufp, MNT_NOWAIT);
203696968c22SPawel Jakub Dawidek 
203746a6b5c4SRick Macklem 		/* Allocate hash tables, for first call. */
203846a6b5c4SRick Macklem 		if (exphead == NULL) {
203946a6b5c4SRick Macklem 			/* Target an average linked list length of 10. */
204046a6b5c4SRick Macklem 			exphashsize = num / 10;
204146a6b5c4SRick Macklem 			if (exphashsize < 1)
204246a6b5c4SRick Macklem 				exphashsize = 1;
204346a6b5c4SRick Macklem 			else if (exphashsize > 100000)
204446a6b5c4SRick Macklem 				exphashsize = 100000;
204546a6b5c4SRick Macklem 			exphead = malloc(exphashsize * sizeof(*exphead));
20460f0869bcSRick Macklem 			oldexphead = malloc(exphashsize * sizeof(*oldexphead));
20470f0869bcSRick Macklem 			if (exphead == NULL || oldexphead == NULL)
20480f0869bcSRick Macklem 				errx(1, "Can't malloc hash tables");
204946a6b5c4SRick Macklem 
20500f0869bcSRick Macklem 			for (i = 0; i < exphashsize; i++) {
205146a6b5c4SRick Macklem 				SLIST_INIT(&exphead[i]);
20520f0869bcSRick Macklem 				SLIST_INIT(&oldexphead[i]);
205346a6b5c4SRick Macklem 			}
205496968c22SPawel Jakub Dawidek 		}
205596968c22SPawel Jakub Dawidek 
20563e08dc74SRick Macklem 		for (i = 0; i < num; i++)
20573e08dc74SRick Macklem 			delete_export(iov, iovlen, &mntbufp[i], errmsg);
205896968c22SPawel Jakub Dawidek 
20590f0869bcSRick Macklem 
20600f0869bcSRick Macklem 		/* Read the export file(s) and process them */
20610f0869bcSRick Macklem 		read_exportfile(0);
20620f0869bcSRick Macklem 	}
20630f0869bcSRick Macklem 
206409673fc0SRick Macklem 	if (strlen(v4root_dirpath) == 0) {
206509673fc0SRick Macklem 		/* Check to see if a V4: line is needed. */
206609673fc0SRick Macklem 		nfs_maxvers_size = sizeof(nfs_maxvers);
206709673fc0SRick Macklem 		error = sysctlbyname("vfs.nfsd.server_max_nfsvers",
206809673fc0SRick Macklem 		    &nfs_maxvers, &nfs_maxvers_size, NULL, 0);
206909673fc0SRick Macklem 		if (error != 0 || nfs_maxvers < NFS_VER2 || nfs_maxvers >
207009673fc0SRick Macklem 		    NFS_VER4) {
207109673fc0SRick Macklem 			syslog(LOG_ERR, "sysctlbyname(vfs.nfsd."
207209673fc0SRick Macklem 			    "server_max_nfsvers) failed, defaulting to NFSv3");
207309673fc0SRick Macklem 			nfs_maxvers = NFS_VER3;
207409673fc0SRick Macklem 		}
207509673fc0SRick Macklem 		if (nfs_maxvers == NFS_VER4)
207609673fc0SRick Macklem 			syslog(LOG_ERR, "NFSv4 requires at least one V4: line");
207709673fc0SRick Macklem 	}
207809673fc0SRick Macklem 
207996968c22SPawel Jakub Dawidek 	if (iov != NULL) {
208096968c22SPawel Jakub Dawidek 		/* Free strings allocated by strdup() in getmntopts.c */
208196968c22SPawel Jakub Dawidek 		free(iov[0].iov_base); /* fstype */
208296968c22SPawel Jakub Dawidek 		free(iov[2].iov_base); /* fspath */
208396968c22SPawel Jakub Dawidek 		free(iov[4].iov_base); /* from */
208496968c22SPawel Jakub Dawidek 		free(iov[6].iov_base); /* update */
208596968c22SPawel Jakub Dawidek 		free(iov[8].iov_base); /* export */
208696968c22SPawel Jakub Dawidek 		free(iov[10].iov_base); /* errmsg */
208796968c22SPawel Jakub Dawidek 
208896968c22SPawel Jakub Dawidek 		/* free iov, allocated by realloc() */
208996968c22SPawel Jakub Dawidek 		free(iov);
209096968c22SPawel Jakub Dawidek 		iovlen = 0;
209196968c22SPawel Jakub Dawidek 	}
209296968c22SPawel Jakub Dawidek 
2093bcc1d071SRick Macklem 	/*
2094bcc1d071SRick Macklem 	 * If there was no public fh, clear any previous one set.
2095bcc1d071SRick Macklem 	 */
20960f0869bcSRick Macklem 	if (has_publicfh == 0) {
20970f0869bcSRick Macklem 		LOGDEBUG("clear public fh");
2098bcc1d071SRick Macklem 		(void) nfssvc(NFSSVC_NOPUBLICFH, NULL);
20990f0869bcSRick Macklem 	}
2100c548eb5cSRick Macklem 
2101c548eb5cSRick Macklem 	/* Resume the nfsd. If they weren't suspended, this is harmless. */
2102c548eb5cSRick Macklem 	(void)nfssvc(NFSSVC_RESUMENFSD, NULL);
21030f0869bcSRick Macklem 	LOGDEBUG("eo get_exportlist");
210496968c22SPawel Jakub Dawidek }
21058fae3551SRodney W. Grimes 
21068fae3551SRodney W. Grimes /*
21071a9a992fSRick Macklem  * Insert an export entry in the appropriate list.
21081a9a992fSRick Macklem  */
21091a9a992fSRick Macklem static void
insert_exports(struct exportlist * ep,struct exportlisthead * exhp)21101a9a992fSRick Macklem insert_exports(struct exportlist *ep, struct exportlisthead *exhp)
21111a9a992fSRick Macklem {
211246a6b5c4SRick Macklem 	uint32_t i;
21131a9a992fSRick Macklem 
211446a6b5c4SRick Macklem 	i = EXPHASH(&ep->ex_fs);
21150f0869bcSRick Macklem 	LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i);
211646a6b5c4SRick Macklem 	SLIST_INSERT_HEAD(&exhp[i], ep, entries);
21171a9a992fSRick Macklem }
21181a9a992fSRick Macklem 
21191a9a992fSRick Macklem /*
21201a9a992fSRick Macklem  * Free up the exports lists passed in as arguments.
21211a9a992fSRick Macklem  */
21221a9a992fSRick Macklem static void
free_exports(struct exportlisthead * exhp)21231a9a992fSRick Macklem free_exports(struct exportlisthead *exhp)
21241a9a992fSRick Macklem {
21251a9a992fSRick Macklem 	struct exportlist *ep, *ep2;
212646a6b5c4SRick Macklem 	int i;
21271a9a992fSRick Macklem 
212846a6b5c4SRick Macklem 	for (i = 0; i < exphashsize; i++) {
212946a6b5c4SRick Macklem 		SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) {
213046a6b5c4SRick Macklem 			SLIST_REMOVE(&exhp[i], ep, exportlist, entries);
21311a9a992fSRick Macklem 			free_exp(ep);
21321a9a992fSRick Macklem 		}
213346a6b5c4SRick Macklem 		SLIST_INIT(&exhp[i]);
213446a6b5c4SRick Macklem 	}
21351a9a992fSRick Macklem }
21361a9a992fSRick Macklem 
21371a9a992fSRick Macklem /*
21383e08dc74SRick Macklem  * Read the exports file(s) and call get_exportlist_one() for each line.
21393e08dc74SRick Macklem  */
21403e08dc74SRick Macklem static void
read_exportfile(int passno)21410f0869bcSRick Macklem read_exportfile(int passno)
21423e08dc74SRick Macklem {
21433e08dc74SRick Macklem 	int done, i;
21443e08dc74SRick Macklem 
21453e08dc74SRick Macklem 	/*
21463e08dc74SRick Macklem 	 * Read in the exports file and build the list, calling
21473e08dc74SRick Macklem 	 * nmount() as we go along to push the export rules into the kernel.
21483e08dc74SRick Macklem 	 */
21493e08dc74SRick Macklem 	done = 0;
21503e08dc74SRick Macklem 	for (i = 0; exnames[i] != NULL; i++) {
21513e08dc74SRick Macklem 		if (debug)
21523e08dc74SRick Macklem 			warnx("reading exports from %s", exnames[i]);
21533e08dc74SRick Macklem 		if ((exp_file = fopen(exnames[i], "r")) == NULL) {
21543e08dc74SRick Macklem 			syslog(LOG_WARNING, "can't open %s", exnames[i]);
21553e08dc74SRick Macklem 			continue;
21563e08dc74SRick Macklem 		}
21570f0869bcSRick Macklem 		get_exportlist_one(passno);
21583e08dc74SRick Macklem 		fclose(exp_file);
21593e08dc74SRick Macklem 		done++;
21603e08dc74SRick Macklem 	}
21613e08dc74SRick Macklem 	if (done == 0) {
21623e08dc74SRick Macklem 		syslog(LOG_ERR, "can't open any exports file");
21633e08dc74SRick Macklem 		exit(2);
21643e08dc74SRick Macklem 	}
21653e08dc74SRick Macklem }
21663e08dc74SRick Macklem 
21673e08dc74SRick Macklem /*
21680f0869bcSRick Macklem  * Compare the export lists against the old ones and do nmount() operations
21690f0869bcSRick Macklem  * for any cases that have changed.  This avoids doing nmount() for entries
21700f0869bcSRick Macklem  * that have not changed.
21710f0869bcSRick Macklem  * Return 0 upon success, 1 otherwise.
21720f0869bcSRick Macklem  */
21730f0869bcSRick Macklem static int
compare_nmount_exportlist(struct iovec * iov,int iovlen,char * errmsg)21740f0869bcSRick Macklem compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg)
21750f0869bcSRick Macklem {
21760f0869bcSRick Macklem 	struct exportlist *ep, *oep;
21770f0869bcSRick Macklem 	struct grouplist *grp;
21780f0869bcSRick Macklem 	struct statfs fs, ofs;
21790f0869bcSRick Macklem 	int i, ret;
21800f0869bcSRick Macklem 
21810f0869bcSRick Macklem 	/*
21820f0869bcSRick Macklem 	 * Loop through the current list and look for an entry in the old
21830f0869bcSRick Macklem 	 * list.
21840f0869bcSRick Macklem 	 * If found, check to see if it the same.
21850f0869bcSRick Macklem 	 *        If it is not the same, delete and re-export.
21860f0869bcSRick Macklem 	 *        Then mark it done on the old list.
21870f0869bcSRick Macklem 	 * else (not found)
21880f0869bcSRick Macklem 	 *        export it.
21890f0869bcSRick Macklem 	 * Any entries left in the old list after processing must have their
21900f0869bcSRick Macklem 	 * exports deleted.
21910f0869bcSRick Macklem 	 */
21920f0869bcSRick Macklem 	for (i = 0; i < exphashsize; i++)
21930f0869bcSRick Macklem 		SLIST_FOREACH(ep, &exphead[i], entries) {
21940f0869bcSRick Macklem 			LOGDEBUG("foreach ep=%s", ep->ex_fsdir);
21950f0869bcSRick Macklem 			oep = ex_search(&ep->ex_fs, oldexphead);
21960f0869bcSRick Macklem 			if (oep != NULL) {
21970f0869bcSRick Macklem 				/*
21980f0869bcSRick Macklem 				 * Check the mount paths are the same.
21990f0869bcSRick Macklem 				 * If not, return 1 so that the reload of the
22000f0869bcSRick Macklem 				 * exports will be done in bulk, the
22010f0869bcSRick Macklem 				 * passno == 0 way.
22020f0869bcSRick Macklem 				 */
22030f0869bcSRick Macklem 				LOGDEBUG("found old exp");
22040f0869bcSRick Macklem 				if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
22050f0869bcSRick Macklem 					return (1);
22060f0869bcSRick Macklem 				LOGDEBUG("same fsdir");
22070f0869bcSRick Macklem 				/*
22080f0869bcSRick Macklem 				 * Test to see if the entry is the same.
22090f0869bcSRick Macklem 				 * If not the same delete exports and
22100f0869bcSRick Macklem 				 * re-export.
22110f0869bcSRick Macklem 				 */
22120f0869bcSRick Macklem 				if (compare_export(ep, oep) != 0) {
22130f0869bcSRick Macklem 					/*
22140f0869bcSRick Macklem 					 * Clear has_publicfh if if was set
22150f0869bcSRick Macklem 					 * in the old exports, but only if it
22160f0869bcSRick Macklem 					 * has not been set during processing of
22170f0869bcSRick Macklem 					 * the exports for this pass, as
22180f0869bcSRick Macklem 					 * indicated by has_set_publicfh.
22190f0869bcSRick Macklem 					 */
22200f0869bcSRick Macklem 					if (has_set_publicfh == 0 &&
22210f0869bcSRick Macklem 					    (oep->ex_flag & EX_PUBLICFH) != 0)
22220f0869bcSRick Macklem 						has_publicfh = 0;
22230f0869bcSRick Macklem 
22240f0869bcSRick Macklem 					/* Delete and re-export. */
22250f0869bcSRick Macklem 					if (statfs(ep->ex_fsdir, &fs) < 0)
22260f0869bcSRick Macklem 						return (1);
22270f0869bcSRick Macklem 					delete_export(iov, iovlen, &fs, errmsg);
22280f0869bcSRick Macklem 					ret = do_export_mount(ep, &fs);
22290f0869bcSRick Macklem 					if (ret != 0)
22300f0869bcSRick Macklem 						return (ret);
22310f0869bcSRick Macklem 				}
22320f0869bcSRick Macklem 				oep->ex_flag |= EX_DONE;
22330f0869bcSRick Macklem 				LOGDEBUG("exdone");
22340f0869bcSRick Macklem 			} else {
22350f0869bcSRick Macklem 				LOGDEBUG("not found so export");
22360f0869bcSRick Macklem 				/* Not found, so do export. */
22370f0869bcSRick Macklem 				if (statfs(ep->ex_fsdir, &fs) < 0)
22380f0869bcSRick Macklem 					return (1);
22390f0869bcSRick Macklem 				ret = do_export_mount(ep, &fs);
22400f0869bcSRick Macklem 				if (ret != 0)
22410f0869bcSRick Macklem 					return (ret);
22420f0869bcSRick Macklem 			}
22430f0869bcSRick Macklem 		}
22440f0869bcSRick Macklem 
22450f0869bcSRick Macklem 	/* Delete exports not done. */
22460f0869bcSRick Macklem 	for (i = 0; i < exphashsize; i++)
22470f0869bcSRick Macklem 		SLIST_FOREACH(oep, &oldexphead[i], entries) {
22480f0869bcSRick Macklem 			if ((oep->ex_flag & EX_DONE) == 0) {
22490f0869bcSRick Macklem 				LOGDEBUG("not done delete=%s", oep->ex_fsdir);
22500f0869bcSRick Macklem 				if (statfs(oep->ex_fsdir, &ofs) >= 0 &&
2251245bfd34SRyan Moeller 				    fsidcmp(&oep->ex_fs, &ofs.f_fsid) == 0) {
22520f0869bcSRick Macklem 					LOGDEBUG("do delete");
22530f0869bcSRick Macklem 					/*
22540f0869bcSRick Macklem 					 * Clear has_publicfh if if was set
22550f0869bcSRick Macklem 					 * in the old exports, but only if it
22560f0869bcSRick Macklem 					 * has not been set during processing of
22570f0869bcSRick Macklem 					 * the exports for this pass, as
22580f0869bcSRick Macklem 					 * indicated by has_set_publicfh.
22590f0869bcSRick Macklem 					 */
22600f0869bcSRick Macklem 					if (has_set_publicfh == 0 &&
22610f0869bcSRick Macklem 					    (oep->ex_flag & EX_PUBLICFH) != 0)
22620f0869bcSRick Macklem 						has_publicfh = 0;
22630f0869bcSRick Macklem 
22640f0869bcSRick Macklem 					delete_export(iov, iovlen, &ofs,
22650f0869bcSRick Macklem 					    errmsg);
22660f0869bcSRick Macklem 				}
22670f0869bcSRick Macklem 			}
22680f0869bcSRick Macklem 		}
22690f0869bcSRick Macklem 
22700f0869bcSRick Macklem 	/* Do the V4 root exports, as required. */
22710f0869bcSRick Macklem 	grp = NULL;
22720f0869bcSRick Macklem 	if (v4root_ep != NULL)
22730f0869bcSRick Macklem 		grp = v4root_ep->ex_grphead;
22740f0869bcSRick Macklem 	v4root_phase = 2;
22750f0869bcSRick Macklem 	while (v4root_ep != NULL && grp != NULL) {
22760f0869bcSRick Macklem 		LOGDEBUG("v4root expath=%s", v4root_dirpath);
22770f0869bcSRick Macklem 		ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon,
22780f0869bcSRick Macklem 		    v4root_dirpath, strlen(v4root_dirpath), &fs,
22790f0869bcSRick Macklem 		    grp->gr_numsecflavors, grp->gr_secflavors);
22800f0869bcSRick Macklem 		if (ret != 0) {
22810f0869bcSRick Macklem 			v4root_phase = 0;
22820f0869bcSRick Macklem 			return (ret);
22830f0869bcSRick Macklem 		}
22840f0869bcSRick Macklem 		grp = grp->gr_next;
22850f0869bcSRick Macklem 	}
22860f0869bcSRick Macklem 	v4root_phase = 0;
22870f0869bcSRick Macklem 	free_v4rootexp();
22880f0869bcSRick Macklem 	return (0);
22890f0869bcSRick Macklem }
22900f0869bcSRick Macklem 
22910f0869bcSRick Macklem /*
22920f0869bcSRick Macklem  * Compare old and current exportlist entries for the fsid and return 0
22930f0869bcSRick Macklem  * if they are the same, 1 otherwise.
22940f0869bcSRick Macklem  */
22950f0869bcSRick Macklem static int
compare_export(struct exportlist * ep,struct exportlist * oep)22960f0869bcSRick Macklem compare_export(struct exportlist *ep, struct exportlist *oep)
22970f0869bcSRick Macklem {
22980f0869bcSRick Macklem 	struct grouplist *grp, *ogrp;
22990f0869bcSRick Macklem 
23000f0869bcSRick Macklem 	if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0)
23010f0869bcSRick Macklem 		return (1);
23020f0869bcSRick Macklem 	if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET))
23030f0869bcSRick Macklem 		return (1);
23040f0869bcSRick Macklem 	if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) ||
23050f0869bcSRick Macklem 	    (ep->ex_defdir == NULL && oep->ex_defdir != NULL))
23060f0869bcSRick Macklem 		return (1);
23070f0869bcSRick Macklem 	if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) !=
23080f0869bcSRick Macklem 	    (oep->ex_defdir->dp_flag & DP_DEFSET))
23090f0869bcSRick Macklem 		return (1);
23100f0869bcSRick Macklem 	if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors !=
23110f0869bcSRick Macklem 	    oep->ex_defnumsecflavors || ep->ex_defexflags !=
23120f0869bcSRick Macklem 	    oep->ex_defexflags || compare_cred(&ep->ex_defanon,
23130f0869bcSRick Macklem 	    &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors,
23140f0869bcSRick Macklem 	    oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0))
23150f0869bcSRick Macklem 		return (1);
23160f0869bcSRick Macklem 
23170f0869bcSRick Macklem 	/* Now, check all the groups. */
23180f0869bcSRick Macklem 	for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
23190f0869bcSRick Macklem 		ogrp->gr_flag = 0;
23200f0869bcSRick Macklem 	for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) {
23210f0869bcSRick Macklem 		for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp =
23220f0869bcSRick Macklem 		    ogrp->gr_next)
23230f0869bcSRick Macklem 			if ((ogrp->gr_flag & GR_FND) == 0 &&
23240f0869bcSRick Macklem 			    grp->gr_numsecflavors == ogrp->gr_numsecflavors &&
23250f0869bcSRick Macklem 			    grp->gr_exflags == ogrp->gr_exflags &&
23260f0869bcSRick Macklem 			    compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 &&
23270f0869bcSRick Macklem 			    compare_secflavor(grp->gr_secflavors,
23280f0869bcSRick Macklem 			    ogrp->gr_secflavors, grp->gr_numsecflavors) == 0)
23290f0869bcSRick Macklem 				break;
23300f0869bcSRick Macklem 		if (ogrp != NULL)
23310f0869bcSRick Macklem 			ogrp->gr_flag |= GR_FND;
23320f0869bcSRick Macklem 		else
23330f0869bcSRick Macklem 			return (1);
23340f0869bcSRick Macklem 	}
23350f0869bcSRick Macklem 	for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next)
23360f0869bcSRick Macklem 		if ((ogrp->gr_flag & GR_FND) == 0)
23370f0869bcSRick Macklem 			return (1);
23380f0869bcSRick Macklem 	return (0);
23390f0869bcSRick Macklem }
23400f0869bcSRick Macklem 
23410f0869bcSRick Macklem /*
23420f0869bcSRick Macklem  * This algorithm compares two arrays of "n" items. It returns 0 if they are
23430f0869bcSRick Macklem  * the "same" and 1 otherwise.  Although suboptimal, it is always safe to
23440f0869bcSRick Macklem  * return 1, which makes compare_nmount_export() reload the exports entry.
23450f0869bcSRick Macklem  * "same" refers to having the same set of values in the two arrays.
23460f0869bcSRick Macklem  * The arrays are in no particular order and duplicates (multiple entries
23470f0869bcSRick Macklem  * in an array with the same value) is allowed.
2348c77cc846SElyes Haouas  * The algorithm is inefficient, but the common case of identical arrays is
23490f0869bcSRick Macklem  * handled first and "n" is normally fairly small.
23500f0869bcSRick Macklem  * Since the two functions need the same algorithm but for arrays of
23510f0869bcSRick Macklem  * different types (gid_t vs int), this is done as a macro.
23520f0869bcSRick Macklem  */
23530f0869bcSRick Macklem #define	COMPARE_ARRAYS(a1, a2, n)					\
23540f0869bcSRick Macklem 	do {								\
23550f0869bcSRick Macklem 		int fnd, fndarray[(n)], i, j;				\
23560f0869bcSRick Macklem 		/* Handle common case of identical arrays. */		\
23570f0869bcSRick Macklem 		for (i = 0; i < (n); i++)				\
23580f0869bcSRick Macklem 			if ((a1)[i] != (a2)[i])				\
23590f0869bcSRick Macklem 				break;					\
23600f0869bcSRick Macklem 		if (i == (n))						\
23610f0869bcSRick Macklem 			return (0);					\
23620f0869bcSRick Macklem 		for (i = 0; i < (n); i++)				\
23630f0869bcSRick Macklem 			fndarray[i] = 0;				\
23640f0869bcSRick Macklem 		for (i = 0; i < (n); i++) {				\
23650f0869bcSRick Macklem 			fnd = 0;					\
23660f0869bcSRick Macklem 			for (j = 0; j < (n); j++) {			\
23670f0869bcSRick Macklem 				if ((a1)[i] == (a2)[j]) {		\
23680f0869bcSRick Macklem 					fndarray[j] = 1;		\
23690f0869bcSRick Macklem 					fnd = 1;			\
23700f0869bcSRick Macklem 				}					\
23710f0869bcSRick Macklem 			}						\
23720f0869bcSRick Macklem 			if (fnd == 0)					\
23730f0869bcSRick Macklem 				return (1);				\
23740f0869bcSRick Macklem 		}							\
23750f0869bcSRick Macklem 		for (i = 0; i < (n); i++)				\
23760f0869bcSRick Macklem 			if (fndarray[i] == 0)				\
23770f0869bcSRick Macklem 				return (1);				\
23780f0869bcSRick Macklem 		return (0);						\
23790f0869bcSRick Macklem 	} while (0)
23800f0869bcSRick Macklem 
23810f0869bcSRick Macklem /*
2382cc5efddeSRick Macklem  * Compare two struct expcred's.  Return 0 if the same and 1 otherwise.
23830f0869bcSRick Macklem  */
23840f0869bcSRick Macklem static int
compare_cred(struct expcred * cr0,struct expcred * cr1)2385cc5efddeSRick Macklem compare_cred(struct expcred *cr0, struct expcred *cr1)
23860f0869bcSRick Macklem {
23870f0869bcSRick Macklem 
23880f0869bcSRick Macklem 	if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups)
23890f0869bcSRick Macklem 		return (1);
23900f0869bcSRick Macklem 
23910f0869bcSRick Macklem 	COMPARE_ARRAYS(cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups);
23920f0869bcSRick Macklem }
23930f0869bcSRick Macklem 
23940f0869bcSRick Macklem /*
23950f0869bcSRick Macklem  * Compare two lists of security flavors.  Return 0 if the same and 1 otherwise.
23960f0869bcSRick Macklem  */
23970f0869bcSRick Macklem static int
compare_secflavor(int * sec1,int * sec2,int nsec)23980f0869bcSRick Macklem compare_secflavor(int *sec1, int *sec2, int nsec)
23990f0869bcSRick Macklem {
24000f0869bcSRick Macklem 
24010f0869bcSRick Macklem 	COMPARE_ARRAYS(sec1, sec2, nsec);
24020f0869bcSRick Macklem }
24030f0869bcSRick Macklem 
24040f0869bcSRick Macklem /*
24053e08dc74SRick Macklem  * Delete an exports entry.
24063e08dc74SRick Macklem  */
24073e08dc74SRick Macklem static void
delete_export(struct iovec * iov,int iovlen,struct statfs * fsp,char * errmsg)24083e08dc74SRick Macklem delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg)
24093e08dc74SRick Macklem {
24103e08dc74SRick Macklem 	struct xvfsconf vfc;
24113e08dc74SRick Macklem 
24123e08dc74SRick Macklem 	if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
24133e08dc74SRick Macklem 		syslog(LOG_ERR, "getvfsbyname() failed for %s",
24143e08dc74SRick Macklem 		    fsp->f_fstypename);
24153e08dc74SRick Macklem 		return;
24163e08dc74SRick Macklem 	}
24173e08dc74SRick Macklem 
24183e08dc74SRick Macklem 	/*
24193e08dc74SRick Macklem 	 * We do not need to delete "export" flag from
24203e08dc74SRick Macklem 	 * filesystems that do not have it set.
24213e08dc74SRick Macklem 	 */
24223e08dc74SRick Macklem 	if (!(fsp->f_flags & MNT_EXPORTED))
24233e08dc74SRick Macklem 		return;
24243e08dc74SRick Macklem 	/*
24253e08dc74SRick Macklem 	 * Do not delete export for network filesystem by
24263e08dc74SRick Macklem 	 * passing "export" arg to nmount().
24273e08dc74SRick Macklem 	 * It only makes sense to do this for local filesystems.
24283e08dc74SRick Macklem 	 */
24293e08dc74SRick Macklem 	if (vfc.vfc_flags & VFCF_NETWORK)
24303e08dc74SRick Macklem 		return;
24313e08dc74SRick Macklem 
24323e08dc74SRick Macklem 	iov[1].iov_base = fsp->f_fstypename;
24333e08dc74SRick Macklem 	iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
24343e08dc74SRick Macklem 	iov[3].iov_base = fsp->f_mntonname;
24353e08dc74SRick Macklem 	iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
24363e08dc74SRick Macklem 	iov[5].iov_base = fsp->f_mntfromname;
24373e08dc74SRick Macklem 	iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
24383e08dc74SRick Macklem 	errmsg[0] = '\0';
24393e08dc74SRick Macklem 
24403e08dc74SRick Macklem 	/*
24413e08dc74SRick Macklem 	 * EXDEV is returned when path exists but is not a
24423e08dc74SRick Macklem 	 * mount point.  May happens if raced with unmount.
24433e08dc74SRick Macklem 	 */
24443e08dc74SRick Macklem 	if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT &&
24453e08dc74SRick Macklem 	    errno != ENOTSUP && errno != EXDEV) {
24463e08dc74SRick Macklem 		syslog(LOG_ERR,
24473e08dc74SRick Macklem 		    "can't delete exports for %s: %m %s",
24483e08dc74SRick Macklem 		    fsp->f_mntonname, errmsg);
24493e08dc74SRick Macklem 	}
24503e08dc74SRick Macklem }
24513e08dc74SRick Macklem 
24523e08dc74SRick Macklem /*
24538fae3551SRodney W. Grimes  * Allocate an export list element
24548fae3551SRodney W. Grimes  */
245519c46d8cSEdward Tomasz Napierala static struct exportlist *
get_exp(void)2456a7a7d96cSPhilippe Charnier get_exp(void)
24578fae3551SRodney W. Grimes {
24588fae3551SRodney W. Grimes 	struct exportlist *ep;
24598fae3551SRodney W. Grimes 
246053750151SXin LI 	ep = (struct exportlist *)calloc(1, sizeof (struct exportlist));
24618fae3551SRodney W. Grimes 	if (ep == (struct exportlist *)NULL)
24628fae3551SRodney W. Grimes 		out_of_mem();
24638fae3551SRodney W. Grimes 	return (ep);
24648fae3551SRodney W. Grimes }
24658fae3551SRodney W. Grimes 
24668fae3551SRodney W. Grimes /*
24678fae3551SRodney W. Grimes  * Allocate a group list element
24688fae3551SRodney W. Grimes  */
246919c46d8cSEdward Tomasz Napierala static struct grouplist *
get_grp(void)2470a7a7d96cSPhilippe Charnier get_grp(void)
24718fae3551SRodney W. Grimes {
24728fae3551SRodney W. Grimes 	struct grouplist *gp;
24738fae3551SRodney W. Grimes 
247453750151SXin LI 	gp = (struct grouplist *)calloc(1, sizeof (struct grouplist));
24758fae3551SRodney W. Grimes 	if (gp == (struct grouplist *)NULL)
24768fae3551SRodney W. Grimes 		out_of_mem();
24778fae3551SRodney W. Grimes 	return (gp);
24788fae3551SRodney W. Grimes }
24798fae3551SRodney W. Grimes 
24808fae3551SRodney W. Grimes /*
24818fae3551SRodney W. Grimes  * Clean up upon an error in get_exportlist().
24828fae3551SRodney W. Grimes  */
248319c46d8cSEdward Tomasz Napierala static void
getexp_err(struct exportlist * ep,struct grouplist * grp,const char * reason)2484354fce28SConrad Meyer getexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason)
24858fae3551SRodney W. Grimes {
24868fae3551SRodney W. Grimes 	struct grouplist *tgrp;
24878fae3551SRodney W. Grimes 
2488354fce28SConrad Meyer 	if (!(opt_flags & OP_QUIET)) {
2489354fce28SConrad Meyer 		if (reason != NULL)
2490354fce28SConrad Meyer 			syslog(LOG_ERR, "bad exports list line '%s': %s", line,
2491354fce28SConrad Meyer 			    reason);
2492354fce28SConrad Meyer 		else
2493354fce28SConrad Meyer 			syslog(LOG_ERR, "bad exports list line '%s'", line);
2494354fce28SConrad Meyer 	}
24958fae3551SRodney W. Grimes 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
24968fae3551SRodney W. Grimes 		free_exp(ep);
24978fae3551SRodney W. Grimes 	while (grp) {
24988fae3551SRodney W. Grimes 		tgrp = grp;
24998fae3551SRodney W. Grimes 		grp = grp->gr_next;
25008fae3551SRodney W. Grimes 		free_grp(tgrp);
25018fae3551SRodney W. Grimes 	}
25028fae3551SRodney W. Grimes }
25038fae3551SRodney W. Grimes 
25048fae3551SRodney W. Grimes /*
25058fae3551SRodney W. Grimes  * Search the export list for a matching fs.
25068fae3551SRodney W. Grimes  */
250719c46d8cSEdward Tomasz Napierala static struct exportlist *
ex_search(fsid_t * fsid,struct exportlisthead * exhp)25081a9a992fSRick Macklem ex_search(fsid_t *fsid, struct exportlisthead *exhp)
25098fae3551SRodney W. Grimes {
25108fae3551SRodney W. Grimes 	struct exportlist *ep;
251146a6b5c4SRick Macklem 	uint32_t i;
25128fae3551SRodney W. Grimes 
251346a6b5c4SRick Macklem 	i = EXPHASH(fsid);
251446a6b5c4SRick Macklem 	SLIST_FOREACH(ep, &exhp[i], entries) {
2515245bfd34SRyan Moeller 		if (fsidcmp(&ep->ex_fs, fsid) == 0)
25168fae3551SRodney W. Grimes 			return (ep);
25178fae3551SRodney W. Grimes 	}
2518c9ac0f71SEmmanuel Vadot 
25198fae3551SRodney W. Grimes 	return (ep);
25208fae3551SRodney W. Grimes }
25218fae3551SRodney W. Grimes 
25228fae3551SRodney W. Grimes /*
25238fae3551SRodney W. Grimes  * Add a directory path to the list.
25248fae3551SRodney W. Grimes  */
252519c46d8cSEdward Tomasz Napierala static char *
add_expdir(struct dirlist ** dpp,char * cp,int len)2526a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len)
25278fae3551SRodney W. Grimes {
25288fae3551SRodney W. Grimes 	struct dirlist *dp;
25298fae3551SRodney W. Grimes 
253089b859e3SEmmanuel Vadot 	dp = malloc(sizeof (struct dirlist));
253174853402SPhilippe Charnier 	if (dp == (struct dirlist *)NULL)
253274853402SPhilippe Charnier 		out_of_mem();
25338fae3551SRodney W. Grimes 	dp->dp_left = *dpp;
25348fae3551SRodney W. Grimes 	dp->dp_right = (struct dirlist *)NULL;
25358fae3551SRodney W. Grimes 	dp->dp_flag = 0;
25368fae3551SRodney W. Grimes 	dp->dp_hosts = (struct hostlist *)NULL;
2537380a3fcdSEmmanuel Vadot 	dp->dp_dirp = strndup(cp, len);
2538380a3fcdSEmmanuel Vadot 	if (dp->dp_dirp == NULL)
2539380a3fcdSEmmanuel Vadot 		out_of_mem();
25408fae3551SRodney W. Grimes 	*dpp = dp;
25418fae3551SRodney W. Grimes 	return (dp->dp_dirp);
25428fae3551SRodney W. Grimes }
25438fae3551SRodney W. Grimes 
25448fae3551SRodney W. Grimes /*
25458fae3551SRodney W. Grimes  * Hang the dir list element off the dirpath binary tree as required
25468fae3551SRodney W. Grimes  * and update the entry for host.
25478fae3551SRodney W. Grimes  */
254819c46d8cSEdward Tomasz Napierala static void
hang_dirp(struct dirlist * dp,struct grouplist * grp,struct exportlist * ep,int flags,struct expcred * anoncrp,uint64_t exflags)2549a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep,
2550cc5efddeSRick Macklem 	int flags, struct expcred *anoncrp, uint64_t exflags)
25518fae3551SRodney W. Grimes {
25528fae3551SRodney W. Grimes 	struct hostlist *hp;
25538fae3551SRodney W. Grimes 	struct dirlist *dp2;
25548fae3551SRodney W. Grimes 
2555a62dc406SDoug Rabson 	if (flags & OP_ALLDIRS) {
25568fae3551SRodney W. Grimes 		if (ep->ex_defdir)
25578fae3551SRodney W. Grimes 			free((caddr_t)dp);
25588fae3551SRodney W. Grimes 		else
25598fae3551SRodney W. Grimes 			ep->ex_defdir = dp;
2560a62dc406SDoug Rabson 		if (grp == (struct grouplist *)NULL) {
25610f0869bcSRick Macklem 			ep->ex_flag |= EX_DEFSET;
25628fae3551SRodney W. Grimes 			ep->ex_defdir->dp_flag |= DP_DEFSET;
2563c3f86a25SRick Macklem 			/* Save the default security flavors list. */
2564c3f86a25SRick Macklem 			ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2565c3f86a25SRick Macklem 			if (ep->ex_numsecflavors > 0)
2566c3f86a25SRick Macklem 				memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2567c3f86a25SRick Macklem 				    sizeof(ep->ex_secflavors));
2568cc5efddeSRick Macklem 			cp_cred(&ep->ex_defanon, anoncrp);
25690f0869bcSRick Macklem 			ep->ex_defexflags = exflags;
2570a62dc406SDoug Rabson 		} else while (grp) {
25718fae3551SRodney W. Grimes 			hp = get_ht();
25728fae3551SRodney W. Grimes 			hp->ht_grp = grp;
25738fae3551SRodney W. Grimes 			hp->ht_next = ep->ex_defdir->dp_hosts;
25748fae3551SRodney W. Grimes 			ep->ex_defdir->dp_hosts = hp;
2575c3f86a25SRick Macklem 			/* Save the security flavors list for this host set. */
2576c3f86a25SRick Macklem 			grp->gr_numsecflavors = ep->ex_numsecflavors;
2577c3f86a25SRick Macklem 			if (ep->ex_numsecflavors > 0)
2578c3f86a25SRick Macklem 				memcpy(grp->gr_secflavors, ep->ex_secflavors,
2579c3f86a25SRick Macklem 				    sizeof(ep->ex_secflavors));
25808fae3551SRodney W. Grimes 			grp = grp->gr_next;
25818fae3551SRodney W. Grimes 		}
25828fae3551SRodney W. Grimes 	} else {
25838fae3551SRodney W. Grimes 
25848fae3551SRodney W. Grimes 		/*
258574853402SPhilippe Charnier 		 * Loop through the directories adding them to the tree.
25868fae3551SRodney W. Grimes 		 */
25878fae3551SRodney W. Grimes 		while (dp) {
25888fae3551SRodney W. Grimes 			dp2 = dp->dp_left;
25890f0869bcSRick Macklem 			add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp,
25900f0869bcSRick Macklem 			    exflags);
25918fae3551SRodney W. Grimes 			dp = dp2;
25928fae3551SRodney W. Grimes 		}
25938fae3551SRodney W. Grimes 	}
25948fae3551SRodney W. Grimes }
25958fae3551SRodney W. Grimes 
25968fae3551SRodney W. Grimes /*
25978fae3551SRodney W. Grimes  * Traverse the binary tree either updating a node that is already there
25988fae3551SRodney W. Grimes  * for the new directory or adding the new node.
25998fae3551SRodney W. Grimes  */
260019c46d8cSEdward Tomasz Napierala static void
add_dlist(struct dirlist ** dpp,struct dirlist * newdp,struct grouplist * grp,int flags,struct exportlist * ep,struct expcred * anoncrp,uint64_t exflags)2601a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp,
2602cc5efddeSRick Macklem 	int flags, struct exportlist *ep, struct expcred *anoncrp,
2603cc5efddeSRick Macklem 	uint64_t exflags)
26048fae3551SRodney W. Grimes {
26058fae3551SRodney W. Grimes 	struct dirlist *dp;
26068fae3551SRodney W. Grimes 	struct hostlist *hp;
26078fae3551SRodney W. Grimes 	int cmp;
26088fae3551SRodney W. Grimes 
26098fae3551SRodney W. Grimes 	dp = *dpp;
26108fae3551SRodney W. Grimes 	if (dp) {
26118fae3551SRodney W. Grimes 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
26128fae3551SRodney W. Grimes 		if (cmp > 0) {
26130f0869bcSRick Macklem 			add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp,
26140f0869bcSRick Macklem 			    exflags);
26158fae3551SRodney W. Grimes 			return;
26168fae3551SRodney W. Grimes 		} else if (cmp < 0) {
26170f0869bcSRick Macklem 			add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp,
26180f0869bcSRick Macklem 			    exflags);
26198fae3551SRodney W. Grimes 			return;
26208fae3551SRodney W. Grimes 		} else
26218fae3551SRodney W. Grimes 			free((caddr_t)newdp);
26228fae3551SRodney W. Grimes 	} else {
26238fae3551SRodney W. Grimes 		dp = newdp;
26248fae3551SRodney W. Grimes 		dp->dp_left = (struct dirlist *)NULL;
26258fae3551SRodney W. Grimes 		*dpp = dp;
26268fae3551SRodney W. Grimes 	}
26278fae3551SRodney W. Grimes 	if (grp) {
26288fae3551SRodney W. Grimes 
26298fae3551SRodney W. Grimes 		/*
26308fae3551SRodney W. Grimes 		 * Hang all of the host(s) off of the directory point.
26318fae3551SRodney W. Grimes 		 */
26328fae3551SRodney W. Grimes 		do {
26338fae3551SRodney W. Grimes 			hp = get_ht();
26348fae3551SRodney W. Grimes 			hp->ht_grp = grp;
26358fae3551SRodney W. Grimes 			hp->ht_next = dp->dp_hosts;
26368fae3551SRodney W. Grimes 			dp->dp_hosts = hp;
2637c3f86a25SRick Macklem 			/* Save the security flavors list for this host set. */
2638c3f86a25SRick Macklem 			grp->gr_numsecflavors = ep->ex_numsecflavors;
2639c3f86a25SRick Macklem 			if (ep->ex_numsecflavors > 0)
2640c3f86a25SRick Macklem 				memcpy(grp->gr_secflavors, ep->ex_secflavors,
2641c3f86a25SRick Macklem 				    sizeof(ep->ex_secflavors));
26428fae3551SRodney W. Grimes 			grp = grp->gr_next;
26438fae3551SRodney W. Grimes 		} while (grp);
2644a62dc406SDoug Rabson 	} else {
26450f0869bcSRick Macklem 		ep->ex_flag |= EX_DEFSET;
26468fae3551SRodney W. Grimes 		dp->dp_flag |= DP_DEFSET;
2647c3f86a25SRick Macklem 		/* Save the default security flavors list. */
2648c3f86a25SRick Macklem 		ep->ex_defnumsecflavors = ep->ex_numsecflavors;
2649c3f86a25SRick Macklem 		if (ep->ex_numsecflavors > 0)
2650c3f86a25SRick Macklem 			memcpy(ep->ex_defsecflavors, ep->ex_secflavors,
2651c3f86a25SRick Macklem 			    sizeof(ep->ex_secflavors));
2652cc5efddeSRick Macklem 		cp_cred(&ep->ex_defanon, anoncrp);
26530f0869bcSRick Macklem 		ep->ex_defexflags = exflags;
2654a62dc406SDoug Rabson 	}
26558fae3551SRodney W. Grimes }
26568fae3551SRodney W. Grimes 
26578fae3551SRodney W. Grimes /*
26588fae3551SRodney W. Grimes  * Search for a dirpath on the export point.
26598fae3551SRodney W. Grimes  */
266019c46d8cSEdward Tomasz Napierala static struct dirlist *
dirp_search(struct dirlist * dp,char * dirp)2661a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp)
26628fae3551SRodney W. Grimes {
26638fae3551SRodney W. Grimes 	int cmp;
26648fae3551SRodney W. Grimes 
26658fae3551SRodney W. Grimes 	if (dp) {
26668360efbdSAlfred Perlstein 		cmp = strcmp(dp->dp_dirp, dirp);
26678fae3551SRodney W. Grimes 		if (cmp > 0)
26688360efbdSAlfred Perlstein 			return (dirp_search(dp->dp_left, dirp));
26698fae3551SRodney W. Grimes 		else if (cmp < 0)
26708360efbdSAlfred Perlstein 			return (dirp_search(dp->dp_right, dirp));
26718fae3551SRodney W. Grimes 		else
26728fae3551SRodney W. Grimes 			return (dp);
26738fae3551SRodney W. Grimes 	}
26748fae3551SRodney W. Grimes 	return (dp);
26758fae3551SRodney W. Grimes }
26768fae3551SRodney W. Grimes 
26778fae3551SRodney W. Grimes /*
26788fae3551SRodney W. Grimes  * Scan for a host match in a directory tree.
26798fae3551SRodney W. Grimes  */
268019c46d8cSEdward Tomasz Napierala static int
chk_host(struct dirlist * dp,struct sockaddr * saddr,int * defsetp,int * hostsetp,int * numsecflavors,int ** secflavorsp)2681a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp,
2682c3f86a25SRick Macklem 	int *hostsetp, int *numsecflavors, int **secflavorsp)
26838fae3551SRodney W. Grimes {
26848fae3551SRodney W. Grimes 	struct hostlist *hp;
26858fae3551SRodney W. Grimes 	struct grouplist *grp;
26868360efbdSAlfred Perlstein 	struct addrinfo *ai;
26878fae3551SRodney W. Grimes 
26888fae3551SRodney W. Grimes 	if (dp) {
26898fae3551SRodney W. Grimes 		if (dp->dp_flag & DP_DEFSET)
2690a62dc406SDoug Rabson 			*defsetp = dp->dp_flag;
26918fae3551SRodney W. Grimes 		hp = dp->dp_hosts;
26928fae3551SRodney W. Grimes 		while (hp) {
26938fae3551SRodney W. Grimes 			grp = hp->ht_grp;
26948fae3551SRodney W. Grimes 			switch (grp->gr_type) {
26958fae3551SRodney W. Grimes 			case GT_HOST:
26968360efbdSAlfred Perlstein 				ai = grp->gr_ptr.gt_addrinfo;
26978360efbdSAlfred Perlstein 				for (; ai; ai = ai->ai_next) {
269860caaee2SIan Dowse 					if (!sacmp(ai->ai_addr, saddr, NULL)) {
26998360efbdSAlfred Perlstein 						*hostsetp =
27008360efbdSAlfred Perlstein 						    (hp->ht_flag | DP_HOSTSET);
2701c3f86a25SRick Macklem 						if (numsecflavors != NULL) {
2702c3f86a25SRick Macklem 							*numsecflavors =
2703c3f86a25SRick Macklem 							    grp->gr_numsecflavors;
2704c3f86a25SRick Macklem 							*secflavorsp =
2705c3f86a25SRick Macklem 							    grp->gr_secflavors;
2706c3f86a25SRick Macklem 						}
27078fae3551SRodney W. Grimes 						return (1);
2708a62dc406SDoug Rabson 					}
27098fae3551SRodney W. Grimes 				}
27108fae3551SRodney W. Grimes 				break;
27118fae3551SRodney W. Grimes 			case GT_NET:
271260caaee2SIan Dowse 				if (!sacmp(saddr, (struct sockaddr *)
271360caaee2SIan Dowse 				    &grp->gr_ptr.gt_net.nt_net,
271460caaee2SIan Dowse 				    (struct sockaddr *)
271560caaee2SIan Dowse 				    &grp->gr_ptr.gt_net.nt_mask)) {
2716a62dc406SDoug Rabson 					*hostsetp = (hp->ht_flag | DP_HOSTSET);
2717c3f86a25SRick Macklem 					if (numsecflavors != NULL) {
2718c3f86a25SRick Macklem 						*numsecflavors =
2719c3f86a25SRick Macklem 						    grp->gr_numsecflavors;
2720c3f86a25SRick Macklem 						*secflavorsp =
2721c3f86a25SRick Macklem 						    grp->gr_secflavors;
2722c3f86a25SRick Macklem 					}
27238fae3551SRodney W. Grimes 					return (1);
2724a62dc406SDoug Rabson 				}
27258fae3551SRodney W. Grimes 				break;
272660caaee2SIan Dowse 			}
27278fae3551SRodney W. Grimes 			hp = hp->ht_next;
27288fae3551SRodney W. Grimes 		}
27298fae3551SRodney W. Grimes 	}
27308fae3551SRodney W. Grimes 	return (0);
27318fae3551SRodney W. Grimes }
27328fae3551SRodney W. Grimes 
27338fae3551SRodney W. Grimes /*
27348fae3551SRodney W. Grimes  * Scan tree for a host that matches the address.
27358fae3551SRodney W. Grimes  */
273619c46d8cSEdward Tomasz Napierala static int
scan_tree(struct dirlist * dp,struct sockaddr * saddr)2737a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr)
27388fae3551SRodney W. Grimes {
2739a62dc406SDoug Rabson 	int defset, hostset;
27408fae3551SRodney W. Grimes 
27418fae3551SRodney W. Grimes 	if (dp) {
27428fae3551SRodney W. Grimes 		if (scan_tree(dp->dp_left, saddr))
27438fae3551SRodney W. Grimes 			return (1);
2744c3f86a25SRick Macklem 		if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL))
27458fae3551SRodney W. Grimes 			return (1);
27468fae3551SRodney W. Grimes 		if (scan_tree(dp->dp_right, saddr))
27478fae3551SRodney W. Grimes 			return (1);
27488fae3551SRodney W. Grimes 	}
27498fae3551SRodney W. Grimes 	return (0);
27508fae3551SRodney W. Grimes }
27518fae3551SRodney W. Grimes 
27528fae3551SRodney W. Grimes /*
27538fae3551SRodney W. Grimes  * Traverse the dirlist tree and free it up.
27548fae3551SRodney W. Grimes  */
275519c46d8cSEdward Tomasz Napierala static void
free_dir(struct dirlist * dp)2756a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp)
27578fae3551SRodney W. Grimes {
27588fae3551SRodney W. Grimes 
27598fae3551SRodney W. Grimes 	if (dp) {
27608fae3551SRodney W. Grimes 		free_dir(dp->dp_left);
27618fae3551SRodney W. Grimes 		free_dir(dp->dp_right);
27628fae3551SRodney W. Grimes 		free_host(dp->dp_hosts);
276392e73cccSEmmanuel Vadot 		free(dp->dp_dirp);
276492e73cccSEmmanuel Vadot 		free(dp);
27658fae3551SRodney W. Grimes 	}
27668fae3551SRodney W. Grimes }
27678fae3551SRodney W. Grimes 
27688fae3551SRodney W. Grimes /*
2769a9148abdSDoug Rabson  * Parse a colon separated list of security flavors
2770a9148abdSDoug Rabson  */
277119c46d8cSEdward Tomasz Napierala static int
parsesec(char * seclist,struct exportlist * ep)2772a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep)
2773a9148abdSDoug Rabson {
2774a9148abdSDoug Rabson 	char *cp, savedc;
2775a9148abdSDoug Rabson 	int flavor;
2776a9148abdSDoug Rabson 
2777a9148abdSDoug Rabson 	ep->ex_numsecflavors = 0;
2778a9148abdSDoug Rabson 	for (;;) {
2779a9148abdSDoug Rabson 		cp = strchr(seclist, ':');
2780a9148abdSDoug Rabson 		if (cp) {
2781a9148abdSDoug Rabson 			savedc = *cp;
2782a9148abdSDoug Rabson 			*cp = '\0';
2783a9148abdSDoug Rabson 		}
2784a9148abdSDoug Rabson 
2785a9148abdSDoug Rabson 		if (!strcmp(seclist, "sys"))
2786a9148abdSDoug Rabson 			flavor = AUTH_SYS;
2787a9148abdSDoug Rabson 		else if (!strcmp(seclist, "krb5"))
2788a9148abdSDoug Rabson 			flavor = RPCSEC_GSS_KRB5;
2789a9148abdSDoug Rabson 		else if (!strcmp(seclist, "krb5i"))
2790a9148abdSDoug Rabson 			flavor = RPCSEC_GSS_KRB5I;
2791a9148abdSDoug Rabson 		else if (!strcmp(seclist, "krb5p"))
2792a9148abdSDoug Rabson 			flavor = RPCSEC_GSS_KRB5P;
2793a9148abdSDoug Rabson 		else {
2794a9148abdSDoug Rabson 			if (cp)
2795a9148abdSDoug Rabson 				*cp = savedc;
2796a9148abdSDoug Rabson 			syslog(LOG_ERR, "bad sec flavor: %s", seclist);
2797a9148abdSDoug Rabson 			return (1);
2798a9148abdSDoug Rabson 		}
2799a9148abdSDoug Rabson 		if (ep->ex_numsecflavors == MAXSECFLAVORS) {
2800a9148abdSDoug Rabson 			if (cp)
2801a9148abdSDoug Rabson 				*cp = savedc;
2802a9148abdSDoug Rabson 			syslog(LOG_ERR, "too many sec flavors: %s", seclist);
2803a9148abdSDoug Rabson 			return (1);
2804a9148abdSDoug Rabson 		}
2805a9148abdSDoug Rabson 		ep->ex_secflavors[ep->ex_numsecflavors] = flavor;
2806a9148abdSDoug Rabson 		ep->ex_numsecflavors++;
2807a9148abdSDoug Rabson 		if (cp) {
2808a9148abdSDoug Rabson 			*cp = savedc;
2809a9148abdSDoug Rabson 			seclist = cp + 1;
2810a9148abdSDoug Rabson 		} else {
2811a9148abdSDoug Rabson 			break;
2812a9148abdSDoug Rabson 		}
2813a9148abdSDoug Rabson 	}
2814a9148abdSDoug Rabson 	return (0);
2815a9148abdSDoug Rabson }
2816a9148abdSDoug Rabson 
2817a9148abdSDoug Rabson /*
28188fae3551SRodney W. Grimes  * Parse the option string and update fields.
28198fae3551SRodney W. Grimes  * Option arguments may either be -<option>=<value> or
28208fae3551SRodney W. Grimes  * -<option> <value>
28218fae3551SRodney W. Grimes  */
282219c46d8cSEdward Tomasz Napierala static int
do_opt(char ** cpp,char ** endcpp,struct exportlist * ep,struct grouplist * grp,int * has_hostp,uint64_t * exflagsp,struct expcred * cr)2823a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp,
2824cc5efddeSRick Macklem 	int *has_hostp, uint64_t *exflagsp, struct expcred *cr)
28258fae3551SRodney W. Grimes {
28268fae3551SRodney W. Grimes 	char *cpoptarg, *cpoptend;
28278fae3551SRodney W. Grimes 	char *cp, *endcp, *cpopt, savedc, savedc2;
2828*3df987c9SRick Macklem 	int allflag, usedarg, fnd_equal;
28298fae3551SRodney W. Grimes 
2830cb479b11SAlfred Perlstein 	savedc2 = '\0';
28318fae3551SRodney W. Grimes 	cpopt = *cpp;
28328fae3551SRodney W. Grimes 	cpopt++;
28338fae3551SRodney W. Grimes 	cp = *endcpp;
28348fae3551SRodney W. Grimes 	savedc = *cp;
28358fae3551SRodney W. Grimes 	*cp = '\0';
28368fae3551SRodney W. Grimes 	while (cpopt && *cpopt) {
28378fae3551SRodney W. Grimes 		allflag = 1;
28388fae3551SRodney W. Grimes 		usedarg = -2;
2839*3df987c9SRick Macklem 		fnd_equal = 0;
284074853402SPhilippe Charnier 		if ((cpoptend = strchr(cpopt, ','))) {
28418fae3551SRodney W. Grimes 			*cpoptend++ = '\0';
2842*3df987c9SRick Macklem 			if ((cpoptarg = strchr(cpopt, '='))) {
28438fae3551SRodney W. Grimes 				*cpoptarg++ = '\0';
2844*3df987c9SRick Macklem 				fnd_equal = 1;
2845*3df987c9SRick Macklem 			}
28468fae3551SRodney W. Grimes 		} else {
2847*3df987c9SRick Macklem 			if ((cpoptarg = strchr(cpopt, '='))) {
28488fae3551SRodney W. Grimes 				*cpoptarg++ = '\0';
2849*3df987c9SRick Macklem 				fnd_equal = 1;
2850*3df987c9SRick Macklem 			} else {
28518fae3551SRodney W. Grimes 				*cp = savedc;
28528fae3551SRodney W. Grimes 				nextfield(&cp, &endcp);
28538fae3551SRodney W. Grimes 				**endcpp = '\0';
28548fae3551SRodney W. Grimes 				if (endcp > cp && *cp != '-') {
28558fae3551SRodney W. Grimes 					cpoptarg = cp;
28568fae3551SRodney W. Grimes 					savedc2 = *endcp;
28578fae3551SRodney W. Grimes 					*endcp = '\0';
28588fae3551SRodney W. Grimes 					usedarg = 0;
28598fae3551SRodney W. Grimes 				}
28608fae3551SRodney W. Grimes 			}
28618fae3551SRodney W. Grimes 		}
28628fae3551SRodney W. Grimes 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
2863*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2864*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2865*3df987c9SRick Macklem 				return (1);
2866*3df987c9SRick Macklem 			}
28678fae3551SRodney W. Grimes 			*exflagsp |= MNT_EXRDONLY;
28688fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
28698fae3551SRodney W. Grimes 		    !(allflag = strcmp(cpopt, "mapall")) ||
28708fae3551SRodney W. Grimes 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
28718fae3551SRodney W. Grimes 			usedarg++;
28728fae3551SRodney W. Grimes 			parsecred(cpoptarg, cr);
28738fae3551SRodney W. Grimes 			if (allflag == 0) {
28748fae3551SRodney W. Grimes 				*exflagsp |= MNT_EXPORTANON;
28758fae3551SRodney W. Grimes 				opt_flags |= OP_MAPALL;
28768fae3551SRodney W. Grimes 			} else
28778fae3551SRodney W. Grimes 				opt_flags |= OP_MAPROOT;
28788fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
28798fae3551SRodney W. Grimes 		    !strcmp(cpopt, "m"))) {
28808fae3551SRodney W. Grimes 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
288174853402SPhilippe Charnier 				syslog(LOG_ERR, "bad mask: %s", cpoptarg);
28828fae3551SRodney W. Grimes 				return (1);
28838fae3551SRodney W. Grimes 			}
28848fae3551SRodney W. Grimes 			usedarg++;
28858fae3551SRodney W. Grimes 			opt_flags |= OP_MASK;
28868fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
28878fae3551SRodney W. Grimes 			!strcmp(cpopt, "n"))) {
28888360efbdSAlfred Perlstein 			if (strchr(cpoptarg, '/') != NULL) {
28898360efbdSAlfred Perlstein 				if (debug)
28908360efbdSAlfred Perlstein 					fprintf(stderr, "setting OP_MASKLEN\n");
28918360efbdSAlfred Perlstein 				opt_flags |= OP_MASKLEN;
28928360efbdSAlfred Perlstein 			}
28938fae3551SRodney W. Grimes 			if (grp->gr_type != GT_NULL) {
289474853402SPhilippe Charnier 				syslog(LOG_ERR, "network/host conflict");
28958fae3551SRodney W. Grimes 				return (1);
28968fae3551SRodney W. Grimes 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
289774853402SPhilippe Charnier 				syslog(LOG_ERR, "bad net: %s", cpoptarg);
28988fae3551SRodney W. Grimes 				return (1);
28998fae3551SRodney W. Grimes 			}
29008fae3551SRodney W. Grimes 			grp->gr_type = GT_NET;
29018fae3551SRodney W. Grimes 			*has_hostp = 1;
29028fae3551SRodney W. Grimes 			usedarg++;
29038fae3551SRodney W. Grimes 			opt_flags |= OP_NET;
29048fae3551SRodney W. Grimes 		} else if (!strcmp(cpopt, "alldirs")) {
2905*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2906*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2907*3df987c9SRick Macklem 				return (1);
2908*3df987c9SRick Macklem 			}
29098fae3551SRodney W. Grimes 			opt_flags |= OP_ALLDIRS;
2910cb3923e0SDoug Rabson 		} else if (!strcmp(cpopt, "public")) {
2911*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2912*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2913*3df987c9SRick Macklem 				return (1);
2914*3df987c9SRick Macklem 			}
2915cb3923e0SDoug Rabson 			*exflagsp |= MNT_EXPUBLIC;
2916cb3923e0SDoug Rabson 		} else if (!strcmp(cpopt, "webnfs")) {
2917*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2918*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2919*3df987c9SRick Macklem 				return (1);
2920*3df987c9SRick Macklem 			}
2921cb3923e0SDoug Rabson 			*exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
2922cb3923e0SDoug Rabson 			opt_flags |= OP_MAPALL;
2923cb3923e0SDoug Rabson 		} else if (cpoptarg && !strcmp(cpopt, "index")) {
2924cb3923e0SDoug Rabson 			ep->ex_indexfile = strdup(cpoptarg);
2925288fa14aSJoerg Wunsch 		} else if (!strcmp(cpopt, "quiet")) {
2926*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2927*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2928*3df987c9SRick Macklem 				return (1);
2929*3df987c9SRick Macklem 			}
2930288fa14aSJoerg Wunsch 			opt_flags |= OP_QUIET;
2931dcdc127bSSergey Kandaurov 		} else if (cpoptarg && !strcmp(cpopt, "sec")) {
2932a9148abdSDoug Rabson 			if (parsesec(cpoptarg, ep))
2933a9148abdSDoug Rabson 				return (1);
2934a9148abdSDoug Rabson 			opt_flags |= OP_SEC;
2935a9148abdSDoug Rabson 			usedarg++;
2936813837baSRick Macklem 		} else if (!strcmp(cpopt, "tls")) {
2937*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2938*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2939*3df987c9SRick Macklem 				return (1);
2940*3df987c9SRick Macklem 			}
2941813837baSRick Macklem 			*exflagsp |= MNT_EXTLS;
2942813837baSRick Macklem 		} else if (!strcmp(cpopt, "tlscert")) {
2943*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2944*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2945*3df987c9SRick Macklem 				return (1);
2946*3df987c9SRick Macklem 			}
2947813837baSRick Macklem 			*exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT);
2948813837baSRick Macklem 		} else if (!strcmp(cpopt, "tlscertuser")) {
2949*3df987c9SRick Macklem 			if (fnd_equal == 1) {
2950*3df987c9SRick Macklem 				syslog(LOG_ERR, "= after op: %s", cpopt);
2951*3df987c9SRick Macklem 				return (1);
2952*3df987c9SRick Macklem 			}
2953813837baSRick Macklem 			*exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT |
2954813837baSRick Macklem 			    MNT_EXTLSCERTUSER);
29558fae3551SRodney W. Grimes 		} else {
295674853402SPhilippe Charnier 			syslog(LOG_ERR, "bad opt %s", cpopt);
29578fae3551SRodney W. Grimes 			return (1);
29588fae3551SRodney W. Grimes 		}
29598fae3551SRodney W. Grimes 		if (usedarg >= 0) {
29608fae3551SRodney W. Grimes 			*endcp = savedc2;
29618fae3551SRodney W. Grimes 			**endcpp = savedc;
29628fae3551SRodney W. Grimes 			if (usedarg > 0) {
29638fae3551SRodney W. Grimes 				*cpp = cp;
29648fae3551SRodney W. Grimes 				*endcpp = endcp;
29658fae3551SRodney W. Grimes 			}
29668fae3551SRodney W. Grimes 			return (0);
29678fae3551SRodney W. Grimes 		}
29688fae3551SRodney W. Grimes 		cpopt = cpoptend;
29698fae3551SRodney W. Grimes 	}
29708fae3551SRodney W. Grimes 	**endcpp = savedc;
29718fae3551SRodney W. Grimes 	return (0);
29728fae3551SRodney W. Grimes }
29738fae3551SRodney W. Grimes 
29748fae3551SRodney W. Grimes /*
29758fae3551SRodney W. Grimes  * Translate a character string to the corresponding list of network
29768fae3551SRodney W. Grimes  * addresses for a hostname.
29778fae3551SRodney W. Grimes  */
297819c46d8cSEdward Tomasz Napierala static int
get_host(char * cp,struct grouplist * grp,struct grouplist * tgrp)2979a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp)
29808fae3551SRodney W. Grimes {
29818b5a6d67SBill Paul 	struct grouplist *checkgrp;
298201709abfSIan Dowse 	struct addrinfo *ai, *tai, hints;
29838360efbdSAlfred Perlstein 	int ecode;
29848360efbdSAlfred Perlstein 	char host[NI_MAXHOST];
29858fae3551SRodney W. Grimes 
29868360efbdSAlfred Perlstein 	if (grp->gr_type != GT_NULL) {
29878360efbdSAlfred Perlstein 		syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
29888fae3551SRodney W. Grimes 		return (1);
29898fae3551SRodney W. Grimes 	}
29908360efbdSAlfred Perlstein 	memset(&hints, 0, sizeof hints);
29918360efbdSAlfred Perlstein 	hints.ai_flags = AI_CANONNAME;
29928360efbdSAlfred Perlstein 	hints.ai_protocol = IPPROTO_UDP;
29938360efbdSAlfred Perlstein 	ecode = getaddrinfo(cp, NULL, &hints, &ai);
29948360efbdSAlfred Perlstein 	if (ecode != 0) {
299501709abfSIan Dowse 		syslog(LOG_ERR,"can't get address info for host %s", cp);
29968360efbdSAlfred Perlstein 		return 1;
29978fae3551SRodney W. Grimes 	}
29988360efbdSAlfred Perlstein 	grp->gr_ptr.gt_addrinfo = ai;
29998360efbdSAlfred Perlstein 	while (ai != NULL) {
30008360efbdSAlfred Perlstein 		if (ai->ai_canonname == NULL) {
30018360efbdSAlfred Perlstein 			if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
30024f101318SHajimu UMEMOTO 			    sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
30038360efbdSAlfred Perlstein 				strlcpy(host, "?", sizeof(host));
30048360efbdSAlfred Perlstein 			ai->ai_canonname = strdup(host);
30058360efbdSAlfred Perlstein 			ai->ai_flags |= AI_CANONNAME;
30066d359f31SIan Dowse 		}
30078fae3551SRodney W. Grimes 		if (debug)
300801709abfSIan Dowse 			fprintf(stderr, "got host %s\n", ai->ai_canonname);
300901709abfSIan Dowse 		/*
301001709abfSIan Dowse 		 * Sanity check: make sure we don't already have an entry
301101709abfSIan Dowse 		 * for this host in the grouplist.
301201709abfSIan Dowse 		 */
301301709abfSIan Dowse 		for (checkgrp = tgrp; checkgrp != NULL;
301401709abfSIan Dowse 		    checkgrp = checkgrp->gr_next) {
301501709abfSIan Dowse 			if (checkgrp->gr_type != GT_HOST)
301601709abfSIan Dowse 				continue;
301701709abfSIan Dowse 			for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
301801709abfSIan Dowse 			    tai = tai->ai_next) {
301960caaee2SIan Dowse 				if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
302001709abfSIan Dowse 					continue;
302101709abfSIan Dowse 				if (debug)
302201709abfSIan Dowse 					fprintf(stderr,
302301709abfSIan Dowse 					    "ignoring duplicate host %s\n",
302401709abfSIan Dowse 					    ai->ai_canonname);
302501709abfSIan Dowse 				grp->gr_type = GT_IGNORE;
302601709abfSIan Dowse 				return (0);
302701709abfSIan Dowse 			}
302801709abfSIan Dowse 		}
30298360efbdSAlfred Perlstein 		ai = ai->ai_next;
30308360efbdSAlfred Perlstein 	}
303101709abfSIan Dowse 	grp->gr_type = GT_HOST;
30328fae3551SRodney W. Grimes 	return (0);
30338fae3551SRodney W. Grimes }
30348fae3551SRodney W. Grimes 
30358fae3551SRodney W. Grimes /*
30368fae3551SRodney W. Grimes  * Free up an exports list component
30378fae3551SRodney W. Grimes  */
303819c46d8cSEdward Tomasz Napierala static void
free_exp(struct exportlist * ep)3039a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep)
30408fae3551SRodney W. Grimes {
3041711d44eeSRick Macklem 	struct grouplist *grp, *tgrp;
30428fae3551SRodney W. Grimes 
30438fae3551SRodney W. Grimes 	if (ep->ex_defdir) {
30448fae3551SRodney W. Grimes 		free_host(ep->ex_defdir->dp_hosts);
30458fae3551SRodney W. Grimes 		free((caddr_t)ep->ex_defdir);
30468fae3551SRodney W. Grimes 	}
30478fae3551SRodney W. Grimes 	if (ep->ex_fsdir)
30488fae3551SRodney W. Grimes 		free(ep->ex_fsdir);
3049cb3923e0SDoug Rabson 	if (ep->ex_indexfile)
3050cb3923e0SDoug Rabson 		free(ep->ex_indexfile);
30518fae3551SRodney W. Grimes 	free_dir(ep->ex_dirl);
3052711d44eeSRick Macklem 	grp = ep->ex_grphead;
3053711d44eeSRick Macklem 	while (grp) {
3054711d44eeSRick Macklem 		tgrp = grp;
3055711d44eeSRick Macklem 		grp = grp->gr_next;
3056711d44eeSRick Macklem 		free_grp(tgrp);
3057711d44eeSRick Macklem 	}
30582ffad162SRick Macklem 	if (ep->ex_defanon.cr_groups != ep->ex_defanon.cr_smallgrps)
30592ffad162SRick Macklem 		free(ep->ex_defanon.cr_groups);
30608fae3551SRodney W. Grimes 	free((caddr_t)ep);
30618fae3551SRodney W. Grimes }
30628fae3551SRodney W. Grimes 
30638fae3551SRodney W. Grimes /*
30640f0869bcSRick Macklem  * Free up the v4root exports.
30650f0869bcSRick Macklem  */
30660f0869bcSRick Macklem static void
free_v4rootexp(void)30670f0869bcSRick Macklem free_v4rootexp(void)
30680f0869bcSRick Macklem {
30690f0869bcSRick Macklem 
30700f0869bcSRick Macklem 	if (v4root_ep != NULL) {
30710f0869bcSRick Macklem 		free_exp(v4root_ep);
30720f0869bcSRick Macklem 		v4root_ep = NULL;
30730f0869bcSRick Macklem 	}
30740f0869bcSRick Macklem }
30750f0869bcSRick Macklem 
30760f0869bcSRick Macklem /*
30778fae3551SRodney W. Grimes  * Free hosts.
30788fae3551SRodney W. Grimes  */
307919c46d8cSEdward Tomasz Napierala static void
free_host(struct hostlist * hp)3080a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp)
30818fae3551SRodney W. Grimes {
30828fae3551SRodney W. Grimes 	struct hostlist *hp2;
30838fae3551SRodney W. Grimes 
30848fae3551SRodney W. Grimes 	while (hp) {
30858fae3551SRodney W. Grimes 		hp2 = hp;
30868fae3551SRodney W. Grimes 		hp = hp->ht_next;
30878fae3551SRodney W. Grimes 		free((caddr_t)hp2);
30888fae3551SRodney W. Grimes 	}
30898fae3551SRodney W. Grimes }
30908fae3551SRodney W. Grimes 
309119c46d8cSEdward Tomasz Napierala static struct hostlist *
get_ht(void)3092a7a7d96cSPhilippe Charnier get_ht(void)
30938fae3551SRodney W. Grimes {
30948fae3551SRodney W. Grimes 	struct hostlist *hp;
30958fae3551SRodney W. Grimes 
30968fae3551SRodney W. Grimes 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
30978fae3551SRodney W. Grimes 	if (hp == (struct hostlist *)NULL)
30988fae3551SRodney W. Grimes 		out_of_mem();
30998fae3551SRodney W. Grimes 	hp->ht_next = (struct hostlist *)NULL;
3100a62dc406SDoug Rabson 	hp->ht_flag = 0;
31018fae3551SRodney W. Grimes 	return (hp);
31028fae3551SRodney W. Grimes }
31038fae3551SRodney W. Grimes 
31048fae3551SRodney W. Grimes /*
31058fae3551SRodney W. Grimes  * Out of memory, fatal
31068fae3551SRodney W. Grimes  */
310719c46d8cSEdward Tomasz Napierala static void
out_of_mem(void)3108a7a7d96cSPhilippe Charnier out_of_mem(void)
31098fae3551SRodney W. Grimes {
31108fae3551SRodney W. Grimes 
311174853402SPhilippe Charnier 	syslog(LOG_ERR, "out of memory");
31128fae3551SRodney W. Grimes 	exit(2);
31138fae3551SRodney W. Grimes }
31148fae3551SRodney W. Grimes 
31158fae3551SRodney W. Grimes /*
31160f0869bcSRick Macklem  * Call do_mount() from the struct exportlist, for each case needed.
31170f0869bcSRick Macklem  */
31180f0869bcSRick Macklem static int
do_export_mount(struct exportlist * ep,struct statfs * fsp)31190f0869bcSRick Macklem do_export_mount(struct exportlist *ep, struct statfs *fsp)
31200f0869bcSRick Macklem {
31210f0869bcSRick Macklem 	struct grouplist *grp, defgrp;
31220f0869bcSRick Macklem 	int ret;
31230f0869bcSRick Macklem 	size_t dirlen;
31240f0869bcSRick Macklem 
31250f0869bcSRick Macklem 	LOGDEBUG("do_export_mount=%s", ep->ex_fsdir);
31260f0869bcSRick Macklem 	dirlen = strlen(ep->ex_fsdir);
31270f0869bcSRick Macklem 	if ((ep->ex_flag & EX_DEFSET) != 0) {
31280f0869bcSRick Macklem 		defgrp.gr_type = GT_DEFAULT;
31290f0869bcSRick Macklem 		defgrp.gr_next = NULL;
31300f0869bcSRick Macklem 		/* We have an entry for all other hosts/nets. */
3131cc5efddeSRick Macklem 		LOGDEBUG("ex_defexflags=0x%jx", (uintmax_t)ep->ex_defexflags);
31320f0869bcSRick Macklem 		ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon,
31330f0869bcSRick Macklem 		    ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors,
31340f0869bcSRick Macklem 		    ep->ex_defsecflavors);
31350f0869bcSRick Macklem 		if (ret != 0)
31360f0869bcSRick Macklem 			return (ret);
31370f0869bcSRick Macklem 	}
31380f0869bcSRick Macklem 
31390f0869bcSRick Macklem 	/* Do a mount for each group. */
31400f0869bcSRick Macklem 	grp = ep->ex_grphead;
31410f0869bcSRick Macklem 	while (grp != NULL) {
3142cc5efddeSRick Macklem 		LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%jx",
3143cc5efddeSRick Macklem 		    grp->gr_type, (uintmax_t)grp->gr_exflags);
31440f0869bcSRick Macklem 		ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon,
31450f0869bcSRick Macklem 		    ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors,
31460f0869bcSRick Macklem 		    grp->gr_secflavors);
31470f0869bcSRick Macklem 		if (ret != 0)
31480f0869bcSRick Macklem 			return (ret);
31490f0869bcSRick Macklem 		grp = grp->gr_next;
31500f0869bcSRick Macklem 	}
31510f0869bcSRick Macklem 	return (0);
31520f0869bcSRick Macklem }
31530f0869bcSRick Macklem 
31540f0869bcSRick Macklem /*
31556a09faf2SCraig Rodrigues  * Do the nmount() syscall with the update flag to push the export info into
31568fae3551SRodney W. Grimes  * the kernel.
31578fae3551SRodney W. Grimes  */
315819c46d8cSEdward Tomasz Napierala static int
do_mount(struct exportlist * ep,struct grouplist * grp,uint64_t exflags,struct expcred * anoncrp,char * dirp,int dirplen,struct statfs * fsb,int numsecflavors,int * secflavors)3159cc5efddeSRick Macklem do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags,
3160cc5efddeSRick Macklem     struct expcred *anoncrp, char *dirp, int dirplen, struct statfs *fsb,
31610f0869bcSRick Macklem     int numsecflavors, int *secflavors)
31628fae3551SRodney W. Grimes {
3163f93caef2SIan Dowse 	struct statfs fsb1;
31648360efbdSAlfred Perlstein 	struct addrinfo *ai;
316579b86807SEdward Tomasz Napierala 	struct export_args *eap;
31666a09faf2SCraig Rodrigues 	char errmsg[255];
31676a09faf2SCraig Rodrigues 	char *cp;
31688fae3551SRodney W. Grimes 	int done;
31696a09faf2SCraig Rodrigues 	char savedc;
31706a09faf2SCraig Rodrigues 	struct iovec *iov;
3171a9148abdSDoug Rabson 	int i, iovlen;
31726a09faf2SCraig Rodrigues 	int ret;
3173bcc1d071SRick Macklem 	struct nfsex_args nfsea;
3174bcc1d071SRick Macklem 
3175bcc1d071SRick Macklem 	eap = &nfsea.export;
31768fae3551SRodney W. Grimes 
31776a09faf2SCraig Rodrigues 	cp = NULL;
31786a09faf2SCraig Rodrigues 	savedc = '\0';
31796a09faf2SCraig Rodrigues 	iov = NULL;
31806a09faf2SCraig Rodrigues 	iovlen = 0;
31816a09faf2SCraig Rodrigues 	ret = 0;
318260caaee2SIan Dowse 
3183bcc1d071SRick Macklem 	bzero(eap, sizeof (struct export_args));
31846a09faf2SCraig Rodrigues 	bzero(errmsg, sizeof(errmsg));
3185bcc1d071SRick Macklem 	eap->ex_flags = exflags;
3186cc5efddeSRick Macklem 	eap->ex_uid = anoncrp->cr_uid;
3187cc5efddeSRick Macklem 	eap->ex_ngroups = anoncrp->cr_ngroups;
3188cc5efddeSRick Macklem 	if (eap->ex_ngroups > 0) {
3189cc5efddeSRick Macklem 		eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t));
3190cc5efddeSRick Macklem 		memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups *
3191cc5efddeSRick Macklem 		    sizeof(gid_t));
3192cc5efddeSRick Macklem 	}
3193cc5efddeSRick Macklem 	LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags);
3194bcc1d071SRick Macklem 	eap->ex_indexfile = ep->ex_indexfile;
31956d359f31SIan Dowse 	if (grp->gr_type == GT_HOST)
31968360efbdSAlfred Perlstein 		ai = grp->gr_ptr.gt_addrinfo;
31976d359f31SIan Dowse 	else
31986d359f31SIan Dowse 		ai = NULL;
31990f0869bcSRick Macklem 	eap->ex_numsecflavors = numsecflavors;
32000f0869bcSRick Macklem 	LOGDEBUG("do_mount numsec=%d", numsecflavors);
3201bcc1d071SRick Macklem 	for (i = 0; i < eap->ex_numsecflavors; i++)
32020f0869bcSRick Macklem 		eap->ex_secflavors[i] = secflavors[i];
3203bcc1d071SRick Macklem 	if (eap->ex_numsecflavors == 0) {
3204bcc1d071SRick Macklem 		eap->ex_numsecflavors = 1;
3205bcc1d071SRick Macklem 		eap->ex_secflavors[0] = AUTH_SYS;
3206a9148abdSDoug Rabson 	}
32078fae3551SRodney W. Grimes 	done = FALSE;
32086a09faf2SCraig Rodrigues 
3209bcc1d071SRick Macklem 	if (v4root_phase == 0) {
32106a09faf2SCraig Rodrigues 		build_iovec(&iov, &iovlen, "fstype", NULL, 0);
32116a09faf2SCraig Rodrigues 		build_iovec(&iov, &iovlen, "fspath", NULL, 0);
32126a09faf2SCraig Rodrigues 		build_iovec(&iov, &iovlen, "from", NULL, 0);
32136a09faf2SCraig Rodrigues 		build_iovec(&iov, &iovlen, "update", NULL, 0);
3214bcc1d071SRick Macklem 		build_iovec(&iov, &iovlen, "export", eap,
3215bcc1d071SRick Macklem 		    sizeof (struct export_args));
32166a09faf2SCraig Rodrigues 		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
3217bcc1d071SRick Macklem 	}
32186a09faf2SCraig Rodrigues 
32198fae3551SRodney W. Grimes 	while (!done) {
32208fae3551SRodney W. Grimes 		switch (grp->gr_type) {
32218fae3551SRodney W. Grimes 		case GT_HOST:
32226d359f31SIan Dowse 			if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
32238360efbdSAlfred Perlstein 				goto skip;
3224bcc1d071SRick Macklem 			eap->ex_addr = ai->ai_addr;
3225bcc1d071SRick Macklem 			eap->ex_addrlen = ai->ai_addrlen;
3226bcc1d071SRick Macklem 			eap->ex_masklen = 0;
32278fae3551SRodney W. Grimes 			break;
32288fae3551SRodney W. Grimes 		case GT_NET:
322960caaee2SIan Dowse 			if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
32308360efbdSAlfred Perlstein 			    have_v6 == 0)
32318360efbdSAlfred Perlstein 				goto skip;
3232bcc1d071SRick Macklem 			eap->ex_addr =
323360caaee2SIan Dowse 			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
3234bcc1d071SRick Macklem 			eap->ex_addrlen =
32356a09faf2SCraig Rodrigues 			    ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len;
3236bcc1d071SRick Macklem 			eap->ex_mask =
323760caaee2SIan Dowse 			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
3238bcc1d071SRick Macklem 			eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
32398fae3551SRodney W. Grimes 			break;
32406d359f31SIan Dowse 		case GT_DEFAULT:
3241bcc1d071SRick Macklem 			eap->ex_addr = NULL;
3242bcc1d071SRick Macklem 			eap->ex_addrlen = 0;
3243bcc1d071SRick Macklem 			eap->ex_mask = NULL;
3244bcc1d071SRick Macklem 			eap->ex_masklen = 0;
32456d359f31SIan Dowse 			break;
32468b5a6d67SBill Paul 		case GT_IGNORE:
32476a09faf2SCraig Rodrigues 			ret = 0;
32486a09faf2SCraig Rodrigues 			goto error_exit;
32498b5a6d67SBill Paul 			break;
32508fae3551SRodney W. Grimes 		default:
325174853402SPhilippe Charnier 			syslog(LOG_ERR, "bad grouptype");
32528fae3551SRodney W. Grimes 			if (cp)
32538fae3551SRodney W. Grimes 				*cp = savedc;
32546a09faf2SCraig Rodrigues 			ret = 1;
32556a09faf2SCraig Rodrigues 			goto error_exit;
325680c7cc1cSPedro F. Giffuni 		}
32578fae3551SRodney W. Grimes 
32588fae3551SRodney W. Grimes 		/*
3259bcc1d071SRick Macklem 		 * For V4:, use the nfssvc() syscall, instead of mount().
3260bcc1d071SRick Macklem 		 */
3261bcc1d071SRick Macklem 		if (v4root_phase == 2) {
3262bcc1d071SRick Macklem 			nfsea.fspec = v4root_dirpath;
3263cc5efddeSRick Macklem 			if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT,
3264cc5efddeSRick Macklem 			    (caddr_t)&nfsea) < 0) {
3265bcc1d071SRick Macklem 				syslog(LOG_ERR, "Exporting V4: failed");
3266cc5efddeSRick Macklem 				ret = 2;
3267cc5efddeSRick Macklem 				goto error_exit;
3268bcc1d071SRick Macklem 			}
3269bcc1d071SRick Macklem 		} else {
3270bcc1d071SRick Macklem 			/*
32718fae3551SRodney W. Grimes 			 * XXX:
3272bcc1d071SRick Macklem 			 * Maybe I should just use the fsb->f_mntonname path
3273bcc1d071SRick Macklem 			 * instead of looping back up the dirp to the mount
3274bcc1d071SRick Macklem 			 * point??
32758fae3551SRodney W. Grimes 			 * Also, needs to know how to export all types of local
327687564113SPeter Wemm 			 * exportable filesystems and not just "ufs".
32778fae3551SRodney W. Grimes 			 */
32786a09faf2SCraig Rodrigues 			iov[1].iov_base = fsb->f_fstypename; /* "fstype" */
32796a09faf2SCraig Rodrigues 			iov[1].iov_len = strlen(fsb->f_fstypename) + 1;
32806a09faf2SCraig Rodrigues 			iov[3].iov_base = fsb->f_mntonname; /* "fspath" */
32816a09faf2SCraig Rodrigues 			iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
32826a09faf2SCraig Rodrigues 			iov[5].iov_base = fsb->f_mntfromname; /* "from" */
32836a09faf2SCraig Rodrigues 			iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
32844a185fa6SBryan Drewery 			errmsg[0] = '\0';
32856a09faf2SCraig Rodrigues 
328655dd1327SCraig Rodrigues 			while (nmount(iov, iovlen, fsb->f_flags) < 0) {
32878fae3551SRodney W. Grimes 				if (cp)
32888fae3551SRodney W. Grimes 					*cp-- = savedc;
32898fae3551SRodney W. Grimes 				else
32908fae3551SRodney W. Grimes 					cp = dirp + dirplen - 1;
32916a09faf2SCraig Rodrigues 				if (opt_flags & OP_QUIET) {
32926a09faf2SCraig Rodrigues 					ret = 1;
32936a09faf2SCraig Rodrigues 					goto error_exit;
32946a09faf2SCraig Rodrigues 				}
32958fae3551SRodney W. Grimes 				if (errno == EPERM) {
329601709abfSIan Dowse 					if (debug)
329777909162SXin LI 						warnx("can't change attributes for %s: %s",
329877909162SXin LI 						    dirp, errmsg);
32998fae3551SRodney W. Grimes 					syslog(LOG_ERR,
330077909162SXin LI 					   "can't change attributes for %s: %s",
330177909162SXin LI 					    dirp, errmsg);
33026a09faf2SCraig Rodrigues 					ret = 1;
33036a09faf2SCraig Rodrigues 					goto error_exit;
33048fae3551SRodney W. Grimes 				}
33058fae3551SRodney W. Grimes 				if (opt_flags & OP_ALLDIRS) {
3306288fa14aSJoerg Wunsch 					if (errno == EINVAL)
3307288fa14aSJoerg Wunsch 						syslog(LOG_ERR,
3308288fa14aSJoerg Wunsch 		"-alldirs requested but %s is not a filesystem mountpoint",
3309288fa14aSJoerg Wunsch 						    dirp);
3310288fa14aSJoerg Wunsch 					else
3311288fa14aSJoerg Wunsch 						syslog(LOG_ERR,
3312288fa14aSJoerg Wunsch 						    "could not remount %s: %m",
33133980ac4fSGarrett Wollman 						    dirp);
33146a09faf2SCraig Rodrigues 					ret = 1;
33156a09faf2SCraig Rodrigues 					goto error_exit;
33168fae3551SRodney W. Grimes 				}
33178fae3551SRodney W. Grimes 				/* back up over the last component */
3318d90b3641SBrooks Davis 				while (cp > dirp && *cp == '/')
33198fae3551SRodney W. Grimes 					cp--;
3320d90b3641SBrooks Davis 				while (cp > dirp && *(cp - 1) != '/')
33218fae3551SRodney W. Grimes 					cp--;
33228fae3551SRodney W. Grimes 				if (cp == dirp) {
33238fae3551SRodney W. Grimes 					if (debug)
332474853402SPhilippe Charnier 						warnx("mnt unsucc");
3325bcc1d071SRick Macklem 					syslog(LOG_ERR, "can't export %s %s",
3326bcc1d071SRick Macklem 					    dirp, errmsg);
33276a09faf2SCraig Rodrigues 					ret = 1;
33286a09faf2SCraig Rodrigues 					goto error_exit;
33298fae3551SRodney W. Grimes 				}
33308fae3551SRodney W. Grimes 				savedc = *cp;
33318fae3551SRodney W. Grimes 				*cp = '\0';
3332bcc1d071SRick Macklem 				/*
3333bcc1d071SRick Macklem 				 * Check that we're still on the same
3334bcc1d071SRick Macklem 				 * filesystem.
3335bcc1d071SRick Macklem 				 */
3336bcc1d071SRick Macklem 				if (statfs(dirp, &fsb1) != 0 ||
3337245bfd34SRyan Moeller 				    fsidcmp(&fsb1.f_fsid, &fsb->f_fsid) != 0) {
3338f93caef2SIan Dowse 					*cp = savedc;
3339bcc1d071SRick Macklem 					syslog(LOG_ERR,
3340bcc1d071SRick Macklem 					    "can't export %s %s", dirp,
334137518a88SCraig Rodrigues 					    errmsg);
33426a09faf2SCraig Rodrigues 					ret = 1;
33436a09faf2SCraig Rodrigues 					goto error_exit;
3344f93caef2SIan Dowse 				}
33458fae3551SRodney W. Grimes 			}
3346bcc1d071SRick Macklem 		}
3347bcc1d071SRick Macklem 
3348bcc1d071SRick Macklem 		/*
3349bcc1d071SRick Macklem 		 * For the experimental server:
3350bcc1d071SRick Macklem 		 * If this is the public directory, get the file handle
3351bcc1d071SRick Macklem 		 * and load it into the kernel via the nfssvc() syscall.
3352bcc1d071SRick Macklem 		 */
335379b86807SEdward Tomasz Napierala 		if ((exflags & MNT_EXPUBLIC) != 0) {
3354bcc1d071SRick Macklem 			fhandle_t fh;
3355bcc1d071SRick Macklem 			char *public_name;
3356bcc1d071SRick Macklem 
3357bcc1d071SRick Macklem 			if (eap->ex_indexfile != NULL)
3358bcc1d071SRick Macklem 				public_name = eap->ex_indexfile;
3359bcc1d071SRick Macklem 			else
3360bcc1d071SRick Macklem 				public_name = dirp;
3361bcc1d071SRick Macklem 			if (getfh(public_name, &fh) < 0)
3362bcc1d071SRick Macklem 				syslog(LOG_ERR,
3363bcc1d071SRick Macklem 				    "Can't get public fh for %s", public_name);
3364bcc1d071SRick Macklem 			else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0)
3365bcc1d071SRick Macklem 				syslog(LOG_ERR,
3366bcc1d071SRick Macklem 				    "Can't set public fh for %s", public_name);
33670f0869bcSRick Macklem 			else {
3368bcc1d071SRick Macklem 				has_publicfh = 1;
33690f0869bcSRick Macklem 				has_set_publicfh = 1;
33700f0869bcSRick Macklem 				ep->ex_flag |= EX_PUBLICFH;
33710f0869bcSRick Macklem 			}
3372bcc1d071SRick Macklem 		}
33738360efbdSAlfred Perlstein skip:
33746d359f31SIan Dowse 		if (ai != NULL)
33758360efbdSAlfred Perlstein 			ai = ai->ai_next;
33768360efbdSAlfred Perlstein 		if (ai == NULL)
33778fae3551SRodney W. Grimes 			done = TRUE;
33788fae3551SRodney W. Grimes 	}
33798fae3551SRodney W. Grimes 	if (cp)
33808fae3551SRodney W. Grimes 		*cp = savedc;
33816a09faf2SCraig Rodrigues error_exit:
3382cc5efddeSRick Macklem 	free(eap->ex_groups);
33836a09faf2SCraig Rodrigues 	/* free strings allocated by strdup() in getmntopts.c */
33846a09faf2SCraig Rodrigues 	if (iov != NULL) {
33856a09faf2SCraig Rodrigues 		free(iov[0].iov_base); /* fstype */
33866a09faf2SCraig Rodrigues 		free(iov[2].iov_base); /* fspath */
33876a09faf2SCraig Rodrigues 		free(iov[4].iov_base); /* from */
33886a09faf2SCraig Rodrigues 		free(iov[6].iov_base); /* update */
33896a09faf2SCraig Rodrigues 		free(iov[8].iov_base); /* export */
33906a09faf2SCraig Rodrigues 		free(iov[10].iov_base); /* errmsg */
33916a09faf2SCraig Rodrigues 
33926a09faf2SCraig Rodrigues 		/* free iov, allocated by realloc() */
33936a09faf2SCraig Rodrigues 		free(iov);
33946a09faf2SCraig Rodrigues 	}
33956a09faf2SCraig Rodrigues 	return (ret);
33968fae3551SRodney W. Grimes }
33978fae3551SRodney W. Grimes 
33988fae3551SRodney W. Grimes /*
33998fae3551SRodney W. Grimes  * Translate a net address.
340060caaee2SIan Dowse  *
340160caaee2SIan Dowse  * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
34028fae3551SRodney W. Grimes  */
340319c46d8cSEdward Tomasz Napierala static int
get_net(char * cp,struct netmsk * net,int maskflg)3404a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg)
34058fae3551SRodney W. Grimes {
3406931c04f1SIan Dowse 	struct netent *np = NULL;
34078360efbdSAlfred Perlstein 	char *name, *p, *prefp;
340860caaee2SIan Dowse 	struct sockaddr_in sin;
3409931c04f1SIan Dowse 	struct sockaddr *sa = NULL;
34108360efbdSAlfred Perlstein 	struct addrinfo hints, *ai = NULL;
34118360efbdSAlfred Perlstein 	char netname[NI_MAXHOST];
34128360efbdSAlfred Perlstein 	long preflen;
34138fae3551SRodney W. Grimes 
341401709abfSIan Dowse 	p = prefp = NULL;
34158360efbdSAlfred Perlstein 	if ((opt_flags & OP_MASKLEN) && !maskflg) {
34168360efbdSAlfred Perlstein 		p = strchr(cp, '/');
34178360efbdSAlfred Perlstein 		*p = '\0';
34188360efbdSAlfred Perlstein 		prefp = p + 1;
34198360efbdSAlfred Perlstein 	}
34208360efbdSAlfred Perlstein 
3421931c04f1SIan Dowse 	/*
3422931c04f1SIan Dowse 	 * Check for a numeric address first. We wish to avoid
3423931c04f1SIan Dowse 	 * possible DNS lookups in getnetbyname().
3424931c04f1SIan Dowse 	 */
3425931c04f1SIan Dowse 	if (isxdigit(*cp) || *cp == ':') {
34268360efbdSAlfred Perlstein 		memset(&hints, 0, sizeof hints);
342760caaee2SIan Dowse 		/* Ensure the mask and the network have the same family. */
342860caaee2SIan Dowse 		if (maskflg && (opt_flags & OP_NET))
342960caaee2SIan Dowse 			hints.ai_family = net->nt_net.ss_family;
343060caaee2SIan Dowse 		else if (!maskflg && (opt_flags & OP_HAVEMASK))
343160caaee2SIan Dowse 			hints.ai_family = net->nt_mask.ss_family;
343260caaee2SIan Dowse 		else
34338360efbdSAlfred Perlstein 			hints.ai_family = AF_UNSPEC;
34348360efbdSAlfred Perlstein 		hints.ai_flags = AI_NUMERICHOST;
3435931c04f1SIan Dowse 		if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
3436931c04f1SIan Dowse 			sa = ai->ai_addr;
3437931c04f1SIan Dowse 		if (sa != NULL && ai->ai_family == AF_INET) {
34388fae3551SRodney W. Grimes 			/*
343960caaee2SIan Dowse 			 * The address in `cp' is really a network address, so
344060caaee2SIan Dowse 			 * use inet_network() to re-interpret this correctly.
344160caaee2SIan Dowse 			 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
34428fae3551SRodney W. Grimes 			 */
344360caaee2SIan Dowse 			bzero(&sin, sizeof sin);
34448360efbdSAlfred Perlstein 			sin.sin_family = AF_INET;
34458360efbdSAlfred Perlstein 			sin.sin_len = sizeof sin;
34468360efbdSAlfred Perlstein 			sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
34478360efbdSAlfred Perlstein 			if (debug)
344860caaee2SIan Dowse 				fprintf(stderr, "get_net: v4 addr %s\n",
344960caaee2SIan Dowse 				    inet_ntoa(sin.sin_addr));
34508360efbdSAlfred Perlstein 			sa = (struct sockaddr *)&sin;
3451931c04f1SIan Dowse 		}
3452931c04f1SIan Dowse 	}
3453931c04f1SIan Dowse 	if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
3454931c04f1SIan Dowse 		bzero(&sin, sizeof sin);
3455931c04f1SIan Dowse 		sin.sin_family = AF_INET;
3456931c04f1SIan Dowse 		sin.sin_len = sizeof sin;
3457931c04f1SIan Dowse 		sin.sin_addr = inet_makeaddr(np->n_net, 0);
3458931c04f1SIan Dowse 		sa = (struct sockaddr *)&sin;
3459931c04f1SIan Dowse 	}
3460931c04f1SIan Dowse 	if (sa == NULL)
34618360efbdSAlfred Perlstein 		goto fail;
34628360efbdSAlfred Perlstein 
346360caaee2SIan Dowse 	if (maskflg) {
346460caaee2SIan Dowse 		/* The specified sockaddr is a mask. */
346560caaee2SIan Dowse 		if (checkmask(sa) != 0)
34668360efbdSAlfred Perlstein 			goto fail;
346760caaee2SIan Dowse 		bcopy(sa, &net->nt_mask, sa->sa_len);
346860caaee2SIan Dowse 		opt_flags |= OP_HAVEMASK;
346948514c57SMike Karels 		opt_flags &= ~OP_CLASSMASK;
347060caaee2SIan Dowse 	} else {
347160caaee2SIan Dowse 		/* The specified sockaddr is a network address. */
347260caaee2SIan Dowse 		bcopy(sa, &net->nt_net, sa->sa_len);
34730f4b7baaSPaul Traina 
347460caaee2SIan Dowse 		/* Get a network name for the export list. */
347560caaee2SIan Dowse 		if (np) {
347660caaee2SIan Dowse 			name = np->n_name;
347760caaee2SIan Dowse 		} else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
34784f101318SHajimu UMEMOTO 		   NULL, 0, NI_NUMERICHOST) == 0) {
347960caaee2SIan Dowse 			name = netname;
348060caaee2SIan Dowse 		} else {
348160caaee2SIan Dowse 			goto fail;
348260caaee2SIan Dowse 		}
348360caaee2SIan Dowse 		if ((net->nt_name = strdup(name)) == NULL)
348460caaee2SIan Dowse 			out_of_mem();
348560caaee2SIan Dowse 
348660caaee2SIan Dowse 		/*
348760caaee2SIan Dowse 		 * Extract a mask from either a "/<masklen>" suffix, or
348860caaee2SIan Dowse 		 * from the class of an IPv4 address.
348960caaee2SIan Dowse 		 */
34908360efbdSAlfred Perlstein 		if (opt_flags & OP_MASKLEN) {
34918360efbdSAlfred Perlstein 			preflen = strtol(prefp, NULL, 10);
349260caaee2SIan Dowse 			if (preflen < 0L || preflen == LONG_MAX)
34938360efbdSAlfred Perlstein 				goto fail;
349460caaee2SIan Dowse 			bcopy(sa, &net->nt_mask, sa->sa_len);
349560caaee2SIan Dowse 			if (makemask(&net->nt_mask, (int)preflen) != 0)
349660caaee2SIan Dowse 				goto fail;
349760caaee2SIan Dowse 			opt_flags |= OP_HAVEMASK;
34988360efbdSAlfred Perlstein 			*p = '/';
349960caaee2SIan Dowse 		} else if (sa->sa_family == AF_INET &&
350060caaee2SIan Dowse 		    (opt_flags & OP_MASK) == 0) {
350160caaee2SIan Dowse 			in_addr_t addr;
35028360efbdSAlfred Perlstein 
350360caaee2SIan Dowse 			addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
350460caaee2SIan Dowse 			if (IN_CLASSA(addr))
350560caaee2SIan Dowse 				preflen = 8;
350660caaee2SIan Dowse 			else if (IN_CLASSB(addr))
350760caaee2SIan Dowse 				preflen = 16;
350860caaee2SIan Dowse 			else if (IN_CLASSC(addr))
350960caaee2SIan Dowse 				preflen = 24;
351092aebdeaSMike Karels 			else if (IN_CLASSD(addr))	/* XXX Multicast??? */
351160caaee2SIan Dowse 				preflen = 28;
35128360efbdSAlfred Perlstein 			else
351360caaee2SIan Dowse 				preflen = 32;	/* XXX */
351460caaee2SIan Dowse 
351560caaee2SIan Dowse 			bcopy(sa, &net->nt_mask, sa->sa_len);
351660caaee2SIan Dowse 			makemask(&net->nt_mask, (int)preflen);
351748514c57SMike Karels 			opt_flags |= OP_HAVEMASK | OP_CLASSMASK;
351860caaee2SIan Dowse 		}
35198360efbdSAlfred Perlstein 	}
35208360efbdSAlfred Perlstein 
35218360efbdSAlfred Perlstein 	if (ai)
35228360efbdSAlfred Perlstein 		freeaddrinfo(ai);
35238360efbdSAlfred Perlstein 	return 0;
35248360efbdSAlfred Perlstein 
35258360efbdSAlfred Perlstein fail:
35268360efbdSAlfred Perlstein 	if (ai)
35278360efbdSAlfred Perlstein 		freeaddrinfo(ai);
35288360efbdSAlfred Perlstein 	return 1;
35298fae3551SRodney W. Grimes }
35308fae3551SRodney W. Grimes 
35318fae3551SRodney W. Grimes /*
35328fae3551SRodney W. Grimes  * Parse out the next white space separated field
35338fae3551SRodney W. Grimes  */
353419c46d8cSEdward Tomasz Napierala static void
nextfield(char ** cp,char ** endcp)3535a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp)
35368fae3551SRodney W. Grimes {
35378fae3551SRodney W. Grimes 	char *p;
3538eb1f7f43SAlexander Motin 	char quot = 0;
35398fae3551SRodney W. Grimes 
35408fae3551SRodney W. Grimes 	p = *cp;
35418fae3551SRodney W. Grimes 	while (*p == ' ' || *p == '\t')
35428fae3551SRodney W. Grimes 		p++;
3543eb1f7f43SAlexander Motin 	*cp = p;
3544eb1f7f43SAlexander Motin 	while (*p != '\0') {
3545eb1f7f43SAlexander Motin 		if (quot) {
3546eb1f7f43SAlexander Motin 			if (*p == quot)
3547eb1f7f43SAlexander Motin 				quot = 0;
3548eb1f7f43SAlexander Motin 		} else {
3549eb1f7f43SAlexander Motin 			if (*p == '\\' && *(p + 1) != '\0')
35508fae3551SRodney W. Grimes 				p++;
3551eb1f7f43SAlexander Motin 			else if (*p == '\'' || *p == '"')
3552eb1f7f43SAlexander Motin 				quot = *p;
3553eb1f7f43SAlexander Motin 			else if (*p == ' ' || *p == '\t')
3554eb1f7f43SAlexander Motin 				break;
35558fae3551SRodney W. Grimes 		}
3556eb1f7f43SAlexander Motin 		p++;
3557eb1f7f43SAlexander Motin 	};
3558eb1f7f43SAlexander Motin 	*endcp = p;
35598fae3551SRodney W. Grimes }
35608fae3551SRodney W. Grimes 
35618fae3551SRodney W. Grimes /*
35628fae3551SRodney W. Grimes  * Get an exports file line. Skip over blank lines and handle line
35638fae3551SRodney W. Grimes  * continuations.
35648fae3551SRodney W. Grimes  */
356519c46d8cSEdward Tomasz Napierala static int
get_line(void)3566a7a7d96cSPhilippe Charnier get_line(void)
35678fae3551SRodney W. Grimes {
35688fae3551SRodney W. Grimes 	char *p, *cp;
356991ca1a91SIan Dowse 	size_t len;
35708fae3551SRodney W. Grimes 	int totlen, cont_line;
35718fae3551SRodney W. Grimes 
35728fae3551SRodney W. Grimes 	/*
35738fae3551SRodney W. Grimes 	 * Loop around ignoring blank lines and getting all continuation lines.
35748fae3551SRodney W. Grimes 	 */
35758fae3551SRodney W. Grimes 	p = line;
35768fae3551SRodney W. Grimes 	totlen = 0;
35778fae3551SRodney W. Grimes 	do {
357891ca1a91SIan Dowse 		if ((p = fgetln(exp_file, &len)) == NULL)
35798fae3551SRodney W. Grimes 			return (0);
35808fae3551SRodney W. Grimes 		cp = p + len - 1;
35818fae3551SRodney W. Grimes 		cont_line = 0;
35828fae3551SRodney W. Grimes 		while (cp >= p &&
35838fae3551SRodney W. Grimes 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
35848fae3551SRodney W. Grimes 			if (*cp == '\\')
35858fae3551SRodney W. Grimes 				cont_line = 1;
35868fae3551SRodney W. Grimes 			cp--;
35878fae3551SRodney W. Grimes 			len--;
35888fae3551SRodney W. Grimes 		}
3589376f8390SDima Dorfman 		if (cont_line) {
3590376f8390SDima Dorfman 			*++cp = ' ';
3591376f8390SDima Dorfman 			len++;
3592376f8390SDima Dorfman 		}
359391ca1a91SIan Dowse 		if (linesize < len + totlen + 1) {
359491ca1a91SIan Dowse 			linesize = len + totlen + 1;
359591ca1a91SIan Dowse 			line = realloc(line, linesize);
359691ca1a91SIan Dowse 			if (line == NULL)
359791ca1a91SIan Dowse 				out_of_mem();
359891ca1a91SIan Dowse 		}
359991ca1a91SIan Dowse 		memcpy(line + totlen, p, len);
36008fae3551SRodney W. Grimes 		totlen += len;
360191ca1a91SIan Dowse 		line[totlen] = '\0';
36028fae3551SRodney W. Grimes 	} while (totlen == 0 || cont_line);
36038fae3551SRodney W. Grimes 	return (1);
36048fae3551SRodney W. Grimes }
36058fae3551SRodney W. Grimes 
36068fae3551SRodney W. Grimes /*
36078fae3551SRodney W. Grimes  * Parse a description of a credential.
36088fae3551SRodney W. Grimes  */
360919c46d8cSEdward Tomasz Napierala static void
parsecred(char * namelist,struct expcred * cr)3610cc5efddeSRick Macklem parsecred(char *namelist, struct expcred *cr)
36118fae3551SRodney W. Grimes {
36128fae3551SRodney W. Grimes 	char *name;
36132ffad162SRick Macklem 	int inpos;
36148fae3551SRodney W. Grimes 	char *names;
36158fae3551SRodney W. Grimes 	struct passwd *pw;
36168fae3551SRodney W. Grimes 	struct group *gr;
36172ffad162SRick Macklem 	gid_t groups[NGROUPS_MAX + 1];
36182ffad162SRick Macklem 	int ngroups;
3619f4bf849bSRick Macklem 	unsigned long name_ul;
3620f4bf849bSRick Macklem 	char *end = NULL;
36218fae3551SRodney W. Grimes 
36228fae3551SRodney W. Grimes 	/*
362374853402SPhilippe Charnier 	 * Set up the unprivileged user.
36248fae3551SRodney W. Grimes 	 */
36252ffad162SRick Macklem 	cr->cr_groups = cr->cr_smallgrps;
36263e2d36ffSRick Macklem 	cr->cr_uid = UID_NOBODY;
36273e2d36ffSRick Macklem 	cr->cr_groups[0] = GID_NOGROUP;
36288fae3551SRodney W. Grimes 	cr->cr_ngroups = 1;
36298fae3551SRodney W. Grimes 	/*
36308fae3551SRodney W. Grimes 	 * Get the user's password table entry.
36318fae3551SRodney W. Grimes 	 */
3632eb1f7f43SAlexander Motin 	names = namelist;
3633eb1f7f43SAlexander Motin 	name = strsep_quote(&names, ":");
3634b875c2e9SJosh Paetzel 	/* Bug?  name could be NULL here */
3635f4bf849bSRick Macklem 	name_ul = strtoul(name, &end, 10);
3636f4bf849bSRick Macklem 	if (*end != '\0' || end == name)
36378fae3551SRodney W. Grimes 		pw = getpwnam(name);
3638f4bf849bSRick Macklem 	else
3639f4bf849bSRick Macklem 		pw = getpwuid((uid_t)name_ul);
36408fae3551SRodney W. Grimes 	/*
36418fae3551SRodney W. Grimes 	 * Credentials specified as those of a user.
36428fae3551SRodney W. Grimes 	 */
36438fae3551SRodney W. Grimes 	if (names == NULL) {
36448fae3551SRodney W. Grimes 		if (pw == NULL) {
364574853402SPhilippe Charnier 			syslog(LOG_ERR, "unknown user: %s", name);
36468fae3551SRodney W. Grimes 			return;
36478fae3551SRodney W. Grimes 		}
36488fae3551SRodney W. Grimes 		cr->cr_uid = pw->pw_uid;
36492ffad162SRick Macklem 		ngroups = NGROUPS_MAX + 1;
36502ffad162SRick Macklem 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) {
365174853402SPhilippe Charnier 			syslog(LOG_ERR, "too many groups");
36522ffad162SRick Macklem 			ngroups = NGROUPS_MAX + 1;
3653020d6f96SAndriy Gapon 		}
3654020d6f96SAndriy Gapon 
36558fae3551SRodney W. Grimes 		/*
3656950cc395SStefan Farfeleder 		 * Compress out duplicate.
36578fae3551SRodney W. Grimes 		 */
36582ffad162SRick Macklem 		if (ngroups > 1 && groups[0] == groups[1]) {
36592ffad162SRick Macklem 			ngroups--;
36602ffad162SRick Macklem 			inpos = 2;
3661f4bf849bSRick Macklem 		} else {
36622ffad162SRick Macklem 			inpos = 1;
3663f4bf849bSRick Macklem 		}
36642ffad162SRick Macklem 		if (ngroups > NGROUPS_MAX)
36652ffad162SRick Macklem 			ngroups = NGROUPS_MAX;
36662ffad162SRick Macklem 		if (ngroups > SMALLNGROUPS)
36672ffad162SRick Macklem 			cr->cr_groups = malloc(ngroups * sizeof(gid_t));
36682ffad162SRick Macklem 		cr->cr_ngroups = ngroups;
36692ffad162SRick Macklem 		cr->cr_groups[0] = groups[0];
36702ffad162SRick Macklem 		memcpy(&cr->cr_groups[1], &groups[inpos], (ngroups - 1) *
36712ffad162SRick Macklem 		    sizeof(gid_t));
36728fae3551SRodney W. Grimes 		return;
36738fae3551SRodney W. Grimes 	}
36748fae3551SRodney W. Grimes 	/*
36758fae3551SRodney W. Grimes 	 * Explicit credential specified as a colon separated list:
36768fae3551SRodney W. Grimes 	 *	uid:gid:gid:...
36778fae3551SRodney W. Grimes 	 */
3678f4bf849bSRick Macklem 	if (pw != NULL) {
36798fae3551SRodney W. Grimes 		cr->cr_uid = pw->pw_uid;
3680f4bf849bSRick Macklem 	} else if (*end != '\0' || end == name) {
368174853402SPhilippe Charnier 		syslog(LOG_ERR, "unknown user: %s", name);
36828fae3551SRodney W. Grimes 		return;
3683f4bf849bSRick Macklem 	} else {
3684f4bf849bSRick Macklem 		cr->cr_uid = name_ul;
36858fae3551SRodney W. Grimes 	}
36868fae3551SRodney W. Grimes 	cr->cr_ngroups = 0;
3687cc5efddeSRick Macklem 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) {
3688eb1f7f43SAlexander Motin 		name = strsep_quote(&names, ":");
3689f4bf849bSRick Macklem 		name_ul = strtoul(name, &end, 10);
3690f4bf849bSRick Macklem 		if (*end != '\0' || end == name) {
36918fae3551SRodney W. Grimes 			if ((gr = getgrnam(name)) == NULL) {
369274853402SPhilippe Charnier 				syslog(LOG_ERR, "unknown group: %s", name);
36938fae3551SRodney W. Grimes 				continue;
36948fae3551SRodney W. Grimes 			}
36952ffad162SRick Macklem 			groups[cr->cr_ngroups++] = gr->gr_gid;
3696f4bf849bSRick Macklem 		} else {
3697f4bf849bSRick Macklem 			groups[cr->cr_ngroups++] = name_ul;
36988fae3551SRodney W. Grimes 		}
36998fae3551SRodney W. Grimes 	}
3700cc5efddeSRick Macklem 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX)
370174853402SPhilippe Charnier 		syslog(LOG_ERR, "too many groups");
37022ffad162SRick Macklem 	if (cr->cr_ngroups > SMALLNGROUPS)
37032ffad162SRick Macklem 		cr->cr_groups = malloc(cr->cr_ngroups * sizeof(gid_t));
37042ffad162SRick Macklem 	memcpy(cr->cr_groups, groups, cr->cr_ngroups * sizeof(gid_t));
37058fae3551SRodney W. Grimes }
37068fae3551SRodney W. Grimes 
37070775314bSDoug Rabson #define	STRSIZ	(MNTNAMLEN+MNTPATHLEN+50)
37088fae3551SRodney W. Grimes /*
37098fae3551SRodney W. Grimes  * Routines that maintain the remote mounttab
37108fae3551SRodney W. Grimes  */
371119c46d8cSEdward Tomasz Napierala static void
get_mountlist(void)3712a7a7d96cSPhilippe Charnier get_mountlist(void)
37138fae3551SRodney W. Grimes {
37141da3e8b0SEmmanuel Vadot 	struct mountlist *mlp;
371587564113SPeter Wemm 	char *host, *dirp, *cp;
37168fae3551SRodney W. Grimes 	char str[STRSIZ];
37178fae3551SRodney W. Grimes 	FILE *mlfile;
37188fae3551SRodney W. Grimes 
37198fae3551SRodney W. Grimes 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
372039539916SBill Fumerola 		if (errno == ENOENT)
372139539916SBill Fumerola 			return;
372239539916SBill Fumerola 		else {
372374853402SPhilippe Charnier 			syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
37248fae3551SRodney W. Grimes 			return;
37258fae3551SRodney W. Grimes 		}
372639539916SBill Fumerola 	}
37278fae3551SRodney W. Grimes 	while (fgets(str, STRSIZ, mlfile) != NULL) {
372887564113SPeter Wemm 		cp = str;
372987564113SPeter Wemm 		host = strsep(&cp, " \t\n");
373087564113SPeter Wemm 		dirp = strsep(&cp, " \t\n");
373187564113SPeter Wemm 		if (host == NULL || dirp == NULL)
37328fae3551SRodney W. Grimes 			continue;
37338fae3551SRodney W. Grimes 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
373474853402SPhilippe Charnier 		if (mlp == (struct mountlist *)NULL)
373574853402SPhilippe Charnier 			out_of_mem();
37360775314bSDoug Rabson 		strncpy(mlp->ml_host, host, MNTNAMLEN);
37370775314bSDoug Rabson 		mlp->ml_host[MNTNAMLEN] = '\0';
37380775314bSDoug Rabson 		strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
37390775314bSDoug Rabson 		mlp->ml_dirp[MNTPATHLEN] = '\0';
37401da3e8b0SEmmanuel Vadot 
37411da3e8b0SEmmanuel Vadot 		SLIST_INSERT_HEAD(&mlhead, mlp, next);
37428fae3551SRodney W. Grimes 	}
37438fae3551SRodney W. Grimes 	fclose(mlfile);
37448fae3551SRodney W. Grimes }
37458fae3551SRodney W. Grimes 
374619c46d8cSEdward Tomasz Napierala static void
del_mlist(char * hostp,char * dirp)374701709abfSIan Dowse del_mlist(char *hostp, char *dirp)
37488fae3551SRodney W. Grimes {
37491da3e8b0SEmmanuel Vadot 	struct mountlist *mlp, *mlp2;
37508fae3551SRodney W. Grimes 	FILE *mlfile;
37518fae3551SRodney W. Grimes 	int fnd = 0;
37528fae3551SRodney W. Grimes 
37531da3e8b0SEmmanuel Vadot 	SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) {
37548fae3551SRodney W. Grimes 		if (!strcmp(mlp->ml_host, hostp) &&
37558fae3551SRodney W. Grimes 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
37568fae3551SRodney W. Grimes 			fnd = 1;
37571da3e8b0SEmmanuel Vadot 			SLIST_REMOVE(&mlhead, mlp, mountlist, next);
37581da3e8b0SEmmanuel Vadot 			free((caddr_t)mlp);
37598fae3551SRodney W. Grimes 		}
37608fae3551SRodney W. Grimes 	}
37618fae3551SRodney W. Grimes 	if (fnd) {
37628fae3551SRodney W. Grimes 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
376374853402SPhilippe Charnier 			syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
37648fae3551SRodney W. Grimes 			return;
37658fae3551SRodney W. Grimes 		}
37661da3e8b0SEmmanuel Vadot 		SLIST_FOREACH(mlp, &mlhead, next) {
37678fae3551SRodney W. Grimes 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
37688fae3551SRodney W. Grimes 		}
37698fae3551SRodney W. Grimes 		fclose(mlfile);
37708fae3551SRodney W. Grimes 	}
37718fae3551SRodney W. Grimes }
37728fae3551SRodney W. Grimes 
377319c46d8cSEdward Tomasz Napierala static void
add_mlist(char * hostp,char * dirp)3774a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp)
37758fae3551SRodney W. Grimes {
37761da3e8b0SEmmanuel Vadot 	struct mountlist *mlp;
37778fae3551SRodney W. Grimes 	FILE *mlfile;
37788fae3551SRodney W. Grimes 
37791da3e8b0SEmmanuel Vadot 	SLIST_FOREACH(mlp, &mlhead, next) {
37808fae3551SRodney W. Grimes 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
37818fae3551SRodney W. Grimes 			return;
37828fae3551SRodney W. Grimes 	}
37831da3e8b0SEmmanuel Vadot 
37848fae3551SRodney W. Grimes 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
378574853402SPhilippe Charnier 	if (mlp == (struct mountlist *)NULL)
378674853402SPhilippe Charnier 		out_of_mem();
37870775314bSDoug Rabson 	strncpy(mlp->ml_host, hostp, MNTNAMLEN);
37880775314bSDoug Rabson 	mlp->ml_host[MNTNAMLEN] = '\0';
37890775314bSDoug Rabson 	strncpy(mlp->ml_dirp, dirp, MNTPATHLEN);
37900775314bSDoug Rabson 	mlp->ml_dirp[MNTPATHLEN] = '\0';
37911da3e8b0SEmmanuel Vadot 	SLIST_INSERT_HEAD(&mlhead, mlp, next);
37928fae3551SRodney W. Grimes 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
379374853402SPhilippe Charnier 		syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
37948fae3551SRodney W. Grimes 		return;
37958fae3551SRodney W. Grimes 	}
37968fae3551SRodney W. Grimes 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
37978fae3551SRodney W. Grimes 	fclose(mlfile);
37988fae3551SRodney W. Grimes }
37998fae3551SRodney W. Grimes 
38008fae3551SRodney W. Grimes /*
38018fae3551SRodney W. Grimes  * Free up a group list.
38028fae3551SRodney W. Grimes  */
380319c46d8cSEdward Tomasz Napierala static void
free_grp(struct grouplist * grp)3804a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp)
38058fae3551SRodney W. Grimes {
38068fae3551SRodney W. Grimes 	if (grp->gr_type == GT_HOST) {
38078360efbdSAlfred Perlstein 		if (grp->gr_ptr.gt_addrinfo != NULL)
38088360efbdSAlfred Perlstein 			freeaddrinfo(grp->gr_ptr.gt_addrinfo);
38098fae3551SRodney W. Grimes 	} else if (grp->gr_type == GT_NET) {
38108fae3551SRodney W. Grimes 		if (grp->gr_ptr.gt_net.nt_name)
38118fae3551SRodney W. Grimes 			free(grp->gr_ptr.gt_net.nt_name);
38128fae3551SRodney W. Grimes 	}
38132ffad162SRick Macklem 	if (grp->gr_anon.cr_groups != grp->gr_anon.cr_smallgrps)
38142ffad162SRick Macklem 		free(grp->gr_anon.cr_groups);
38158fae3551SRodney W. Grimes 	free((caddr_t)grp);
38168fae3551SRodney W. Grimes }
38178fae3551SRodney W. Grimes 
38188fae3551SRodney W. Grimes #ifdef DEBUG
381919c46d8cSEdward Tomasz Napierala static void
SYSLOG(int pri,const char * fmt,...)38208fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...)
38218fae3551SRodney W. Grimes {
38228fae3551SRodney W. Grimes 	va_list ap;
38238fae3551SRodney W. Grimes 
38248fae3551SRodney W. Grimes 	va_start(ap, fmt);
38258fae3551SRodney W. Grimes 	vfprintf(stderr, fmt, ap);
38268fae3551SRodney W. Grimes 	va_end(ap);
38278fae3551SRodney W. Grimes }
38288fae3551SRodney W. Grimes #endif /* DEBUG */
38298fae3551SRodney W. Grimes 
38308fae3551SRodney W. Grimes /*
38318fae3551SRodney W. Grimes  * Check options for consistency.
38328fae3551SRodney W. Grimes  */
383319c46d8cSEdward Tomasz Napierala static int
check_options(struct dirlist * dp)3834a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp)
38358fae3551SRodney W. Grimes {
38368fae3551SRodney W. Grimes 
3837bcc1d071SRick Macklem 	if (v4root_phase == 0 && dp == NULL)
38388fae3551SRodney W. Grimes 	    return (1);
383991196234SPeter Wemm 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
384091196234SPeter Wemm 	    syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
38418fae3551SRodney W. Grimes 	    return (1);
38428fae3551SRodney W. Grimes 	}
38438fae3551SRodney W. Grimes 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
384460caaee2SIan Dowse 		syslog(LOG_ERR, "-mask requires -network");
384560caaee2SIan Dowse 		return (1);
384660caaee2SIan Dowse 	}
384760caaee2SIan Dowse 	if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
384860caaee2SIan Dowse 		syslog(LOG_ERR, "-network requires mask specification");
384960caaee2SIan Dowse 		return (1);
385060caaee2SIan Dowse 	}
385160caaee2SIan Dowse 	if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
385260caaee2SIan Dowse 		syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
38538fae3551SRodney W. Grimes 		return (1);
38548fae3551SRodney W. Grimes 	}
3855bcc1d071SRick Macklem 	if (v4root_phase > 0 &&
3856bcc1d071SRick Macklem 	    (opt_flags &
3857bcc1d071SRick Macklem 	     ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) {
3858bcc1d071SRick Macklem 	    syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:");
3859bcc1d071SRick Macklem 	    return (1);
3860bcc1d071SRick Macklem 	}
386156cfc5edSRick Macklem 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
386256cfc5edSRick Macklem 	    syslog(LOG_ERR, "-alldirs has multiple directories");
386356cfc5edSRick Macklem 	    return (1);
386456cfc5edSRick Macklem 	}
38658fae3551SRodney W. Grimes 	return (0);
38668fae3551SRodney W. Grimes }
38678fae3551SRodney W. Grimes 
386819c46d8cSEdward Tomasz Napierala static int
check_path_component(const char * path,char ** err)3869572b77f8SAlexander Motin check_path_component(const char *path, char **err)
38708fae3551SRodney W. Grimes {
38718fae3551SRodney W. Grimes 	struct stat sb;
38728fae3551SRodney W. Grimes 
3873572b77f8SAlexander Motin 	if (lstat(path, &sb)) {
3874572b77f8SAlexander Motin 		asprintf(err, "%s: lstat() failed: %s.\n",
3875572b77f8SAlexander Motin 		    path, strerror(errno));
3876572b77f8SAlexander Motin 		return (0);
3877572b77f8SAlexander Motin 	}
3878572b77f8SAlexander Motin 
3879572b77f8SAlexander Motin 	switch (sb.st_mode & S_IFMT) {
3880572b77f8SAlexander Motin 	case S_IFDIR:
3881572b77f8SAlexander Motin 		return (1);
3882572b77f8SAlexander Motin 	case S_IFLNK:
3883572b77f8SAlexander Motin 		asprintf(err, "%s: path is a symbolic link.\n", path);
3884572b77f8SAlexander Motin 		break;
3885572b77f8SAlexander Motin 	case S_IFREG:
3886572b77f8SAlexander Motin 		asprintf(err, "%s: path is a file rather than a directory.\n",
3887572b77f8SAlexander Motin 		    path);
3888572b77f8SAlexander Motin 		break;
3889572b77f8SAlexander Motin 	default:
3890572b77f8SAlexander Motin 		asprintf(err, "%s: path is not a directory.\n", path);
3891572b77f8SAlexander Motin 	}
3892572b77f8SAlexander Motin 
3893572b77f8SAlexander Motin 	return (0);
3894572b77f8SAlexander Motin }
3895572b77f8SAlexander Motin 
3896572b77f8SAlexander Motin /*
3897572b77f8SAlexander Motin  * Check each path component for the presence of symbolic links. Return true
3898572b77f8SAlexander Motin  */
3899572b77f8SAlexander Motin static int
check_dirpath(char * dirp,char ** err)3900572b77f8SAlexander Motin check_dirpath(char *dirp, char **err)
3901572b77f8SAlexander Motin {
3902572b77f8SAlexander Motin 	char *cp;
3903572b77f8SAlexander Motin 
39048fae3551SRodney W. Grimes 	cp = dirp + 1;
3905572b77f8SAlexander Motin 	while (*cp) {
39068fae3551SRodney W. Grimes 		if (*cp == '/') {
39078fae3551SRodney W. Grimes 			*cp = '\0';
3908572b77f8SAlexander Motin 
3909572b77f8SAlexander Motin 			if (!check_path_component(dirp, err)) {
3910572b77f8SAlexander Motin 				*cp = '/';
3911572b77f8SAlexander Motin 				return (0);
3912572b77f8SAlexander Motin 			}
3913572b77f8SAlexander Motin 
39148fae3551SRodney W. Grimes 			*cp = '/';
39158fae3551SRodney W. Grimes 		}
39168fae3551SRodney W. Grimes 		cp++;
39178fae3551SRodney W. Grimes 	}
3918572b77f8SAlexander Motin 
3919572b77f8SAlexander Motin 	if (!check_path_component(dirp, err))
3920572b77f8SAlexander Motin 		return (0);
3921572b77f8SAlexander Motin 
3922572b77f8SAlexander Motin 	return (1);
3923572b77f8SAlexander Motin }
3924572b77f8SAlexander Motin 
3925572b77f8SAlexander Motin /*
3926572b77f8SAlexander Motin  * Populate statfs information. Return true on success.
3927572b77f8SAlexander Motin  */
3928572b77f8SAlexander Motin static int
check_statfs(const char * dirp,struct statfs * fsb,char ** err)3929572b77f8SAlexander Motin check_statfs(const char *dirp, struct statfs *fsb, char **err)
3930572b77f8SAlexander Motin {
3931572b77f8SAlexander Motin 	if (statfs(dirp, fsb)) {
3932572b77f8SAlexander Motin 		asprintf(err, "%s: statfs() failed: %s\n", dirp,
3933572b77f8SAlexander Motin 		    strerror(errno));
3934572b77f8SAlexander Motin 		return (0);
3935572b77f8SAlexander Motin 	}
3936572b77f8SAlexander Motin 
3937572b77f8SAlexander Motin 	return (1);
39388fae3551SRodney W. Grimes }
3939a62dc406SDoug Rabson 
394060caaee2SIan Dowse /*
394160caaee2SIan Dowse  * Make a netmask according to the specified prefix length. The ss_family
394260caaee2SIan Dowse  * and other non-address fields must be initialised before calling this.
394360caaee2SIan Dowse  */
394419c46d8cSEdward Tomasz Napierala static int
makemask(struct sockaddr_storage * ssp,int bitlen)394560caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen)
39468360efbdSAlfred Perlstein {
394760caaee2SIan Dowse 	u_char *p;
394860caaee2SIan Dowse 	int bits, i, len;
39498360efbdSAlfred Perlstein 
395060caaee2SIan Dowse 	if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
395160caaee2SIan Dowse 		return (-1);
395289fdc4e1SMike Barcroft 	if (bitlen > len * CHAR_BIT)
395360caaee2SIan Dowse 		return (-1);
39548360efbdSAlfred Perlstein 
395560caaee2SIan Dowse 	for (i = 0; i < len; i++) {
3956a175f065SMarcelo Araujo 		bits = MIN(CHAR_BIT, bitlen);
395758202d89SRuslan Ermilov 		*p++ = (u_char)~0 << (CHAR_BIT - bits);
395860caaee2SIan Dowse 		bitlen -= bits;
39598360efbdSAlfred Perlstein 	}
39608360efbdSAlfred Perlstein 	return 0;
39618360efbdSAlfred Perlstein }
39628360efbdSAlfred Perlstein 
396360caaee2SIan Dowse /*
396460caaee2SIan Dowse  * Check that the sockaddr is a valid netmask. Returns 0 if the mask
396560caaee2SIan Dowse  * is acceptable (i.e. of the form 1...10....0).
396660caaee2SIan Dowse  */
396719c46d8cSEdward Tomasz Napierala static int
checkmask(struct sockaddr * sa)396860caaee2SIan Dowse checkmask(struct sockaddr *sa)
39698360efbdSAlfred Perlstein {
397060caaee2SIan Dowse 	u_char *mask;
397160caaee2SIan Dowse 	int i, len;
397260caaee2SIan Dowse 
397360caaee2SIan Dowse 	if ((mask = sa_rawaddr(sa, &len)) == NULL)
397460caaee2SIan Dowse 		return (-1);
397560caaee2SIan Dowse 
397660caaee2SIan Dowse 	for (i = 0; i < len; i++)
397760caaee2SIan Dowse 		if (mask[i] != 0xff)
397860caaee2SIan Dowse 			break;
397960caaee2SIan Dowse 	if (i < len) {
398060caaee2SIan Dowse 		if (~mask[i] & (u_char)(~mask[i] + 1))
398160caaee2SIan Dowse 			return (-1);
398260caaee2SIan Dowse 		i++;
398360caaee2SIan Dowse 	}
398460caaee2SIan Dowse 	for (; i < len; i++)
398560caaee2SIan Dowse 		if (mask[i] != 0)
398660caaee2SIan Dowse 			return (-1);
398760caaee2SIan Dowse 	return (0);
398860caaee2SIan Dowse }
398960caaee2SIan Dowse 
399060caaee2SIan Dowse /*
399160caaee2SIan Dowse  * Compare two sockaddrs according to a specified mask. Return zero if
399260caaee2SIan Dowse  * `sa1' matches `sa2' when filtered by the netmask in `samask'.
39933df5ecacSUlrich Spörlein  * If samask is NULL, perform a full comparison.
399460caaee2SIan Dowse  */
399519c46d8cSEdward Tomasz Napierala static int
sacmp(struct sockaddr * sa1,struct sockaddr * sa2,struct sockaddr * samask)399660caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
399760caaee2SIan Dowse {
399860caaee2SIan Dowse 	unsigned char *p1, *p2, *mask;
399960caaee2SIan Dowse 	int len, i;
400060caaee2SIan Dowse 
400160caaee2SIan Dowse 	if (sa1->sa_family != sa2->sa_family ||
400260caaee2SIan Dowse 	    (p1 = sa_rawaddr(sa1, &len)) == NULL ||
400360caaee2SIan Dowse 	    (p2 = sa_rawaddr(sa2, NULL)) == NULL)
400460caaee2SIan Dowse 		return (1);
400560caaee2SIan Dowse 
400660caaee2SIan Dowse 	switch (sa1->sa_family) {
400760caaee2SIan Dowse 	case AF_INET6:
400860caaee2SIan Dowse 		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
400960caaee2SIan Dowse 		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
401060caaee2SIan Dowse 			return (1);
401160caaee2SIan Dowse 		break;
401260caaee2SIan Dowse 	}
401360caaee2SIan Dowse 
401460caaee2SIan Dowse 	/* Simple binary comparison if no mask specified. */
401560caaee2SIan Dowse 	if (samask == NULL)
401660caaee2SIan Dowse 		return (memcmp(p1, p2, len));
401760caaee2SIan Dowse 
401860caaee2SIan Dowse 	/* Set up the mask, and do a mask-based comparison. */
401960caaee2SIan Dowse 	if (sa1->sa_family != samask->sa_family ||
402060caaee2SIan Dowse 	    (mask = sa_rawaddr(samask, NULL)) == NULL)
402160caaee2SIan Dowse 		return (1);
402260caaee2SIan Dowse 
402360caaee2SIan Dowse 	for (i = 0; i < len; i++)
402460caaee2SIan Dowse 		if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
402560caaee2SIan Dowse 			return (1);
402660caaee2SIan Dowse 	return (0);
402760caaee2SIan Dowse }
402860caaee2SIan Dowse 
402960caaee2SIan Dowse /*
403060caaee2SIan Dowse  * Return a pointer to the part of the sockaddr that contains the
403160caaee2SIan Dowse  * raw address, and set *nbytes to its length in bytes. Returns
403260caaee2SIan Dowse  * NULL if the address family is unknown.
403360caaee2SIan Dowse  */
403419c46d8cSEdward Tomasz Napierala static void *
sa_rawaddr(struct sockaddr * sa,int * nbytes)403560caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) {
403660caaee2SIan Dowse 	void *p;
403760caaee2SIan Dowse 	int len;
40388360efbdSAlfred Perlstein 
40398360efbdSAlfred Perlstein 	switch (sa->sa_family) {
40408360efbdSAlfred Perlstein 	case AF_INET:
404160caaee2SIan Dowse 		len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
404260caaee2SIan Dowse 		p = &((struct sockaddr_in *)sa)->sin_addr;
40438360efbdSAlfred Perlstein 		break;
40448360efbdSAlfred Perlstein 	case AF_INET6:
404560caaee2SIan Dowse 		len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
404660caaee2SIan Dowse 		p = &((struct sockaddr_in6 *)sa)->sin6_addr;
40478360efbdSAlfred Perlstein 		break;
40488360efbdSAlfred Perlstein 	default:
404960caaee2SIan Dowse 		p = NULL;
405060caaee2SIan Dowse 		len = 0;
40518360efbdSAlfred Perlstein 	}
40528360efbdSAlfred Perlstein 
405360caaee2SIan Dowse 	if (nbytes != NULL)
405460caaee2SIan Dowse 		*nbytes = len;
405560caaee2SIan Dowse 	return (p);
40568360efbdSAlfred Perlstein }
40578360efbdSAlfred Perlstein 
405819c46d8cSEdward Tomasz Napierala static void
huphandler(int sig __unused)4059a7a7d96cSPhilippe Charnier huphandler(int sig __unused)
406069d65572SIan Dowse {
406119c46d8cSEdward Tomasz Napierala 
406269d65572SIan Dowse 	got_sighup = 1;
406369d65572SIan Dowse }
406469d65572SIan Dowse 
406519c46d8cSEdward Tomasz Napierala static void
terminate(int sig __unused)406619c46d8cSEdward Tomasz Napierala terminate(int sig __unused)
40678360efbdSAlfred Perlstein {
4068a032b226SPawel Jakub Dawidek 	pidfile_remove(pfh);
40690775314bSDoug Rabson 	rpcb_unset(MOUNTPROG, MOUNTVERS, NULL);
40700775314bSDoug Rabson 	rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL);
40718360efbdSAlfred Perlstein 	exit (0);
40728360efbdSAlfred Perlstein }
4073cc5efddeSRick Macklem 
4074cc5efddeSRick Macklem static void
cp_cred(struct expcred * outcr,struct expcred * incr)4075cc5efddeSRick Macklem cp_cred(struct expcred *outcr, struct expcred *incr)
4076cc5efddeSRick Macklem {
4077cc5efddeSRick Macklem 
4078cc5efddeSRick Macklem 	outcr->cr_uid = incr->cr_uid;
4079cc5efddeSRick Macklem 	outcr->cr_ngroups = incr->cr_ngroups;
40802ffad162SRick Macklem 	if (outcr->cr_ngroups > SMALLNGROUPS)
40812ffad162SRick Macklem 		outcr->cr_groups = malloc(outcr->cr_ngroups * sizeof(gid_t));
40822ffad162SRick Macklem 	else
40832ffad162SRick Macklem 		outcr->cr_groups = outcr->cr_smallgrps;
4084cc5efddeSRick Macklem 	memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups *
4085cc5efddeSRick Macklem 	    sizeof(gid_t));
4086cc5efddeSRick Macklem }
4087