xref: /freebsd/usr.sbin/mountd/mountd.c (revision d11e36457b60efdaa3155b4dd72347f907da28e7)
18fae3551SRodney W. Grimes /*
28fae3551SRodney W. Grimes  * Copyright (c) 1989, 1993
38fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
48fae3551SRodney W. Grimes  *
58fae3551SRodney W. Grimes  * This code is derived from software contributed to Berkeley by
68fae3551SRodney W. Grimes  * Herb Hasler and Rick Macklem at The University of Guelph.
78fae3551SRodney W. Grimes  *
88fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
98fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
108fae3551SRodney W. Grimes  * are met:
118fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
128fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
138fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
148fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
158fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
168fae3551SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
178fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
188fae3551SRodney W. Grimes  *    without specific prior written permission.
198fae3551SRodney W. Grimes  *
208fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
218fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
248fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
258fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
268fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
278fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
288fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
298fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
308fae3551SRodney W. Grimes  * SUCH DAMAGE.
318fae3551SRodney W. Grimes  */
328fae3551SRodney W. Grimes 
338fae3551SRodney W. Grimes #ifndef lint
3474853402SPhilippe Charnier static const char copyright[] =
358fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\
368fae3551SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
37d599144dSGarrett Wollman #endif /*not lint*/
388fae3551SRodney W. Grimes 
3974853402SPhilippe Charnier #if 0
4075201fa4SPhilippe Charnier #ifndef lint
4174853402SPhilippe Charnier static char sccsid[] = "@(#)mountd.c	8.15 (Berkeley) 5/1/95";
42d599144dSGarrett Wollman #endif /*not lint*/
4375201fa4SPhilippe Charnier #endif
4475201fa4SPhilippe Charnier 
4575201fa4SPhilippe Charnier #include <sys/cdefs.h>
4675201fa4SPhilippe Charnier __FBSDID("$FreeBSD$");
478fae3551SRodney W. Grimes 
488fae3551SRodney W. Grimes #include <sys/param.h>
498fae3551SRodney W. Grimes #include <sys/mount.h>
508360efbdSAlfred Perlstein #include <sys/fcntl.h>
518fae3551SRodney W. Grimes #include <sys/stat.h>
528fae3551SRodney W. Grimes #include <sys/syslog.h>
53394da4c1SGuido van Rooij #include <sys/sysctl.h>
5491ca1a91SIan Dowse #include <sys/linker.h>
5591ca1a91SIan Dowse #include <sys/module.h>
568fae3551SRodney W. Grimes 
578fae3551SRodney W. Grimes #include <rpc/rpc.h>
58bcb53b16SMartin Blapp #include <rpc/rpc_com.h>
598fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h>
608360efbdSAlfred Perlstein #include <rpc/pmap_prot.h>
618360efbdSAlfred Perlstein #include <rpcsvc/mount.h>
628fae3551SRodney W. Grimes #include <nfs/rpcv2.h>
63a62dc406SDoug Rabson #include <nfs/nfsproto.h>
6491196234SPeter Wemm #include <nfsserver/nfs.h>
658fae3551SRodney W. Grimes 
668fae3551SRodney W. Grimes #include <arpa/inet.h>
678fae3551SRodney W. Grimes 
688fae3551SRodney W. Grimes #include <ctype.h>
6974853402SPhilippe Charnier #include <err.h>
708fae3551SRodney W. Grimes #include <errno.h>
718fae3551SRodney W. Grimes #include <grp.h>
72a032b226SPawel Jakub Dawidek #include <libutil.h>
7389fdc4e1SMike Barcroft #include <limits.h>
748fae3551SRodney W. Grimes #include <netdb.h>
758fae3551SRodney W. Grimes #include <pwd.h>
768fae3551SRodney W. Grimes #include <signal.h>
778fae3551SRodney W. Grimes #include <stdio.h>
788fae3551SRodney W. Grimes #include <stdlib.h>
798fae3551SRodney W. Grimes #include <string.h>
808fae3551SRodney W. Grimes #include <unistd.h>
818fae3551SRodney W. Grimes #include "pathnames.h"
826a09faf2SCraig Rodrigues #include "mntopts.h"
838fae3551SRodney W. Grimes 
848fae3551SRodney W. Grimes #ifdef DEBUG
858fae3551SRodney W. Grimes #include <stdarg.h>
868fae3551SRodney W. Grimes #endif
878fae3551SRodney W. Grimes 
888fae3551SRodney W. Grimes /*
898fae3551SRodney W. Grimes  * Structures for keeping the mount list and export list
908fae3551SRodney W. Grimes  */
918fae3551SRodney W. Grimes struct mountlist {
928fae3551SRodney W. Grimes 	struct mountlist *ml_next;
938fae3551SRodney W. Grimes 	char	ml_host[RPCMNT_NAMELEN+1];
948fae3551SRodney W. Grimes 	char	ml_dirp[RPCMNT_PATHLEN+1];
958fae3551SRodney W. Grimes };
968fae3551SRodney W. Grimes 
978fae3551SRodney W. Grimes struct dirlist {
988fae3551SRodney W. Grimes 	struct dirlist	*dp_left;
998fae3551SRodney W. Grimes 	struct dirlist	*dp_right;
1008fae3551SRodney W. Grimes 	int		dp_flag;
1018fae3551SRodney W. Grimes 	struct hostlist	*dp_hosts;	/* List of hosts this dir exported to */
1028fae3551SRodney W. Grimes 	char		dp_dirp[1];	/* Actually malloc'd to size of dir */
1038fae3551SRodney W. Grimes };
1048fae3551SRodney W. Grimes /* dp_flag bits */
1058fae3551SRodney W. Grimes #define	DP_DEFSET	0x1
106a62dc406SDoug Rabson #define DP_HOSTSET	0x2
1078fae3551SRodney W. Grimes 
1088fae3551SRodney W. Grimes struct exportlist {
1098fae3551SRodney W. Grimes 	struct exportlist *ex_next;
1108fae3551SRodney W. Grimes 	struct dirlist	*ex_dirl;
1118fae3551SRodney W. Grimes 	struct dirlist	*ex_defdir;
1128fae3551SRodney W. Grimes 	int		ex_flag;
1138fae3551SRodney W. Grimes 	fsid_t		ex_fs;
1148fae3551SRodney W. Grimes 	char		*ex_fsdir;
115cb3923e0SDoug Rabson 	char		*ex_indexfile;
1168fae3551SRodney W. Grimes };
1178fae3551SRodney W. Grimes /* ex_flag bits */
1188fae3551SRodney W. Grimes #define	EX_LINKED	0x1
1198fae3551SRodney W. Grimes 
1208fae3551SRodney W. Grimes struct netmsk {
1218360efbdSAlfred Perlstein 	struct sockaddr_storage nt_net;
12260caaee2SIan Dowse 	struct sockaddr_storage nt_mask;
1238fae3551SRodney W. Grimes 	char		*nt_name;
1248fae3551SRodney W. Grimes };
1258fae3551SRodney W. Grimes 
1268fae3551SRodney W. Grimes union grouptypes {
1278360efbdSAlfred Perlstein 	struct addrinfo *gt_addrinfo;
1288fae3551SRodney W. Grimes 	struct netmsk	gt_net;
1298fae3551SRodney W. Grimes };
1308fae3551SRodney W. Grimes 
1318fae3551SRodney W. Grimes struct grouplist {
1328fae3551SRodney W. Grimes 	int gr_type;
1338fae3551SRodney W. Grimes 	union grouptypes gr_ptr;
1348fae3551SRodney W. Grimes 	struct grouplist *gr_next;
1358fae3551SRodney W. Grimes };
1368fae3551SRodney W. Grimes /* Group types */
1378fae3551SRodney W. Grimes #define	GT_NULL		0x0
1388fae3551SRodney W. Grimes #define	GT_HOST		0x1
1398fae3551SRodney W. Grimes #define	GT_NET		0x2
1406d359f31SIan Dowse #define	GT_DEFAULT	0x3
1418b5a6d67SBill Paul #define GT_IGNORE	0x5
1428fae3551SRodney W. Grimes 
1438fae3551SRodney W. Grimes struct hostlist {
144a62dc406SDoug Rabson 	int		 ht_flag;	/* Uses DP_xx bits */
1458fae3551SRodney W. Grimes 	struct grouplist *ht_grp;
1468fae3551SRodney W. Grimes 	struct hostlist	 *ht_next;
1478fae3551SRodney W. Grimes };
1488fae3551SRodney W. Grimes 
149a62dc406SDoug Rabson struct fhreturn {
150a62dc406SDoug Rabson 	int	fhr_flag;
151a62dc406SDoug Rabson 	int	fhr_vers;
152a62dc406SDoug Rabson 	nfsfh_t	fhr_fh;
153a62dc406SDoug Rabson };
154a62dc406SDoug Rabson 
1558fae3551SRodney W. Grimes /* Global defs */
15685429990SWarner Losh char	*add_expdir(struct dirlist **, char *, int);
15785429990SWarner Losh void	add_dlist(struct dirlist **, struct dirlist *,
15885429990SWarner Losh 				struct grouplist *, int);
15985429990SWarner Losh void	add_mlist(char *, char *);
16085429990SWarner Losh int	check_dirpath(char *);
16185429990SWarner Losh int	check_options(struct dirlist *);
16260caaee2SIan Dowse int	checkmask(struct sockaddr *sa);
16385429990SWarner Losh int	chk_host(struct dirlist *, struct sockaddr *, int *, int *);
164d11e3645SMatteo Riondato void	create_service(struct netconfig *nconf);
16501709abfSIan Dowse void	del_mlist(char *hostp, char *dirp);
16685429990SWarner Losh struct dirlist *dirp_search(struct dirlist *, char *);
16785429990SWarner Losh int	do_mount(struct exportlist *, struct grouplist *, int,
16885429990SWarner Losh 		struct xucred *, char *, int, struct statfs *);
16985429990SWarner Losh int	do_opt(char **, char **, struct exportlist *, struct grouplist *,
17085429990SWarner Losh 				int *, int *, struct xucred *);
17185429990SWarner Losh struct	exportlist *ex_search(fsid_t *);
17285429990SWarner Losh struct	exportlist *get_exp(void);
17385429990SWarner Losh void	free_dir(struct dirlist *);
17485429990SWarner Losh void	free_exp(struct exportlist *);
17585429990SWarner Losh void	free_grp(struct grouplist *);
17685429990SWarner Losh void	free_host(struct hostlist *);
17785429990SWarner Losh void	get_exportlist(void);
17885429990SWarner Losh int	get_host(char *, struct grouplist *, struct grouplist *);
17985429990SWarner Losh struct hostlist *get_ht(void);
18085429990SWarner Losh int	get_line(void);
18185429990SWarner Losh void	get_mountlist(void);
18285429990SWarner Losh int	get_net(char *, struct netmsk *, int);
18385429990SWarner Losh void	getexp_err(struct exportlist *, struct grouplist *);
18485429990SWarner Losh struct grouplist *get_grp(void);
18585429990SWarner Losh void	hang_dirp(struct dirlist *, struct grouplist *,
18685429990SWarner Losh 				struct exportlist *, int);
18769d65572SIan Dowse void	huphandler(int sig);
18860caaee2SIan Dowse int	makemask(struct sockaddr_storage *ssp, int bitlen);
18985429990SWarner Losh void	mntsrv(struct svc_req *, SVCXPRT *);
19085429990SWarner Losh void	nextfield(char **, char **);
19185429990SWarner Losh void	out_of_mem(void);
19285429990SWarner Losh void	parsecred(char *, struct xucred *);
19391acb349SAlfred Perlstein int	put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int);
19460caaee2SIan Dowse void	*sa_rawaddr(struct sockaddr *sa, int *nbytes);
19560caaee2SIan Dowse int	sacmp(struct sockaddr *sa1, struct sockaddr *sa2,
19660caaee2SIan Dowse     struct sockaddr *samask);
19785429990SWarner Losh int	scan_tree(struct dirlist *, struct sockaddr *);
19885429990SWarner Losh static void usage(void);
19985429990SWarner Losh int	xdr_dir(XDR *, char *);
20085429990SWarner Losh int	xdr_explist(XDR *, caddr_t);
20191acb349SAlfred Perlstein int	xdr_explist_brief(XDR *, caddr_t);
20285429990SWarner Losh int	xdr_fhs(XDR *, caddr_t);
20385429990SWarner Losh int	xdr_mlist(XDR *, caddr_t);
20485429990SWarner Losh void	terminate(int);
2058fae3551SRodney W. Grimes 
2068fae3551SRodney W. Grimes struct exportlist *exphead;
2078fae3551SRodney W. Grimes struct mountlist *mlhead;
2088fae3551SRodney W. Grimes struct grouplist *grphead;
20996968c22SPawel Jakub Dawidek char *exnames_default[2] = { _PATH_EXPORTS, NULL };
21096968c22SPawel Jakub Dawidek char **exnames;
211d11e3645SMatteo Riondato char **hosts = NULL;
212c0511d3bSBrian Feldman struct xucred def_anon = {
21376183f34SDima Dorfman 	XUCRED_VERSION,
2148fae3551SRodney W. Grimes 	(uid_t)-2,
2158fae3551SRodney W. Grimes 	1,
216c0511d3bSBrian Feldman 	{ (gid_t)-2 },
217c0511d3bSBrian Feldman 	NULL
2188fae3551SRodney W. Grimes };
2192a66cfc5SDoug Rabson int force_v2 = 0;
220a62dc406SDoug Rabson int resvport_only = 1;
221d11e3645SMatteo Riondato int nhosts = 0;
222a62dc406SDoug Rabson int dir_only = 1;
223c903443aSPeter Wemm int dolog = 0;
22469d65572SIan Dowse int got_sighup = 0;
225d11e3645SMatteo Riondato int xcreated = 0;
226d11e3645SMatteo Riondato 
227d11e3645SMatteo Riondato char *svcport_str = NULL;
2288360efbdSAlfred Perlstein 
2298fae3551SRodney W. Grimes int opt_flags;
2308360efbdSAlfred Perlstein static int have_v6 = 1;
2318360efbdSAlfred Perlstein 
232a032b226SPawel Jakub Dawidek struct pidfh *pfh = NULL;
23360caaee2SIan Dowse /* Bits for opt_flags above */
2348fae3551SRodney W. Grimes #define	OP_MAPROOT	0x01
2358fae3551SRodney W. Grimes #define	OP_MAPALL	0x02
23691196234SPeter Wemm /* 0x4 free */
2378fae3551SRodney W. Grimes #define	OP_MASK		0x08
2388fae3551SRodney W. Grimes #define	OP_NET		0x10
2398fae3551SRodney W. Grimes #define	OP_ALLDIRS	0x40
24060caaee2SIan Dowse #define	OP_HAVEMASK	0x80	/* A mask was specified or inferred. */
241288fa14aSJoerg Wunsch #define	OP_QUIET	0x100
2428360efbdSAlfred Perlstein #define OP_MASKLEN	0x200
2438fae3551SRodney W. Grimes 
2448fae3551SRodney W. Grimes #ifdef DEBUG
2458fae3551SRodney W. Grimes int debug = 1;
24685429990SWarner Losh void	SYSLOG(int, const char *, ...) __printflike(2, 3);
2478fae3551SRodney W. Grimes #define syslog SYSLOG
2488fae3551SRodney W. Grimes #else
2498fae3551SRodney W. Grimes int debug = 0;
2508fae3551SRodney W. Grimes #endif
2518fae3551SRodney W. Grimes 
2528fae3551SRodney W. Grimes /*
2538fae3551SRodney W. Grimes  * Mountd server for NFS mount protocol as described in:
2548fae3551SRodney W. Grimes  * NFS: Network File System Protocol Specification, RFC1094, Appendix A
2558fae3551SRodney W. Grimes  * The optional arguments are the exports file name
2568fae3551SRodney W. Grimes  * default: _PATH_EXPORTS
2578fae3551SRodney W. Grimes  * and "-n" to allow nonroot mount.
2588fae3551SRodney W. Grimes  */
2598fae3551SRodney W. Grimes int
2608fae3551SRodney W. Grimes main(argc, argv)
2618fae3551SRodney W. Grimes 	int argc;
2628fae3551SRodney W. Grimes 	char **argv;
2638fae3551SRodney W. Grimes {
26469d65572SIan Dowse 	fd_set readfds;
265d11e3645SMatteo Riondato 	struct netconfig *nconf;
266d11e3645SMatteo Riondato 	char *endptr, **hosts_bak;
267d11e3645SMatteo Riondato 	void *nc_handle;
268a032b226SPawel Jakub Dawidek 	pid_t otherpid;
269d11e3645SMatteo Riondato 	in_port_t svcport;
270d11e3645SMatteo Riondato 	int c, k, s;
271bcb53b16SMartin Blapp 	int maxrec = RPC_MAXDATASIZE;
2728360efbdSAlfred Perlstein 
27301709abfSIan Dowse 	/* Check that another mountd isn't already running. */
2748b28aef2SPawel Jakub Dawidek 	pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid);
275a032b226SPawel Jakub Dawidek 	if (pfh == NULL) {
276a032b226SPawel Jakub Dawidek 		if (errno == EEXIST)
277a032b226SPawel Jakub Dawidek 			errx(1, "mountd already running, pid: %d.", otherpid);
278a032b226SPawel Jakub Dawidek 		warn("cannot open or create pidfile");
279a032b226SPawel Jakub Dawidek 	}
2808360efbdSAlfred Perlstein 
2818360efbdSAlfred Perlstein 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
2828360efbdSAlfred Perlstein 	if (s < 0)
2838360efbdSAlfred Perlstein 		have_v6 = 0;
2848360efbdSAlfred Perlstein 	else
2858360efbdSAlfred Perlstein 		close(s);
2864a0785aaSPeter Wemm 	if (modfind("nfsserver") < 0) {
2874a0785aaSPeter Wemm 		/* Not present in kernel, try loading it */
2884a0785aaSPeter Wemm 		if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0)
2894a0785aaSPeter Wemm 			errx(1, "NFS server is not available or loadable");
290d599144dSGarrett Wollman 	}
2918fae3551SRodney W. Grimes 
292d11e3645SMatteo Riondato 	while ((c = getopt(argc, argv, "2dh:lnp:r")) != -1)
2938fae3551SRodney W. Grimes 		switch (c) {
2942a66cfc5SDoug Rabson 		case '2':
2952a66cfc5SDoug Rabson 			force_v2 = 1;
2962a66cfc5SDoug Rabson 			break;
297a62dc406SDoug Rabson 		case 'n':
298a62dc406SDoug Rabson 			resvport_only = 0;
299a62dc406SDoug Rabson 			break;
300a62dc406SDoug Rabson 		case 'r':
301a62dc406SDoug Rabson 			dir_only = 0;
302a62dc406SDoug Rabson 			break;
3036444ef3bSPoul-Henning Kamp 		case 'd':
3046444ef3bSPoul-Henning Kamp 			debug = debug ? 0 : 1;
3056444ef3bSPoul-Henning Kamp 			break;
306f51631d7SGuido van Rooij 		case 'l':
307c903443aSPeter Wemm 			dolog = 1;
308f51631d7SGuido van Rooij 			break;
309c203da27SBruce M Simpson 		case 'p':
310c203da27SBruce M Simpson 			endptr = NULL;
311c203da27SBruce M Simpson 			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
312c203da27SBruce M Simpson 			if (endptr == NULL || *endptr != '\0' ||
313c203da27SBruce M Simpson 			    svcport == 0 || svcport >= IPPORT_MAX)
314c203da27SBruce M Simpson 				usage();
315d11e3645SMatteo Riondato 			svcport_str = strdup(optarg);
316d11e3645SMatteo Riondato 			break;
317d11e3645SMatteo Riondato 		case 'h':
318d11e3645SMatteo Riondato 			++nhosts;
319d11e3645SMatteo Riondato 			hosts_bak = hosts;
320d11e3645SMatteo Riondato 			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
321d11e3645SMatteo Riondato 			if (hosts_bak == NULL) {
322d11e3645SMatteo Riondato 				if (hosts != NULL) {
323d11e3645SMatteo Riondato 					for (k = 0; k < nhosts; k++)
324d11e3645SMatteo Riondato 						free(hosts[k]);
325d11e3645SMatteo Riondato 					free(hosts);
326d11e3645SMatteo Riondato 					out_of_mem();
327d11e3645SMatteo Riondato 				}
328d11e3645SMatteo Riondato 			}
329d11e3645SMatteo Riondato 			hosts = hosts_bak;
330d11e3645SMatteo Riondato 			hosts[nhosts - 1] = strdup(optarg);
331d11e3645SMatteo Riondato 			if (hosts[nhosts - 1] == NULL) {
332d11e3645SMatteo Riondato 				for (k = 0; k < (nhosts - 1); k++)
333d11e3645SMatteo Riondato 					free(hosts[k]);
334d11e3645SMatteo Riondato 				free(hosts);
335d11e3645SMatteo Riondato 				out_of_mem();
336d11e3645SMatteo Riondato 			}
337c203da27SBruce M Simpson 			break;
3388fae3551SRodney W. Grimes 		default:
33974853402SPhilippe Charnier 			usage();
3408fae3551SRodney W. Grimes 		};
3418fae3551SRodney W. Grimes 	argc -= optind;
3428fae3551SRodney W. Grimes 	argv += optind;
3438fae3551SRodney W. Grimes 	grphead = (struct grouplist *)NULL;
3448fae3551SRodney W. Grimes 	exphead = (struct exportlist *)NULL;
3458fae3551SRodney W. Grimes 	mlhead = (struct mountlist *)NULL;
34696968c22SPawel Jakub Dawidek 	if (argc > 0)
34796968c22SPawel Jakub Dawidek 		exnames = argv;
34896968c22SPawel Jakub Dawidek 	else
34996968c22SPawel Jakub Dawidek 		exnames = exnames_default;
3508fae3551SRodney W. Grimes 	openlog("mountd", LOG_PID, LOG_DAEMON);
3518fae3551SRodney W. Grimes 	if (debug)
35274853402SPhilippe Charnier 		warnx("getting export list");
3538fae3551SRodney W. Grimes 	get_exportlist();
3548fae3551SRodney W. Grimes 	if (debug)
35574853402SPhilippe Charnier 		warnx("getting mount list");
3568fae3551SRodney W. Grimes 	get_mountlist();
3578fae3551SRodney W. Grimes 	if (debug)
35874853402SPhilippe Charnier 		warnx("here we go");
3598fae3551SRodney W. Grimes 	if (debug == 0) {
3608fae3551SRodney W. Grimes 		daemon(0, 0);
3618fae3551SRodney W. Grimes 		signal(SIGINT, SIG_IGN);
3628fae3551SRodney W. Grimes 		signal(SIGQUIT, SIG_IGN);
3638fae3551SRodney W. Grimes 	}
36469d65572SIan Dowse 	signal(SIGHUP, huphandler);
3658360efbdSAlfred Perlstein 	signal(SIGTERM, terminate);
36609fc9dc6SCraig Rodrigues 	signal(SIGPIPE, SIG_IGN);
367a032b226SPawel Jakub Dawidek 
368a032b226SPawel Jakub Dawidek 	pidfile_write(pfh);
369a032b226SPawel Jakub Dawidek 
3708360efbdSAlfred Perlstein 	rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
3718360efbdSAlfred Perlstein 	rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
372bcb53b16SMartin Blapp 	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
373bcb53b16SMartin Blapp 
374c6e5e158SGuido van Rooij 	if (!resvport_only) {
3754a0785aaSPeter Wemm 		if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL,
3764a0785aaSPeter Wemm 		    &resvport_only, sizeof(resvport_only)) != 0 &&
3774a0785aaSPeter Wemm 		    errno != ENOENT) {
378394da4c1SGuido van Rooij 			syslog(LOG_ERR, "sysctl: %m");
379394da4c1SGuido van Rooij 			exit(1);
380394da4c1SGuido van Rooij 		}
381c6e5e158SGuido van Rooij 	}
382c203da27SBruce M Simpson 
383d11e3645SMatteo Riondato 	/*
384d11e3645SMatteo Riondato 	 * If no hosts were specified, add a wildcard entry to bind to
385d11e3645SMatteo Riondato 	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
386d11e3645SMatteo Riondato 	 * list.
387d11e3645SMatteo Riondato 	 */
388d11e3645SMatteo Riondato 	if (nhosts == 0) {
389d11e3645SMatteo Riondato 		hosts = malloc(sizeof(char**));
390d11e3645SMatteo Riondato 		if (hosts == NULL)
391d11e3645SMatteo Riondato 			out_of_mem();
392d11e3645SMatteo Riondato 		hosts[0] = "*";
393d11e3645SMatteo Riondato 		nhosts = 1;
394d11e3645SMatteo Riondato 	} else {
395d11e3645SMatteo Riondato 		hosts_bak = hosts;
396d11e3645SMatteo Riondato 		if (have_v6) {
397d11e3645SMatteo Riondato 			hosts_bak = realloc(hosts, (nhosts + 2) *
398d11e3645SMatteo Riondato 			    sizeof(char *));
399d11e3645SMatteo Riondato 			if (hosts_bak == NULL) {
400d11e3645SMatteo Riondato 				for (k = 0; k < nhosts; k++)
401d11e3645SMatteo Riondato 					free(hosts[k]);
402d11e3645SMatteo Riondato 		    		free(hosts);
403d11e3645SMatteo Riondato 		    		out_of_mem();
404c203da27SBruce M Simpson 			} else
405d11e3645SMatteo Riondato 				hosts = hosts_bak;
406d11e3645SMatteo Riondato 			nhosts += 2;
407d11e3645SMatteo Riondato 			hosts[nhosts - 2] = "::1";
408d11e3645SMatteo Riondato 		} else {
409d11e3645SMatteo Riondato 			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
410d11e3645SMatteo Riondato 			if (hosts_bak == NULL) {
411d11e3645SMatteo Riondato 				for (k = 0; k < nhosts; k++)
412d11e3645SMatteo Riondato 					free(hosts[k]);
413d11e3645SMatteo Riondato 				free(hosts);
414d11e3645SMatteo Riondato 				out_of_mem();
415d11e3645SMatteo Riondato 			} else {
416d11e3645SMatteo Riondato 				nhosts += 1;
417d11e3645SMatteo Riondato 				hosts = hosts_bak;
4188fae3551SRodney W. Grimes 			}
419d11e3645SMatteo Riondato 		}
4208360efbdSAlfred Perlstein 
421d11e3645SMatteo Riondato 		hosts[nhosts - 1] = "127.0.0.1";
4228360efbdSAlfred Perlstein 	}
4238360efbdSAlfred Perlstein 
424d11e3645SMatteo Riondato 	nc_handle = setnetconfig();
425d11e3645SMatteo Riondato 	while ((nconf = getnetconfig(nc_handle))) {
426d11e3645SMatteo Riondato 		if (nconf->nc_flag & NC_VISIBLE) {
427d11e3645SMatteo Riondato 			if (have_v6 == 0 && strcmp(nconf->nc_protofmly,
428d11e3645SMatteo Riondato 			    "inet6") == 0) {
429d11e3645SMatteo Riondato 				/* DO NOTHING */
430c203da27SBruce M Simpson 			} else
431d11e3645SMatteo Riondato 				create_service(nconf);
4328360efbdSAlfred Perlstein 		}
433d11e3645SMatteo Riondato 	}
434d11e3645SMatteo Riondato 	endnetconfig(nc_handle);
4358360efbdSAlfred Perlstein 
4368360efbdSAlfred Perlstein 	if (xcreated == 0) {
4378360efbdSAlfred Perlstein 		syslog(LOG_ERR, "could not create any services");
4382a66cfc5SDoug Rabson 		exit(1);
4392a66cfc5SDoug Rabson 	}
44069d65572SIan Dowse 
44169d65572SIan Dowse 	/* Expand svc_run() here so that we can call get_exportlist(). */
44269d65572SIan Dowse 	for (;;) {
44369d65572SIan Dowse 		if (got_sighup) {
44469d65572SIan Dowse 			get_exportlist();
44569d65572SIan Dowse 			got_sighup = 0;
44669d65572SIan Dowse 		}
44769d65572SIan Dowse 		readfds = svc_fdset;
44869d65572SIan Dowse 		switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) {
44969d65572SIan Dowse 		case -1:
45069d65572SIan Dowse 			if (errno == EINTR)
45169d65572SIan Dowse                                 continue;
45269d65572SIan Dowse 			syslog(LOG_ERR, "mountd died: select: %m");
45374853402SPhilippe Charnier 			exit(1);
45469d65572SIan Dowse 		case 0:
45569d65572SIan Dowse 			continue;
45669d65572SIan Dowse 		default:
45769d65572SIan Dowse 			svc_getreqset(&readfds);
45869d65572SIan Dowse 		}
45969d65572SIan Dowse 	}
46074853402SPhilippe Charnier }
46174853402SPhilippe Charnier 
462d11e3645SMatteo Riondato /*
463d11e3645SMatteo Riondato  * This routine creates and binds sockets on the appropriate
464d11e3645SMatteo Riondato  * addresses. It gets called one time for each transport and
465d11e3645SMatteo Riondato  * registrates the service with rpcbind on that trasport.
466d11e3645SMatteo Riondato  */
467d11e3645SMatteo Riondato void
468d11e3645SMatteo Riondato create_service(struct netconfig *nconf)
469d11e3645SMatteo Riondato {
470d11e3645SMatteo Riondato 	struct addrinfo hints, *res = NULL;
471d11e3645SMatteo Riondato 	struct sockaddr_in *sin;
472d11e3645SMatteo Riondato 	struct sockaddr_in6 *sin6;
473d11e3645SMatteo Riondato 	struct __rpc_sockinfo si;
474d11e3645SMatteo Riondato 	struct netbuf servaddr;
475d11e3645SMatteo Riondato 	SVCXPRT	*transp = NULL;
476d11e3645SMatteo Riondato 	int aicode;
477d11e3645SMatteo Riondato 	int fd;
478d11e3645SMatteo Riondato 	int nhostsbak;
479d11e3645SMatteo Riondato 	int one = 1;
480d11e3645SMatteo Riondato 	int r;
481d11e3645SMatteo Riondato 	int registered = 0;
482d11e3645SMatteo Riondato 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
483d11e3645SMatteo Riondato 
484d11e3645SMatteo Riondato 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
485d11e3645SMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS) &&
486d11e3645SMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
487d11e3645SMatteo Riondato 		return;	/* not my type */
488d11e3645SMatteo Riondato 
489d11e3645SMatteo Riondato 	/*
490d11e3645SMatteo Riondato 	 * XXX - using RPC library internal functions.
491d11e3645SMatteo Riondato 	 */
492d11e3645SMatteo Riondato 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
493d11e3645SMatteo Riondato 		syslog(LOG_ERR, "cannot get information for %s",
494d11e3645SMatteo Riondato 		    nconf->nc_netid);
495d11e3645SMatteo Riondato 		return;
496d11e3645SMatteo Riondato 	}
497d11e3645SMatteo Riondato 
498d11e3645SMatteo Riondato 	/* Get mountd's address on this transport */
499d11e3645SMatteo Riondato 	memset(&hints, 0, sizeof hints);
500d11e3645SMatteo Riondato 	hints.ai_flags = AI_PASSIVE;
501d11e3645SMatteo Riondato 	hints.ai_family = si.si_af;
502d11e3645SMatteo Riondato 	hints.ai_socktype = si.si_socktype;
503d11e3645SMatteo Riondato 	hints.ai_protocol = si.si_proto;
504d11e3645SMatteo Riondato 
505d11e3645SMatteo Riondato 	/*
506d11e3645SMatteo Riondato 	 * Bind to specific IPs if asked to
507d11e3645SMatteo Riondato 	 */
508d11e3645SMatteo Riondato 	nhostsbak = nhosts;
509d11e3645SMatteo Riondato 	while (nhostsbak > 0) {
510d11e3645SMatteo Riondato 		--nhostsbak;
511d11e3645SMatteo Riondato 		/*
512d11e3645SMatteo Riondato 		 * XXX - using RPC library internal functions.
513d11e3645SMatteo Riondato 		 */
514d11e3645SMatteo Riondato 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
515d11e3645SMatteo Riondato 			int non_fatal = 0;
516d11e3645SMatteo Riondato 	    		if (errno == EPROTONOSUPPORT &&
517d11e3645SMatteo Riondato 			    nconf->nc_semantics != NC_TPI_CLTS)
518d11e3645SMatteo Riondato 				non_fatal = 1;
519d11e3645SMatteo Riondato 
520d11e3645SMatteo Riondato 			syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
521d11e3645SMatteo Riondato 			    "cannot create socket for %s", nconf->nc_netid);
522d11e3645SMatteo Riondato 	    		return;
523d11e3645SMatteo Riondato 		}
524d11e3645SMatteo Riondato 
525d11e3645SMatteo Riondato 		switch (hints.ai_family) {
526d11e3645SMatteo Riondato 		case AF_INET:
527d11e3645SMatteo Riondato 			if (inet_pton(AF_INET, hosts[nhostsbak],
528d11e3645SMatteo Riondato 			    host_addr) == 1) {
529d11e3645SMatteo Riondato 				hints.ai_flags &= AI_NUMERICHOST;
530d11e3645SMatteo Riondato 			} else {
531d11e3645SMatteo Riondato 				/*
532d11e3645SMatteo Riondato 				 * Skip if we have an AF_INET6 address.
533d11e3645SMatteo Riondato 				 */
534d11e3645SMatteo Riondato 				if (inet_pton(AF_INET6, hosts[nhostsbak],
535d11e3645SMatteo Riondato 				    host_addr) == 1) {
536d11e3645SMatteo Riondato 					close(fd);
537d11e3645SMatteo Riondato 					continue;
538d11e3645SMatteo Riondato 				}
539d11e3645SMatteo Riondato 			}
540d11e3645SMatteo Riondato 			break;
541d11e3645SMatteo Riondato 		case AF_INET6:
542d11e3645SMatteo Riondato 			if (inet_pton(AF_INET6, hosts[nhostsbak],
543d11e3645SMatteo Riondato 			    host_addr) == 1) {
544d11e3645SMatteo Riondato 				hints.ai_flags &= AI_NUMERICHOST;
545d11e3645SMatteo Riondato 			} else {
546d11e3645SMatteo Riondato 				/*
547d11e3645SMatteo Riondato 				 * Skip if we have an AF_INET address.
548d11e3645SMatteo Riondato 				 */
549d11e3645SMatteo Riondato 				if (inet_pton(AF_INET, hosts[nhostsbak],
550d11e3645SMatteo Riondato 				    host_addr) == 1) {
551d11e3645SMatteo Riondato 					close(fd);
552d11e3645SMatteo Riondato 					continue;
553d11e3645SMatteo Riondato 				}
554d11e3645SMatteo Riondato 			}
555d11e3645SMatteo Riondato 
556d11e3645SMatteo Riondato 			/*
557d11e3645SMatteo Riondato 			 * We're doing host-based access checks here, so don't
558d11e3645SMatteo Riondato 			 * allow v4-in-v6 to confuse things. The kernel will
559d11e3645SMatteo Riondato 			 * disable it by default on NFS sockets too.
560d11e3645SMatteo Riondato 			 */
561d11e3645SMatteo Riondato 			if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
562d11e3645SMatteo Riondato 			    sizeof one) < 0) {
563d11e3645SMatteo Riondato 				syslog(LOG_ERR,
564d11e3645SMatteo Riondato 				    "can't disable v4-in-v6 on IPv6 socket");
565d11e3645SMatteo Riondato 				exit(1);
566d11e3645SMatteo Riondato 			}
567d11e3645SMatteo Riondato 			break;
568d11e3645SMatteo Riondato 		default:
569d11e3645SMatteo Riondato 			break;
570d11e3645SMatteo Riondato 		}
571d11e3645SMatteo Riondato 
572d11e3645SMatteo Riondato 		/*
573d11e3645SMatteo Riondato 		 * If no hosts were specified, just bind to INADDR_ANY
574d11e3645SMatteo Riondato 		 */
575d11e3645SMatteo Riondato 		if (strcmp("*", hosts[nhostsbak]) == 0) {
576d11e3645SMatteo Riondato 			if (svcport_str == NULL) {
577d11e3645SMatteo Riondato 				res = malloc(sizeof(struct addrinfo));
578d11e3645SMatteo Riondato 				if (res == NULL)
579d11e3645SMatteo Riondato 					out_of_mem();
580d11e3645SMatteo Riondato 				res->ai_flags = hints.ai_flags;
581d11e3645SMatteo Riondato 				res->ai_family = hints.ai_family;
582d11e3645SMatteo Riondato 				res->ai_protocol = hints.ai_protocol;
583d11e3645SMatteo Riondato 				switch (res->ai_family) {
584d11e3645SMatteo Riondato 				case AF_INET:
585d11e3645SMatteo Riondato 					sin = malloc(sizeof(struct sockaddr_in));
586d11e3645SMatteo Riondato 					if (sin == NULL)
587d11e3645SMatteo Riondato 						out_of_mem();
588d11e3645SMatteo Riondato 					sin->sin_family = AF_INET;
589d11e3645SMatteo Riondato 					sin->sin_port = htons(0);
590d11e3645SMatteo Riondato 					sin->sin_addr.s_addr = htonl(INADDR_ANY);
591d11e3645SMatteo Riondato 					res->ai_addr = (struct sockaddr*) sin;
592d11e3645SMatteo Riondato 					res->ai_addrlen = (socklen_t)
593d11e3645SMatteo Riondato 					    sizeof(res->ai_addr);
594d11e3645SMatteo Riondato 					break;
595d11e3645SMatteo Riondato 				case AF_INET6:
596d11e3645SMatteo Riondato 					sin6 = malloc(sizeof(struct sockaddr_in6));
597d11e3645SMatteo Riondato 					if (res->ai_addr == NULL)
598d11e3645SMatteo Riondato 						out_of_mem();
599d11e3645SMatteo Riondato 					sin6->sin6_family = AF_INET6;
600d11e3645SMatteo Riondato 					sin6->sin6_port = htons(0);
601d11e3645SMatteo Riondato 					sin6->sin6_addr = in6addr_any;
602d11e3645SMatteo Riondato 					res->ai_addr = (struct sockaddr*) sin6;
603d11e3645SMatteo Riondato 					res->ai_addrlen = (socklen_t)
604d11e3645SMatteo Riondato 					    sizeof(res->ai_addr);
605d11e3645SMatteo Riondato 						break;
606d11e3645SMatteo Riondato 				default:
607d11e3645SMatteo Riondato 					break;
608d11e3645SMatteo Riondato 				}
609d11e3645SMatteo Riondato 			} else {
610d11e3645SMatteo Riondato 				if ((aicode = getaddrinfo(NULL, svcport_str,
611d11e3645SMatteo Riondato 				    &hints, &res)) != 0) {
612d11e3645SMatteo Riondato 					syslog(LOG_ERR,
613d11e3645SMatteo Riondato 					    "cannot get local address for %s: %s",
614d11e3645SMatteo Riondato 					    nconf->nc_netid,
615d11e3645SMatteo Riondato 					    gai_strerror(aicode));
616d11e3645SMatteo Riondato 					continue;
617d11e3645SMatteo Riondato 				}
618d11e3645SMatteo Riondato 			}
619d11e3645SMatteo Riondato 		} else {
620d11e3645SMatteo Riondato 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
621d11e3645SMatteo Riondato 			    &hints, &res)) != 0) {
622d11e3645SMatteo Riondato 				syslog(LOG_ERR,
623d11e3645SMatteo Riondato 				    "cannot get local address for %s: %s",
624d11e3645SMatteo Riondato 				    nconf->nc_netid, gai_strerror(aicode));
625d11e3645SMatteo Riondato 				continue;
626d11e3645SMatteo Riondato 			}
627d11e3645SMatteo Riondato 		}
628d11e3645SMatteo Riondato 
629d11e3645SMatteo Riondato 		r = bindresvport_sa(fd, res->ai_addr);
630d11e3645SMatteo Riondato 		if (r != 0) {
631d11e3645SMatteo Riondato 			syslog(LOG_ERR, "bindresvport_sa: %m");
632d11e3645SMatteo Riondato 			exit(1);
633d11e3645SMatteo Riondato 		}
634d11e3645SMatteo Riondato 
635d11e3645SMatteo Riondato 		if (nconf->nc_semantics != NC_TPI_CLTS)
636d11e3645SMatteo Riondato 			listen(fd, SOMAXCONN);
637d11e3645SMatteo Riondato 
638d11e3645SMatteo Riondato 		if (nconf->nc_semantics == NC_TPI_CLTS )
639d11e3645SMatteo Riondato 			transp = svc_dg_create(fd, 0, 0);
640d11e3645SMatteo Riondato 		else
641d11e3645SMatteo Riondato 			transp = svc_vc_create(fd, RPC_MAXDATASIZE,
642d11e3645SMatteo Riondato 			    RPC_MAXDATASIZE);
643d11e3645SMatteo Riondato 
644d11e3645SMatteo Riondato 		if (transp != (SVCXPRT *) NULL) {
645d11e3645SMatteo Riondato 			if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
646d11e3645SMatteo Riondato 			    NULL))
647d11e3645SMatteo Riondato 				syslog(LOG_ERR,
648d11e3645SMatteo Riondato 				    "can't register %s RPCMNT_VER1 service",
649d11e3645SMatteo Riondato 				    nconf->nc_netid);
650d11e3645SMatteo Riondato 			if (!force_v2) {
651d11e3645SMatteo Riondato 				if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER3,
652d11e3645SMatteo Riondato 				    mntsrv, NULL))
653d11e3645SMatteo Riondato 					syslog(LOG_ERR,
654d11e3645SMatteo Riondato 					    "can't register %s RPCMNT_VER3 service",
655d11e3645SMatteo Riondato 					    nconf->nc_netid);
656d11e3645SMatteo Riondato 			}
657d11e3645SMatteo Riondato 		} else
658d11e3645SMatteo Riondato 			syslog(LOG_WARNING, "can't create %s services",
659d11e3645SMatteo Riondato 			    nconf->nc_netid);
660d11e3645SMatteo Riondato 
661d11e3645SMatteo Riondato 		if (registered == 0) {
662d11e3645SMatteo Riondato 			registered = 1;
663d11e3645SMatteo Riondato 			memset(&hints, 0, sizeof hints);
664d11e3645SMatteo Riondato 			hints.ai_flags = AI_PASSIVE;
665d11e3645SMatteo Riondato 			hints.ai_family = si.si_af;
666d11e3645SMatteo Riondato 			hints.ai_socktype = si.si_socktype;
667d11e3645SMatteo Riondato 			hints.ai_protocol = si.si_proto;
668d11e3645SMatteo Riondato 
669d11e3645SMatteo Riondato 			if (svcport_str == NULL) {
670d11e3645SMatteo Riondato 				svcport_str = malloc(NI_MAXSERV * sizeof(char));
671d11e3645SMatteo Riondato 				if (svcport_str == NULL)
672d11e3645SMatteo Riondato 					out_of_mem();
673d11e3645SMatteo Riondato 
674d11e3645SMatteo Riondato 				if (getnameinfo(res->ai_addr,
675d11e3645SMatteo Riondato 				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
676d11e3645SMatteo Riondato 				    svcport_str, NI_MAXSERV * sizeof(char),
677d11e3645SMatteo Riondato 				    NI_NUMERICHOST | NI_NUMERICSERV))
678d11e3645SMatteo Riondato 					errx(1, "Cannot get port number");
679d11e3645SMatteo Riondato 			}
680d11e3645SMatteo Riondato 
681d11e3645SMatteo Riondato 			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
682d11e3645SMatteo Riondato 			    &res)) != 0) {
683d11e3645SMatteo Riondato 				syslog(LOG_ERR, "cannot get local address: %s",
684d11e3645SMatteo Riondato 				    gai_strerror(aicode));
685d11e3645SMatteo Riondato 				exit(1);
686d11e3645SMatteo Riondato 			}
687d11e3645SMatteo Riondato 
688d11e3645SMatteo Riondato 			servaddr.buf = malloc(res->ai_addrlen);
689d11e3645SMatteo Riondato 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
690d11e3645SMatteo Riondato 			servaddr.len = res->ai_addrlen;
691d11e3645SMatteo Riondato 
692d11e3645SMatteo Riondato 			rpcb_set(RPCPROG_MNT, RPCMNT_VER1, nconf, &servaddr);
693d11e3645SMatteo Riondato 			rpcb_set(RPCPROG_MNT, RPCMNT_VER3, nconf, &servaddr);
694d11e3645SMatteo Riondato 
695d11e3645SMatteo Riondato 			xcreated++;
696d11e3645SMatteo Riondato 			freeaddrinfo(res);
697d11e3645SMatteo Riondato 		}
698d11e3645SMatteo Riondato 	} /* end while */
699d11e3645SMatteo Riondato }
700d11e3645SMatteo Riondato 
70174853402SPhilippe Charnier static void
70274853402SPhilippe Charnier usage()
70374853402SPhilippe Charnier {
70474853402SPhilippe Charnier 	fprintf(stderr,
705c203da27SBruce M Simpson 		"usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] "
706d11e3645SMatteo Riondato 		"[-h <bindip>] [export_file ...]\n");
7078fae3551SRodney W. Grimes 	exit(1);
7088fae3551SRodney W. Grimes }
7098fae3551SRodney W. Grimes 
7108fae3551SRodney W. Grimes /*
7118fae3551SRodney W. Grimes  * The mount rpc service
7128fae3551SRodney W. Grimes  */
7138fae3551SRodney W. Grimes void
7148fae3551SRodney W. Grimes mntsrv(rqstp, transp)
7158fae3551SRodney W. Grimes 	struct svc_req *rqstp;
7168fae3551SRodney W. Grimes 	SVCXPRT *transp;
7178fae3551SRodney W. Grimes {
7188fae3551SRodney W. Grimes 	struct exportlist *ep;
7198fae3551SRodney W. Grimes 	struct dirlist *dp;
720a62dc406SDoug Rabson 	struct fhreturn fhr;
7218fae3551SRodney W. Grimes 	struct stat stb;
7228fae3551SRodney W. Grimes 	struct statfs fsb;
7238360efbdSAlfred Perlstein 	char host[NI_MAXHOST], numerichost[NI_MAXHOST];
7248360efbdSAlfred Perlstein 	int lookup_failed = 1;
7258360efbdSAlfred Perlstein 	struct sockaddr *saddr;
726a62dc406SDoug Rabson 	u_short sport;
7278fae3551SRodney W. Grimes 	char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN];
728e90cdb54SGuido van Rooij 	int bad = 0, defset, hostset;
729a62dc406SDoug Rabson 	sigset_t sighup_mask;
7308fae3551SRodney W. Grimes 
731a62dc406SDoug Rabson 	sigemptyset(&sighup_mask);
732a62dc406SDoug Rabson 	sigaddset(&sighup_mask, SIGHUP);
7338360efbdSAlfred Perlstein 	saddr = svc_getrpccaller(transp)->buf;
7348360efbdSAlfred Perlstein 	switch (saddr->sa_family) {
7358360efbdSAlfred Perlstein 	case AF_INET6:
73601709abfSIan Dowse 		sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port);
7378360efbdSAlfred Perlstein 		break;
7388360efbdSAlfred Perlstein 	case AF_INET:
73901709abfSIan Dowse 		sport = ntohs(((struct sockaddr_in *)saddr)->sin_port);
7408360efbdSAlfred Perlstein 		break;
7418360efbdSAlfred Perlstein 	default:
7428360efbdSAlfred Perlstein 		syslog(LOG_ERR, "request from unknown address family");
7438360efbdSAlfred Perlstein 		return;
7448360efbdSAlfred Perlstein 	}
7458360efbdSAlfred Perlstein 	lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host,
7468360efbdSAlfred Perlstein 	    NULL, 0, 0);
7478360efbdSAlfred Perlstein 	getnameinfo(saddr, saddr->sa_len, numerichost,
7488360efbdSAlfred Perlstein 	    sizeof numerichost, NULL, 0, NI_NUMERICHOST);
7498fae3551SRodney W. Grimes 	switch (rqstp->rq_proc) {
7508fae3551SRodney W. Grimes 	case NULLPROC:
751389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL))
75274853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
7538fae3551SRodney W. Grimes 		return;
7548fae3551SRodney W. Grimes 	case RPCMNT_MOUNT:
755a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
756f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
757f51631d7SGuido van Rooij 			    "mount request from %s from unprivileged port",
7588360efbdSAlfred Perlstein 			    numerichost);
7598fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
7608fae3551SRodney W. Grimes 			return;
7618fae3551SRodney W. Grimes 		}
762389b8446SPeter Wemm 		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
763f51631d7SGuido van Rooij 			syslog(LOG_NOTICE, "undecodable mount request from %s",
7648360efbdSAlfred Perlstein 			    numerichost);
7658fae3551SRodney W. Grimes 			svcerr_decode(transp);
7668fae3551SRodney W. Grimes 			return;
7678fae3551SRodney W. Grimes 		}
7688fae3551SRodney W. Grimes 
7698fae3551SRodney W. Grimes 		/*
7708fae3551SRodney W. Grimes 		 * Get the real pathname and make sure it is a directory
771a62dc406SDoug Rabson 		 * or a regular file if the -r option was specified
772a62dc406SDoug Rabson 		 * and it exists.
7738fae3551SRodney W. Grimes 		 */
774cb479b11SAlfred Perlstein 		if (realpath(rpcpath, dirpath) == NULL ||
7758fae3551SRodney W. Grimes 		    stat(dirpath, &stb) < 0 ||
776a62dc406SDoug Rabson 		    (!S_ISDIR(stb.st_mode) &&
777a62dc406SDoug Rabson 		    (dir_only || !S_ISREG(stb.st_mode))) ||
7788fae3551SRodney W. Grimes 		    statfs(dirpath, &fsb) < 0) {
7798fae3551SRodney W. Grimes 			chdir("/");	/* Just in case realpath doesn't */
780f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
78174853402SPhilippe Charnier 			    "mount request from %s for non existent path %s",
7828360efbdSAlfred Perlstein 			    numerichost, dirpath);
7838fae3551SRodney W. Grimes 			if (debug)
78474853402SPhilippe Charnier 				warnx("stat failed on %s", dirpath);
785e90cdb54SGuido van Rooij 			bad = ENOENT;	/* We will send error reply later */
7868fae3551SRodney W. Grimes 		}
7878fae3551SRodney W. Grimes 
7888fae3551SRodney W. Grimes 		/* Check in the exports list */
789a62dc406SDoug Rabson 		sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
7908fae3551SRodney W. Grimes 		ep = ex_search(&fsb.f_fsid);
791a62dc406SDoug Rabson 		hostset = defset = 0;
792a62dc406SDoug Rabson 		if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) ||
7938fae3551SRodney W. Grimes 		    ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
794a62dc406SDoug Rabson 		      chk_host(dp, saddr, &defset, &hostset)) ||
7958fae3551SRodney W. Grimes 		    (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
7968fae3551SRodney W. Grimes 		     scan_tree(ep->ex_dirl, saddr) == 0))) {
797e90cdb54SGuido van Rooij 			if (bad) {
798389b8446SPeter Wemm 				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
799e90cdb54SGuido van Rooij 				    (caddr_t)&bad))
80074853402SPhilippe Charnier 					syslog(LOG_ERR, "can't send reply");
801e90cdb54SGuido van Rooij 				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
802e90cdb54SGuido van Rooij 				return;
803e90cdb54SGuido van Rooij 			}
804a62dc406SDoug Rabson 			if (hostset & DP_HOSTSET)
805a62dc406SDoug Rabson 				fhr.fhr_flag = hostset;
806a62dc406SDoug Rabson 			else
807a62dc406SDoug Rabson 				fhr.fhr_flag = defset;
808a62dc406SDoug Rabson 			fhr.fhr_vers = rqstp->rq_vers;
8098fae3551SRodney W. Grimes 			/* Get the file handle */
81087564113SPeter Wemm 			memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t));
811a62dc406SDoug Rabson 			if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) {
8128fae3551SRodney W. Grimes 				bad = errno;
81374853402SPhilippe Charnier 				syslog(LOG_ERR, "can't get fh for %s", dirpath);
814389b8446SPeter Wemm 				if (!svc_sendreply(transp, (xdrproc_t)xdr_long,
8158fae3551SRodney W. Grimes 				    (caddr_t)&bad))
81674853402SPhilippe Charnier 					syslog(LOG_ERR, "can't send reply");
817a62dc406SDoug Rabson 				sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
8188fae3551SRodney W. Grimes 				return;
8198fae3551SRodney W. Grimes 			}
820389b8446SPeter Wemm 			if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs,
821389b8446SPeter Wemm 			    (caddr_t)&fhr))
82274853402SPhilippe Charnier 				syslog(LOG_ERR, "can't send reply");
8238360efbdSAlfred Perlstein 			if (!lookup_failed)
8248360efbdSAlfred Perlstein 				add_mlist(host, dirpath);
8258fae3551SRodney W. Grimes 			else
8268360efbdSAlfred Perlstein 				add_mlist(numerichost, dirpath);
8278fae3551SRodney W. Grimes 			if (debug)
82874853402SPhilippe Charnier 				warnx("mount successful");
829c903443aSPeter Wemm 			if (dolog)
830f51631d7SGuido van Rooij 				syslog(LOG_NOTICE,
831f51631d7SGuido van Rooij 				    "mount request succeeded from %s for %s",
8328360efbdSAlfred Perlstein 				    numerichost, dirpath);
833f51631d7SGuido van Rooij 		} else {
8348fae3551SRodney W. Grimes 			bad = EACCES;
835f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
836f51631d7SGuido van Rooij 			    "mount request denied from %s for %s",
8378360efbdSAlfred Perlstein 			    numerichost, dirpath);
838f51631d7SGuido van Rooij 		}
839e90cdb54SGuido van Rooij 
840389b8446SPeter Wemm 		if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long,
841389b8446SPeter Wemm 		    (caddr_t)&bad))
84274853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
843a62dc406SDoug Rabson 		sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
8448fae3551SRodney W. Grimes 		return;
8458fae3551SRodney W. Grimes 	case RPCMNT_DUMP:
846389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL))
84774853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
848c903443aSPeter Wemm 		else if (dolog)
849f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
850f51631d7SGuido van Rooij 			    "dump request succeeded from %s",
8518360efbdSAlfred Perlstein 			    numerichost);
8528fae3551SRodney W. Grimes 		return;
8538fae3551SRodney W. Grimes 	case RPCMNT_UMOUNT:
854a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
855f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
856f51631d7SGuido van Rooij 			    "umount request from %s from unprivileged port",
8578360efbdSAlfred Perlstein 			    numerichost);
8588fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
8598fae3551SRodney W. Grimes 			return;
8608fae3551SRodney W. Grimes 		}
861389b8446SPeter Wemm 		if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) {
862f51631d7SGuido van Rooij 			syslog(LOG_NOTICE, "undecodable umount request from %s",
8638360efbdSAlfred Perlstein 			    numerichost);
8648fae3551SRodney W. Grimes 			svcerr_decode(transp);
8658fae3551SRodney W. Grimes 			return;
8668fae3551SRodney W. Grimes 		}
867cb479b11SAlfred Perlstein 		if (realpath(rpcpath, dirpath) == NULL) {
868cb479b11SAlfred Perlstein 			syslog(LOG_NOTICE, "umount request from %s "
869cb479b11SAlfred Perlstein 			    "for non existent path %s",
8708360efbdSAlfred Perlstein 			    numerichost, dirpath);
871cb479b11SAlfred Perlstein 		}
872389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
87374853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
8748360efbdSAlfred Perlstein 		if (!lookup_failed)
87501709abfSIan Dowse 			del_mlist(host, dirpath);
87601709abfSIan Dowse 		del_mlist(numerichost, dirpath);
877c903443aSPeter Wemm 		if (dolog)
878f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
879f51631d7SGuido van Rooij 			    "umount request succeeded from %s for %s",
8808360efbdSAlfred Perlstein 			    numerichost, dirpath);
8818fae3551SRodney W. Grimes 		return;
8828fae3551SRodney W. Grimes 	case RPCMNT_UMNTALL:
883a62dc406SDoug Rabson 		if (sport >= IPPORT_RESERVED && resvport_only) {
884f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
885f51631d7SGuido van Rooij 			    "umountall request from %s from unprivileged port",
8868360efbdSAlfred Perlstein 			    numerichost);
8878fae3551SRodney W. Grimes 			svcerr_weakauth(transp);
8888fae3551SRodney W. Grimes 			return;
8898fae3551SRodney W. Grimes 		}
890389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL))
89174853402SPhilippe Charnier 			syslog(LOG_ERR, "can't send reply");
8928360efbdSAlfred Perlstein 		if (!lookup_failed)
89301709abfSIan Dowse 			del_mlist(host, NULL);
89401709abfSIan Dowse 		del_mlist(numerichost, NULL);
895c903443aSPeter Wemm 		if (dolog)
896f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
897f51631d7SGuido van Rooij 			    "umountall request succeeded from %s",
8988360efbdSAlfred Perlstein 			    numerichost);
8998fae3551SRodney W. Grimes 		return;
9008fae3551SRodney W. Grimes 	case RPCMNT_EXPORT:
901389b8446SPeter Wemm 		if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL))
902389b8446SPeter Wemm 			if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief,
903389b8446SPeter Wemm 			    (caddr_t)NULL))
90474853402SPhilippe Charnier 				syslog(LOG_ERR, "can't send reply");
905c903443aSPeter Wemm 		if (dolog)
906f51631d7SGuido van Rooij 			syslog(LOG_NOTICE,
907f51631d7SGuido van Rooij 			    "export request succeeded from %s",
9088360efbdSAlfred Perlstein 			    numerichost);
9098fae3551SRodney W. Grimes 		return;
9108fae3551SRodney W. Grimes 	default:
9118fae3551SRodney W. Grimes 		svcerr_noproc(transp);
9128fae3551SRodney W. Grimes 		return;
9138fae3551SRodney W. Grimes 	}
9148fae3551SRodney W. Grimes }
9158fae3551SRodney W. Grimes 
9168fae3551SRodney W. Grimes /*
9178fae3551SRodney W. Grimes  * Xdr conversion for a dirpath string
9188fae3551SRodney W. Grimes  */
9198fae3551SRodney W. Grimes int
9208fae3551SRodney W. Grimes xdr_dir(xdrsp, dirp)
9218fae3551SRodney W. Grimes 	XDR *xdrsp;
9228fae3551SRodney W. Grimes 	char *dirp;
9238fae3551SRodney W. Grimes {
9248fae3551SRodney W. Grimes 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
9258fae3551SRodney W. Grimes }
9268fae3551SRodney W. Grimes 
9278fae3551SRodney W. Grimes /*
928a62dc406SDoug Rabson  * Xdr routine to generate file handle reply
9298fae3551SRodney W. Grimes  */
9308fae3551SRodney W. Grimes int
931a62dc406SDoug Rabson xdr_fhs(xdrsp, cp)
9328fae3551SRodney W. Grimes 	XDR *xdrsp;
933a62dc406SDoug Rabson 	caddr_t cp;
9348fae3551SRodney W. Grimes {
9353d438ad6SDavid E. O'Brien 	struct fhreturn *fhrp = (struct fhreturn *)cp;
936a62dc406SDoug Rabson 	u_long ok = 0, len, auth;
9378fae3551SRodney W. Grimes 
9388fae3551SRodney W. Grimes 	if (!xdr_long(xdrsp, &ok))
9398fae3551SRodney W. Grimes 		return (0);
940a62dc406SDoug Rabson 	switch (fhrp->fhr_vers) {
941a62dc406SDoug Rabson 	case 1:
942a62dc406SDoug Rabson 		return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH));
943a62dc406SDoug Rabson 	case 3:
944a62dc406SDoug Rabson 		len = NFSX_V3FH;
945a62dc406SDoug Rabson 		if (!xdr_long(xdrsp, &len))
946a62dc406SDoug Rabson 			return (0);
947a62dc406SDoug Rabson 		if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len))
948a62dc406SDoug Rabson 			return (0);
949a62dc406SDoug Rabson 		auth = RPCAUTH_UNIX;
950a62dc406SDoug Rabson 		len = 1;
951a62dc406SDoug Rabson 		if (!xdr_long(xdrsp, &len))
952a62dc406SDoug Rabson 			return (0);
953a62dc406SDoug Rabson 		return (xdr_long(xdrsp, &auth));
954a62dc406SDoug Rabson 	};
955a62dc406SDoug Rabson 	return (0);
9568fae3551SRodney W. Grimes }
9578fae3551SRodney W. Grimes 
9588fae3551SRodney W. Grimes int
9598fae3551SRodney W. Grimes xdr_mlist(xdrsp, cp)
9608fae3551SRodney W. Grimes 	XDR *xdrsp;
9618fae3551SRodney W. Grimes 	caddr_t cp;
9628fae3551SRodney W. Grimes {
9638fae3551SRodney W. Grimes 	struct mountlist *mlp;
9648fae3551SRodney W. Grimes 	int true = 1;
9658fae3551SRodney W. Grimes 	int false = 0;
9668fae3551SRodney W. Grimes 	char *strp;
9678fae3551SRodney W. Grimes 
9688fae3551SRodney W. Grimes 	mlp = mlhead;
9698fae3551SRodney W. Grimes 	while (mlp) {
9708fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &true))
9718fae3551SRodney W. Grimes 			return (0);
9728fae3551SRodney W. Grimes 		strp = &mlp->ml_host[0];
9738fae3551SRodney W. Grimes 		if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
9748fae3551SRodney W. Grimes 			return (0);
9758fae3551SRodney W. Grimes 		strp = &mlp->ml_dirp[0];
9768fae3551SRodney W. Grimes 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
9778fae3551SRodney W. Grimes 			return (0);
9788fae3551SRodney W. Grimes 		mlp = mlp->ml_next;
9798fae3551SRodney W. Grimes 	}
9808fae3551SRodney W. Grimes 	if (!xdr_bool(xdrsp, &false))
9818fae3551SRodney W. Grimes 		return (0);
9828fae3551SRodney W. Grimes 	return (1);
9838fae3551SRodney W. Grimes }
9848fae3551SRodney W. Grimes 
9858fae3551SRodney W. Grimes /*
9868fae3551SRodney W. Grimes  * Xdr conversion for export list
9878fae3551SRodney W. Grimes  */
9888fae3551SRodney W. Grimes int
98991acb349SAlfred Perlstein xdr_explist_common(xdrsp, cp, brief)
9908fae3551SRodney W. Grimes 	XDR *xdrsp;
9918fae3551SRodney W. Grimes 	caddr_t cp;
99291acb349SAlfred Perlstein 	int brief;
9938fae3551SRodney W. Grimes {
9948fae3551SRodney W. Grimes 	struct exportlist *ep;
9958fae3551SRodney W. Grimes 	int false = 0;
996a62dc406SDoug Rabson 	int putdef;
997a62dc406SDoug Rabson 	sigset_t sighup_mask;
9988fae3551SRodney W. Grimes 
999a62dc406SDoug Rabson 	sigemptyset(&sighup_mask);
1000a62dc406SDoug Rabson 	sigaddset(&sighup_mask, SIGHUP);
1001a62dc406SDoug Rabson 	sigprocmask(SIG_BLOCK, &sighup_mask, NULL);
10028fae3551SRodney W. Grimes 	ep = exphead;
10038fae3551SRodney W. Grimes 	while (ep) {
10048fae3551SRodney W. Grimes 		putdef = 0;
100591acb349SAlfred Perlstein 		if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir,
100691acb349SAlfred Perlstein 			       &putdef, brief))
10078fae3551SRodney W. Grimes 			goto errout;
10088fae3551SRodney W. Grimes 		if (ep->ex_defdir && putdef == 0 &&
10098fae3551SRodney W. Grimes 			put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
101091acb349SAlfred Perlstein 			&putdef, brief))
10118fae3551SRodney W. Grimes 			goto errout;
10128fae3551SRodney W. Grimes 		ep = ep->ex_next;
10138fae3551SRodney W. Grimes 	}
1014a62dc406SDoug Rabson 	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
10158fae3551SRodney W. Grimes 	if (!xdr_bool(xdrsp, &false))
10168fae3551SRodney W. Grimes 		return (0);
10178fae3551SRodney W. Grimes 	return (1);
10188fae3551SRodney W. Grimes errout:
1019a62dc406SDoug Rabson 	sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL);
10208fae3551SRodney W. Grimes 	return (0);
10218fae3551SRodney W. Grimes }
10228fae3551SRodney W. Grimes 
10238fae3551SRodney W. Grimes /*
10248fae3551SRodney W. Grimes  * Called from xdr_explist() to traverse the tree and export the
10258fae3551SRodney W. Grimes  * directory paths.
10268fae3551SRodney W. Grimes  */
10278fae3551SRodney W. Grimes int
102891acb349SAlfred Perlstein put_exlist(dp, xdrsp, adp, putdefp, brief)
10298fae3551SRodney W. Grimes 	struct dirlist *dp;
10308fae3551SRodney W. Grimes 	XDR *xdrsp;
10318fae3551SRodney W. Grimes 	struct dirlist *adp;
10328fae3551SRodney W. Grimes 	int *putdefp;
103391acb349SAlfred Perlstein 	int brief;
10348fae3551SRodney W. Grimes {
10358fae3551SRodney W. Grimes 	struct grouplist *grp;
10368fae3551SRodney W. Grimes 	struct hostlist *hp;
10378fae3551SRodney W. Grimes 	int true = 1;
10388fae3551SRodney W. Grimes 	int false = 0;
10398fae3551SRodney W. Grimes 	int gotalldir = 0;
10408fae3551SRodney W. Grimes 	char *strp;
10418fae3551SRodney W. Grimes 
10428fae3551SRodney W. Grimes 	if (dp) {
104391acb349SAlfred Perlstein 		if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief))
10448fae3551SRodney W. Grimes 			return (1);
10458fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &true))
10468fae3551SRodney W. Grimes 			return (1);
10478fae3551SRodney W. Grimes 		strp = dp->dp_dirp;
10488fae3551SRodney W. Grimes 		if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
10498fae3551SRodney W. Grimes 			return (1);
10508fae3551SRodney W. Grimes 		if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
10518fae3551SRodney W. Grimes 			gotalldir = 1;
10528fae3551SRodney W. Grimes 			*putdefp = 1;
10538fae3551SRodney W. Grimes 		}
105491acb349SAlfred Perlstein 		if (brief) {
105591acb349SAlfred Perlstein 			if (!xdr_bool(xdrsp, &true))
105691acb349SAlfred Perlstein 				return (1);
105791acb349SAlfred Perlstein 			strp = "(...)";
105891acb349SAlfred Perlstein 			if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
105991acb349SAlfred Perlstein 				return (1);
106091acb349SAlfred Perlstein 		} else if ((dp->dp_flag & DP_DEFSET) == 0 &&
10618fae3551SRodney W. Grimes 		    (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
10628fae3551SRodney W. Grimes 			hp = dp->dp_hosts;
10638fae3551SRodney W. Grimes 			while (hp) {
10648fae3551SRodney W. Grimes 				grp = hp->ht_grp;
10658fae3551SRodney W. Grimes 				if (grp->gr_type == GT_HOST) {
10668fae3551SRodney W. Grimes 					if (!xdr_bool(xdrsp, &true))
10678fae3551SRodney W. Grimes 						return (1);
10688360efbdSAlfred Perlstein 					strp = grp->gr_ptr.gt_addrinfo->ai_canonname;
10698fae3551SRodney W. Grimes 					if (!xdr_string(xdrsp, &strp,
10708fae3551SRodney W. Grimes 					    RPCMNT_NAMELEN))
10718fae3551SRodney W. Grimes 						return (1);
10728fae3551SRodney W. Grimes 				} else if (grp->gr_type == GT_NET) {
10738fae3551SRodney W. Grimes 					if (!xdr_bool(xdrsp, &true))
10748fae3551SRodney W. Grimes 						return (1);
10758fae3551SRodney W. Grimes 					strp = grp->gr_ptr.gt_net.nt_name;
10768fae3551SRodney W. Grimes 					if (!xdr_string(xdrsp, &strp,
10778fae3551SRodney W. Grimes 					    RPCMNT_NAMELEN))
10788fae3551SRodney W. Grimes 						return (1);
10798fae3551SRodney W. Grimes 				}
10808fae3551SRodney W. Grimes 				hp = hp->ht_next;
10818fae3551SRodney W. Grimes 				if (gotalldir && hp == (struct hostlist *)NULL) {
10828fae3551SRodney W. Grimes 					hp = adp->dp_hosts;
10838fae3551SRodney W. Grimes 					gotalldir = 0;
10848fae3551SRodney W. Grimes 				}
10858fae3551SRodney W. Grimes 			}
10868fae3551SRodney W. Grimes 		}
10878fae3551SRodney W. Grimes 		if (!xdr_bool(xdrsp, &false))
10888fae3551SRodney W. Grimes 			return (1);
108991acb349SAlfred Perlstein 		if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief))
10908fae3551SRodney W. Grimes 			return (1);
10918fae3551SRodney W. Grimes 	}
10928fae3551SRodney W. Grimes 	return (0);
10938fae3551SRodney W. Grimes }
10948fae3551SRodney W. Grimes 
109591acb349SAlfred Perlstein int
109691acb349SAlfred Perlstein xdr_explist(xdrsp, cp)
109791acb349SAlfred Perlstein 	XDR *xdrsp;
109891acb349SAlfred Perlstein 	caddr_t cp;
109991acb349SAlfred Perlstein {
110091acb349SAlfred Perlstein 
110191acb349SAlfred Perlstein 	return xdr_explist_common(xdrsp, cp, 0);
110291acb349SAlfred Perlstein }
110391acb349SAlfred Perlstein 
110491acb349SAlfred Perlstein int
110591acb349SAlfred Perlstein xdr_explist_brief(xdrsp, cp)
110691acb349SAlfred Perlstein 	XDR *xdrsp;
110791acb349SAlfred Perlstein 	caddr_t cp;
110891acb349SAlfred Perlstein {
110991acb349SAlfred Perlstein 
111091acb349SAlfred Perlstein 	return xdr_explist_common(xdrsp, cp, 1);
111191acb349SAlfred Perlstein }
111291acb349SAlfred Perlstein 
111391ca1a91SIan Dowse char *line;
111491ca1a91SIan Dowse int linesize;
11158fae3551SRodney W. Grimes FILE *exp_file;
11168fae3551SRodney W. Grimes 
11178fae3551SRodney W. Grimes /*
111896968c22SPawel Jakub Dawidek  * Get the export list from one, currently open file
11198fae3551SRodney W. Grimes  */
112096968c22SPawel Jakub Dawidek static void
112196968c22SPawel Jakub Dawidek get_exportlist_one()
11228fae3551SRodney W. Grimes {
11238fae3551SRodney W. Grimes 	struct exportlist *ep, *ep2;
11248fae3551SRodney W. Grimes 	struct grouplist *grp, *tgrp;
11258fae3551SRodney W. Grimes 	struct exportlist **epp;
11268fae3551SRodney W. Grimes 	struct dirlist *dirhead;
112796968c22SPawel Jakub Dawidek 	struct statfs fsb;
1128c0511d3bSBrian Feldman 	struct xucred anon;
11298fae3551SRodney W. Grimes 	char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
113096968c22SPawel Jakub Dawidek 	int len, has_host, exflags, got_nondir, dirplen, netgrp;
11318fae3551SRodney W. Grimes 
11328fae3551SRodney W. Grimes 	dirhead = (struct dirlist *)NULL;
11338fae3551SRodney W. Grimes 	while (get_line()) {
11348fae3551SRodney W. Grimes 		if (debug)
113574853402SPhilippe Charnier 			warnx("got line %s", line);
11368fae3551SRodney W. Grimes 		cp = line;
11378fae3551SRodney W. Grimes 		nextfield(&cp, &endcp);
11388fae3551SRodney W. Grimes 		if (*cp == '#')
11398fae3551SRodney W. Grimes 			goto nextline;
11408fae3551SRodney W. Grimes 
11418fae3551SRodney W. Grimes 		/*
11428fae3551SRodney W. Grimes 		 * Set defaults.
11438fae3551SRodney W. Grimes 		 */
11448fae3551SRodney W. Grimes 		has_host = FALSE;
11458fae3551SRodney W. Grimes 		anon = def_anon;
11468fae3551SRodney W. Grimes 		exflags = MNT_EXPORTED;
11478fae3551SRodney W. Grimes 		got_nondir = 0;
11488fae3551SRodney W. Grimes 		opt_flags = 0;
11498fae3551SRodney W. Grimes 		ep = (struct exportlist *)NULL;
11508fae3551SRodney W. Grimes 
11518fae3551SRodney W. Grimes 		/*
11528fae3551SRodney W. Grimes 		 * Create new exports list entry
11538fae3551SRodney W. Grimes 		 */
11548fae3551SRodney W. Grimes 		len = endcp-cp;
11558fae3551SRodney W. Grimes 		tgrp = grp = get_grp();
11568fae3551SRodney W. Grimes 		while (len > 0) {
11578fae3551SRodney W. Grimes 			if (len > RPCMNT_NAMELEN) {
11588fae3551SRodney W. Grimes 			    getexp_err(ep, tgrp);
11598fae3551SRodney W. Grimes 			    goto nextline;
11608fae3551SRodney W. Grimes 			}
11618fae3551SRodney W. Grimes 			if (*cp == '-') {
11628fae3551SRodney W. Grimes 			    if (ep == (struct exportlist *)NULL) {
11638fae3551SRodney W. Grimes 				getexp_err(ep, tgrp);
11648fae3551SRodney W. Grimes 				goto nextline;
11658fae3551SRodney W. Grimes 			    }
11668fae3551SRodney W. Grimes 			    if (debug)
116774853402SPhilippe Charnier 				warnx("doing opt %s", cp);
11688fae3551SRodney W. Grimes 			    got_nondir = 1;
11698fae3551SRodney W. Grimes 			    if (do_opt(&cp, &endcp, ep, grp, &has_host,
11708fae3551SRodney W. Grimes 				&exflags, &anon)) {
11718fae3551SRodney W. Grimes 				getexp_err(ep, tgrp);
11728fae3551SRodney W. Grimes 				goto nextline;
11738fae3551SRodney W. Grimes 			    }
11748fae3551SRodney W. Grimes 			} else if (*cp == '/') {
11758fae3551SRodney W. Grimes 			    savedc = *endcp;
11768fae3551SRodney W. Grimes 			    *endcp = '\0';
11778fae3551SRodney W. Grimes 			    if (check_dirpath(cp) &&
11788fae3551SRodney W. Grimes 				statfs(cp, &fsb) >= 0) {
11798fae3551SRodney W. Grimes 				if (got_nondir) {
118074853402SPhilippe Charnier 				    syslog(LOG_ERR, "dirs must be first");
11818fae3551SRodney W. Grimes 				    getexp_err(ep, tgrp);
11828fae3551SRodney W. Grimes 				    goto nextline;
11838fae3551SRodney W. Grimes 				}
11848fae3551SRodney W. Grimes 				if (ep) {
11858fae3551SRodney W. Grimes 				    if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
11868fae3551SRodney W. Grimes 					ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
11878fae3551SRodney W. Grimes 					getexp_err(ep, tgrp);
11888fae3551SRodney W. Grimes 					goto nextline;
11898fae3551SRodney W. Grimes 				    }
11908fae3551SRodney W. Grimes 				} else {
11918fae3551SRodney W. Grimes 				    /*
11928fae3551SRodney W. Grimes 				     * See if this directory is already
11938fae3551SRodney W. Grimes 				     * in the list.
11948fae3551SRodney W. Grimes 				     */
11958fae3551SRodney W. Grimes 				    ep = ex_search(&fsb.f_fsid);
11968fae3551SRodney W. Grimes 				    if (ep == (struct exportlist *)NULL) {
11978fae3551SRodney W. Grimes 					ep = get_exp();
11988fae3551SRodney W. Grimes 					ep->ex_fs = fsb.f_fsid;
11998fae3551SRodney W. Grimes 					ep->ex_fsdir = (char *)
12008fae3551SRodney W. Grimes 					    malloc(strlen(fsb.f_mntonname) + 1);
12018fae3551SRodney W. Grimes 					if (ep->ex_fsdir)
12028fae3551SRodney W. Grimes 					    strcpy(ep->ex_fsdir,
12038fae3551SRodney W. Grimes 						fsb.f_mntonname);
12048fae3551SRodney W. Grimes 					else
12058fae3551SRodney W. Grimes 					    out_of_mem();
12068fae3551SRodney W. Grimes 					if (debug)
120774853402SPhilippe Charnier 						warnx("making new ep fs=0x%x,0x%x",
12088fae3551SRodney W. Grimes 						    fsb.f_fsid.val[0],
12098fae3551SRodney W. Grimes 						    fsb.f_fsid.val[1]);
12108fae3551SRodney W. Grimes 				    } else if (debug)
121174853402SPhilippe Charnier 					warnx("found ep fs=0x%x,0x%x",
12128fae3551SRodney W. Grimes 					    fsb.f_fsid.val[0],
12138fae3551SRodney W. Grimes 					    fsb.f_fsid.val[1]);
12148fae3551SRodney W. Grimes 				}
12158fae3551SRodney W. Grimes 
12168fae3551SRodney W. Grimes 				/*
12178fae3551SRodney W. Grimes 				 * Add dirpath to export mount point.
12188fae3551SRodney W. Grimes 				 */
12198fae3551SRodney W. Grimes 				dirp = add_expdir(&dirhead, cp, len);
12208fae3551SRodney W. Grimes 				dirplen = len;
12218fae3551SRodney W. Grimes 			    } else {
12228fae3551SRodney W. Grimes 				getexp_err(ep, tgrp);
12238fae3551SRodney W. Grimes 				goto nextline;
12248fae3551SRodney W. Grimes 			    }
12258fae3551SRodney W. Grimes 			    *endcp = savedc;
12268fae3551SRodney W. Grimes 			} else {
12278fae3551SRodney W. Grimes 			    savedc = *endcp;
12288fae3551SRodney W. Grimes 			    *endcp = '\0';
12298fae3551SRodney W. Grimes 			    got_nondir = 1;
12308fae3551SRodney W. Grimes 			    if (ep == (struct exportlist *)NULL) {
12318fae3551SRodney W. Grimes 				getexp_err(ep, tgrp);
12328fae3551SRodney W. Grimes 				goto nextline;
12338fae3551SRodney W. Grimes 			    }
12348fae3551SRodney W. Grimes 
12358fae3551SRodney W. Grimes 			    /*
12368fae3551SRodney W. Grimes 			     * Get the host or netgroup.
12378fae3551SRodney W. Grimes 			     */
12388fae3551SRodney W. Grimes 			    setnetgrent(cp);
12398fae3551SRodney W. Grimes 			    netgrp = getnetgrent(&hst, &usr, &dom);
12408fae3551SRodney W. Grimes 			    do {
12418fae3551SRodney W. Grimes 				if (has_host) {
12428fae3551SRodney W. Grimes 				    grp->gr_next = get_grp();
12438fae3551SRodney W. Grimes 				    grp = grp->gr_next;
12448fae3551SRodney W. Grimes 				}
12458fae3551SRodney W. Grimes 				if (netgrp) {
12469d70a156SJoerg Wunsch 				    if (hst == 0) {
124774853402SPhilippe Charnier 					syslog(LOG_ERR,
124874853402SPhilippe Charnier 				"null hostname in netgroup %s, skipping", cp);
124901d48801SJoerg Wunsch 					grp->gr_type = GT_IGNORE;
12509d70a156SJoerg Wunsch 				    } else if (get_host(hst, grp, tgrp)) {
125174853402SPhilippe Charnier 					syslog(LOG_ERR,
125274853402SPhilippe Charnier 			"bad host %s in netgroup %s, skipping", hst, cp);
1253a968cfd8SJonathan Lemon 					grp->gr_type = GT_IGNORE;
12548fae3551SRodney W. Grimes 				    }
12558b5a6d67SBill Paul 				} else if (get_host(cp, grp, tgrp)) {
125674853402SPhilippe Charnier 				    syslog(LOG_ERR, "bad host %s, skipping", cp);
1257a968cfd8SJonathan Lemon 				    grp->gr_type = GT_IGNORE;
12588fae3551SRodney W. Grimes 				}
12598fae3551SRodney W. Grimes 				has_host = TRUE;
12608fae3551SRodney W. Grimes 			    } while (netgrp && getnetgrent(&hst, &usr, &dom));
12618fae3551SRodney W. Grimes 			    endnetgrent();
12628fae3551SRodney W. Grimes 			    *endcp = savedc;
12638fae3551SRodney W. Grimes 			}
12648fae3551SRodney W. Grimes 			cp = endcp;
12658fae3551SRodney W. Grimes 			nextfield(&cp, &endcp);
12668fae3551SRodney W. Grimes 			len = endcp - cp;
12678fae3551SRodney W. Grimes 		}
12688fae3551SRodney W. Grimes 		if (check_options(dirhead)) {
12698fae3551SRodney W. Grimes 			getexp_err(ep, tgrp);
12708fae3551SRodney W. Grimes 			goto nextline;
12718fae3551SRodney W. Grimes 		}
12728fae3551SRodney W. Grimes 		if (!has_host) {
12736d359f31SIan Dowse 			grp->gr_type = GT_DEFAULT;
12748fae3551SRodney W. Grimes 			if (debug)
127574853402SPhilippe Charnier 				warnx("adding a default entry");
12768fae3551SRodney W. Grimes 
12778fae3551SRodney W. Grimes 		/*
12788fae3551SRodney W. Grimes 		 * Don't allow a network export coincide with a list of
12798fae3551SRodney W. Grimes 		 * host(s) on the same line.
12808fae3551SRodney W. Grimes 		 */
12818fae3551SRodney W. Grimes 		} else if ((opt_flags & OP_NET) && tgrp->gr_next) {
128260caaee2SIan Dowse 			syslog(LOG_ERR, "network/host conflict");
12838fae3551SRodney W. Grimes 			getexp_err(ep, tgrp);
12848fae3551SRodney W. Grimes 			goto nextline;
1285a968cfd8SJonathan Lemon 
1286a968cfd8SJonathan Lemon 		/*
1287a968cfd8SJonathan Lemon 		 * If an export list was specified on this line, make sure
1288a968cfd8SJonathan Lemon 		 * that we have at least one valid entry, otherwise skip it.
1289a968cfd8SJonathan Lemon 		 */
1290a968cfd8SJonathan Lemon 		} else {
1291a968cfd8SJonathan Lemon 			grp = tgrp;
1292a968cfd8SJonathan Lemon 			while (grp && grp->gr_type == GT_IGNORE)
1293a968cfd8SJonathan Lemon 				grp = grp->gr_next;
1294a968cfd8SJonathan Lemon 			if (! grp) {
1295a968cfd8SJonathan Lemon 			    getexp_err(ep, tgrp);
1296a968cfd8SJonathan Lemon 			    goto nextline;
1297a968cfd8SJonathan Lemon 			}
12988fae3551SRodney W. Grimes 		}
12998fae3551SRodney W. Grimes 
13008fae3551SRodney W. Grimes 		/*
13018fae3551SRodney W. Grimes 		 * Loop through hosts, pushing the exports into the kernel.
13028fae3551SRodney W. Grimes 		 * After loop, tgrp points to the start of the list and
13038fae3551SRodney W. Grimes 		 * grp points to the last entry in the list.
13048fae3551SRodney W. Grimes 		 */
13058fae3551SRodney W. Grimes 		grp = tgrp;
13068fae3551SRodney W. Grimes 		do {
130701709abfSIan Dowse 			if (do_mount(ep, grp, exflags, &anon, dirp, dirplen,
130801709abfSIan Dowse 			    &fsb)) {
13098fae3551SRodney W. Grimes 				getexp_err(ep, tgrp);
13108fae3551SRodney W. Grimes 				goto nextline;
13118fae3551SRodney W. Grimes 			}
13128fae3551SRodney W. Grimes 		} while (grp->gr_next && (grp = grp->gr_next));
13138fae3551SRodney W. Grimes 
13148fae3551SRodney W. Grimes 		/*
13158fae3551SRodney W. Grimes 		 * Success. Update the data structures.
13168fae3551SRodney W. Grimes 		 */
13178fae3551SRodney W. Grimes 		if (has_host) {
1318a62dc406SDoug Rabson 			hang_dirp(dirhead, tgrp, ep, opt_flags);
13198fae3551SRodney W. Grimes 			grp->gr_next = grphead;
13208fae3551SRodney W. Grimes 			grphead = tgrp;
13218fae3551SRodney W. Grimes 		} else {
13228fae3551SRodney W. Grimes 			hang_dirp(dirhead, (struct grouplist *)NULL, ep,
1323a62dc406SDoug Rabson 				opt_flags);
13248fae3551SRodney W. Grimes 			free_grp(grp);
13258fae3551SRodney W. Grimes 		}
13268fae3551SRodney W. Grimes 		dirhead = (struct dirlist *)NULL;
13278fae3551SRodney W. Grimes 		if ((ep->ex_flag & EX_LINKED) == 0) {
13288fae3551SRodney W. Grimes 			ep2 = exphead;
13298fae3551SRodney W. Grimes 			epp = &exphead;
13308fae3551SRodney W. Grimes 
13318fae3551SRodney W. Grimes 			/*
13328fae3551SRodney W. Grimes 			 * Insert in the list in alphabetical order.
13338fae3551SRodney W. Grimes 			 */
13348fae3551SRodney W. Grimes 			while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
13358fae3551SRodney W. Grimes 				epp = &ep2->ex_next;
13368fae3551SRodney W. Grimes 				ep2 = ep2->ex_next;
13378fae3551SRodney W. Grimes 			}
13388fae3551SRodney W. Grimes 			if (ep2)
13398fae3551SRodney W. Grimes 				ep->ex_next = ep2;
13408fae3551SRodney W. Grimes 			*epp = ep;
13418fae3551SRodney W. Grimes 			ep->ex_flag |= EX_LINKED;
13428fae3551SRodney W. Grimes 		}
13438fae3551SRodney W. Grimes nextline:
13448fae3551SRodney W. Grimes 		if (dirhead) {
13458fae3551SRodney W. Grimes 			free_dir(dirhead);
13468fae3551SRodney W. Grimes 			dirhead = (struct dirlist *)NULL;
13478fae3551SRodney W. Grimes 		}
13488fae3551SRodney W. Grimes 	}
134996968c22SPawel Jakub Dawidek }
135096968c22SPawel Jakub Dawidek 
135196968c22SPawel Jakub Dawidek /*
135296968c22SPawel Jakub Dawidek  * Get the export list from all specified files
135396968c22SPawel Jakub Dawidek  */
135496968c22SPawel Jakub Dawidek void
135596968c22SPawel Jakub Dawidek get_exportlist()
135696968c22SPawel Jakub Dawidek {
135796968c22SPawel Jakub Dawidek 	struct exportlist *ep, *ep2;
135896968c22SPawel Jakub Dawidek 	struct grouplist *grp, *tgrp;
135996968c22SPawel Jakub Dawidek 	struct export_args export;
136096968c22SPawel Jakub Dawidek 	struct iovec *iov;
136196968c22SPawel Jakub Dawidek 	struct statfs *fsp, *mntbufp;
136296968c22SPawel Jakub Dawidek 	struct xvfsconf vfc;
136396968c22SPawel Jakub Dawidek 	char *dirp;
136496968c22SPawel Jakub Dawidek 	char errmsg[255];
136596968c22SPawel Jakub Dawidek 	int dirplen, num, i;
136696968c22SPawel Jakub Dawidek 	int iovlen;
13676c90092bSPawel Jakub Dawidek 	int done;
136896968c22SPawel Jakub Dawidek 
136996968c22SPawel Jakub Dawidek 	bzero(&export, sizeof(export));
137096968c22SPawel Jakub Dawidek 	export.ex_flags = MNT_DELEXPORT;
137196968c22SPawel Jakub Dawidek 	dirp = NULL;
137296968c22SPawel Jakub Dawidek 	dirplen = 0;
137396968c22SPawel Jakub Dawidek 	iov = NULL;
137496968c22SPawel Jakub Dawidek 	iovlen = 0;
137596968c22SPawel Jakub Dawidek 	bzero(errmsg, sizeof(errmsg));
137696968c22SPawel Jakub Dawidek 
137796968c22SPawel Jakub Dawidek 	/*
137896968c22SPawel Jakub Dawidek 	 * First, get rid of the old list
137996968c22SPawel Jakub Dawidek 	 */
138096968c22SPawel Jakub Dawidek 	ep = exphead;
138196968c22SPawel Jakub Dawidek 	while (ep) {
138296968c22SPawel Jakub Dawidek 		ep2 = ep;
138396968c22SPawel Jakub Dawidek 		ep = ep->ex_next;
138496968c22SPawel Jakub Dawidek 		free_exp(ep2);
138596968c22SPawel Jakub Dawidek 	}
138696968c22SPawel Jakub Dawidek 	exphead = (struct exportlist *)NULL;
138796968c22SPawel Jakub Dawidek 
138896968c22SPawel Jakub Dawidek 	grp = grphead;
138996968c22SPawel Jakub Dawidek 	while (grp) {
139096968c22SPawel Jakub Dawidek 		tgrp = grp;
139196968c22SPawel Jakub Dawidek 		grp = grp->gr_next;
139296968c22SPawel Jakub Dawidek 		free_grp(tgrp);
139396968c22SPawel Jakub Dawidek 	}
139496968c22SPawel Jakub Dawidek 	grphead = (struct grouplist *)NULL;
139596968c22SPawel Jakub Dawidek 
139696968c22SPawel Jakub Dawidek 	/*
139796968c22SPawel Jakub Dawidek 	 * And delete exports that are in the kernel for all local
139896968c22SPawel Jakub Dawidek 	 * filesystems.
139996968c22SPawel Jakub Dawidek 	 * XXX: Should know how to handle all local exportable filesystems.
140096968c22SPawel Jakub Dawidek 	 */
140196968c22SPawel Jakub Dawidek 	num = getmntinfo(&mntbufp, MNT_NOWAIT);
140296968c22SPawel Jakub Dawidek 
140396968c22SPawel Jakub Dawidek 	if (num > 0) {
140496968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "fstype", NULL, 0);
140596968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "fspath", NULL, 0);
140696968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "from", NULL, 0);
140796968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "update", NULL, 0);
140896968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "export", &export, sizeof(export));
140996968c22SPawel Jakub Dawidek 		build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
141096968c22SPawel Jakub Dawidek 	}
141196968c22SPawel Jakub Dawidek 
141296968c22SPawel Jakub Dawidek 	for (i = 0; i < num; i++) {
141396968c22SPawel Jakub Dawidek 		fsp = &mntbufp[i];
141496968c22SPawel Jakub Dawidek 		if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) {
141596968c22SPawel Jakub Dawidek 			syslog(LOG_ERR, "getvfsbyname() failed for %s",
141696968c22SPawel Jakub Dawidek 			    fsp->f_fstypename);
141796968c22SPawel Jakub Dawidek 			continue;
141896968c22SPawel Jakub Dawidek 		}
141996968c22SPawel Jakub Dawidek 
142096968c22SPawel Jakub Dawidek 		/*
142196968c22SPawel Jakub Dawidek 		 * Do not delete export for network filesystem by
142296968c22SPawel Jakub Dawidek 		 * passing "export" arg to nmount().
142396968c22SPawel Jakub Dawidek 		 * It only makes sense to do this for local filesystems.
142496968c22SPawel Jakub Dawidek 		 */
142596968c22SPawel Jakub Dawidek 		if (vfc.vfc_flags & VFCF_NETWORK)
142696968c22SPawel Jakub Dawidek 			continue;
142796968c22SPawel Jakub Dawidek 
142896968c22SPawel Jakub Dawidek 		iov[1].iov_base = fsp->f_fstypename;
142996968c22SPawel Jakub Dawidek 		iov[1].iov_len = strlen(fsp->f_fstypename) + 1;
143096968c22SPawel Jakub Dawidek 		iov[3].iov_base = fsp->f_mntonname;
143196968c22SPawel Jakub Dawidek 		iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
143296968c22SPawel Jakub Dawidek 		iov[5].iov_base = fsp->f_mntfromname;
143396968c22SPawel Jakub Dawidek 		iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
143496968c22SPawel Jakub Dawidek 
143596968c22SPawel Jakub Dawidek 		/*
143696968c22SPawel Jakub Dawidek 		 * Kick out MNT_ROOTFS.  It should not be passed from
143796968c22SPawel Jakub Dawidek 		 * userland to kernel.  It should only be used
143896968c22SPawel Jakub Dawidek 		 * internally in the kernel.
143996968c22SPawel Jakub Dawidek 		 */
144096968c22SPawel Jakub Dawidek 		if (fsp->f_flags & MNT_ROOTFS) {
144196968c22SPawel Jakub Dawidek 			fsp->f_flags &= ~MNT_ROOTFS;
144296968c22SPawel Jakub Dawidek 		}
144396968c22SPawel Jakub Dawidek 
144496968c22SPawel Jakub Dawidek 		if (nmount(iov, iovlen, fsp->f_flags) < 0 &&
144596968c22SPawel Jakub Dawidek 		    errno != ENOENT && errno != ENOTSUP) {
144696968c22SPawel Jakub Dawidek 			syslog(LOG_ERR,
144796968c22SPawel Jakub Dawidek 			    "can't delete exports for %s: %m %s",
144896968c22SPawel Jakub Dawidek 			    fsp->f_mntonname, errmsg);
144996968c22SPawel Jakub Dawidek 		}
145096968c22SPawel Jakub Dawidek 	}
145196968c22SPawel Jakub Dawidek 
145296968c22SPawel Jakub Dawidek 	if (iov != NULL) {
145396968c22SPawel Jakub Dawidek 		/* Free strings allocated by strdup() in getmntopts.c */
145496968c22SPawel Jakub Dawidek 		free(iov[0].iov_base); /* fstype */
145596968c22SPawel Jakub Dawidek 		free(iov[2].iov_base); /* fspath */
145696968c22SPawel Jakub Dawidek 		free(iov[4].iov_base); /* from */
145796968c22SPawel Jakub Dawidek 		free(iov[6].iov_base); /* update */
145896968c22SPawel Jakub Dawidek 		free(iov[8].iov_base); /* export */
145996968c22SPawel Jakub Dawidek 		free(iov[10].iov_base); /* errmsg */
146096968c22SPawel Jakub Dawidek 
146196968c22SPawel Jakub Dawidek 		/* free iov, allocated by realloc() */
146296968c22SPawel Jakub Dawidek 		free(iov);
146396968c22SPawel Jakub Dawidek 		iovlen = 0;
146496968c22SPawel Jakub Dawidek 	}
146596968c22SPawel Jakub Dawidek 
146696968c22SPawel Jakub Dawidek 	/*
146796968c22SPawel Jakub Dawidek 	 * Read in the exports file and build the list, calling
146896968c22SPawel Jakub Dawidek 	 * nmount() as we go along to push the export rules into the kernel.
146996968c22SPawel Jakub Dawidek 	 */
14706c90092bSPawel Jakub Dawidek 	done = 0;
147196968c22SPawel Jakub Dawidek 	for (i = 0; exnames[i] != NULL; i++) {
147296968c22SPawel Jakub Dawidek 		if (debug)
147396968c22SPawel Jakub Dawidek 			warnx("reading exports from %s", exnames[i]);
147496968c22SPawel Jakub Dawidek 		if ((exp_file = fopen(exnames[i], "r")) == NULL) {
14756c90092bSPawel Jakub Dawidek 			syslog(LOG_WARNING, "can't open %s", exnames[i]);
14766c90092bSPawel Jakub Dawidek 			continue;
147796968c22SPawel Jakub Dawidek 		}
147896968c22SPawel Jakub Dawidek 		get_exportlist_one();
14798fae3551SRodney W. Grimes 		fclose(exp_file);
14806c90092bSPawel Jakub Dawidek 		done++;
14816c90092bSPawel Jakub Dawidek 	}
14826c90092bSPawel Jakub Dawidek 	if (done == 0) {
14836c90092bSPawel Jakub Dawidek 		syslog(LOG_ERR, "can't open any exports file");
14846c90092bSPawel Jakub Dawidek 		exit(2);
14858fae3551SRodney W. Grimes 	}
148696968c22SPawel Jakub Dawidek }
14878fae3551SRodney W. Grimes 
14888fae3551SRodney W. Grimes /*
14898fae3551SRodney W. Grimes  * Allocate an export list element
14908fae3551SRodney W. Grimes  */
14918fae3551SRodney W. Grimes struct exportlist *
14928fae3551SRodney W. Grimes get_exp()
14938fae3551SRodney W. Grimes {
14948fae3551SRodney W. Grimes 	struct exportlist *ep;
14958fae3551SRodney W. Grimes 
14968fae3551SRodney W. Grimes 	ep = (struct exportlist *)malloc(sizeof (struct exportlist));
14978fae3551SRodney W. Grimes 	if (ep == (struct exportlist *)NULL)
14988fae3551SRodney W. Grimes 		out_of_mem();
149987564113SPeter Wemm 	memset(ep, 0, sizeof(struct exportlist));
15008fae3551SRodney W. Grimes 	return (ep);
15018fae3551SRodney W. Grimes }
15028fae3551SRodney W. Grimes 
15038fae3551SRodney W. Grimes /*
15048fae3551SRodney W. Grimes  * Allocate a group list element
15058fae3551SRodney W. Grimes  */
15068fae3551SRodney W. Grimes struct grouplist *
15078fae3551SRodney W. Grimes get_grp()
15088fae3551SRodney W. Grimes {
15098fae3551SRodney W. Grimes 	struct grouplist *gp;
15108fae3551SRodney W. Grimes 
15118fae3551SRodney W. Grimes 	gp = (struct grouplist *)malloc(sizeof (struct grouplist));
15128fae3551SRodney W. Grimes 	if (gp == (struct grouplist *)NULL)
15138fae3551SRodney W. Grimes 		out_of_mem();
151487564113SPeter Wemm 	memset(gp, 0, sizeof(struct grouplist));
15158fae3551SRodney W. Grimes 	return (gp);
15168fae3551SRodney W. Grimes }
15178fae3551SRodney W. Grimes 
15188fae3551SRodney W. Grimes /*
15198fae3551SRodney W. Grimes  * Clean up upon an error in get_exportlist().
15208fae3551SRodney W. Grimes  */
15218fae3551SRodney W. Grimes void
15228fae3551SRodney W. Grimes getexp_err(ep, grp)
15238fae3551SRodney W. Grimes 	struct exportlist *ep;
15248fae3551SRodney W. Grimes 	struct grouplist *grp;
15258fae3551SRodney W. Grimes {
15268fae3551SRodney W. Grimes 	struct grouplist *tgrp;
15278fae3551SRodney W. Grimes 
1528288fa14aSJoerg Wunsch 	if (!(opt_flags & OP_QUIET))
152974853402SPhilippe Charnier 		syslog(LOG_ERR, "bad exports list line %s", line);
15308fae3551SRodney W. Grimes 	if (ep && (ep->ex_flag & EX_LINKED) == 0)
15318fae3551SRodney W. Grimes 		free_exp(ep);
15328fae3551SRodney W. Grimes 	while (grp) {
15338fae3551SRodney W. Grimes 		tgrp = grp;
15348fae3551SRodney W. Grimes 		grp = grp->gr_next;
15358fae3551SRodney W. Grimes 		free_grp(tgrp);
15368fae3551SRodney W. Grimes 	}
15378fae3551SRodney W. Grimes }
15388fae3551SRodney W. Grimes 
15398fae3551SRodney W. Grimes /*
15408fae3551SRodney W. Grimes  * Search the export list for a matching fs.
15418fae3551SRodney W. Grimes  */
15428fae3551SRodney W. Grimes struct exportlist *
15438fae3551SRodney W. Grimes ex_search(fsid)
15448fae3551SRodney W. Grimes 	fsid_t *fsid;
15458fae3551SRodney W. Grimes {
15468fae3551SRodney W. Grimes 	struct exportlist *ep;
15478fae3551SRodney W. Grimes 
15488fae3551SRodney W. Grimes 	ep = exphead;
15498fae3551SRodney W. Grimes 	while (ep) {
15508fae3551SRodney W. Grimes 		if (ep->ex_fs.val[0] == fsid->val[0] &&
15518fae3551SRodney W. Grimes 		    ep->ex_fs.val[1] == fsid->val[1])
15528fae3551SRodney W. Grimes 			return (ep);
15538fae3551SRodney W. Grimes 		ep = ep->ex_next;
15548fae3551SRodney W. Grimes 	}
15558fae3551SRodney W. Grimes 	return (ep);
15568fae3551SRodney W. Grimes }
15578fae3551SRodney W. Grimes 
15588fae3551SRodney W. Grimes /*
15598fae3551SRodney W. Grimes  * Add a directory path to the list.
15608fae3551SRodney W. Grimes  */
15618fae3551SRodney W. Grimes char *
15628fae3551SRodney W. Grimes add_expdir(dpp, cp, len)
15638fae3551SRodney W. Grimes 	struct dirlist **dpp;
15648fae3551SRodney W. Grimes 	char *cp;
15658fae3551SRodney W. Grimes 	int len;
15668fae3551SRodney W. Grimes {
15678fae3551SRodney W. Grimes 	struct dirlist *dp;
15688fae3551SRodney W. Grimes 
15698fae3551SRodney W. Grimes 	dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
157074853402SPhilippe Charnier 	if (dp == (struct dirlist *)NULL)
157174853402SPhilippe Charnier 		out_of_mem();
15728fae3551SRodney W. Grimes 	dp->dp_left = *dpp;
15738fae3551SRodney W. Grimes 	dp->dp_right = (struct dirlist *)NULL;
15748fae3551SRodney W. Grimes 	dp->dp_flag = 0;
15758fae3551SRodney W. Grimes 	dp->dp_hosts = (struct hostlist *)NULL;
15768fae3551SRodney W. Grimes 	strcpy(dp->dp_dirp, cp);
15778fae3551SRodney W. Grimes 	*dpp = dp;
15788fae3551SRodney W. Grimes 	return (dp->dp_dirp);
15798fae3551SRodney W. Grimes }
15808fae3551SRodney W. Grimes 
15818fae3551SRodney W. Grimes /*
15828fae3551SRodney W. Grimes  * Hang the dir list element off the dirpath binary tree as required
15838fae3551SRodney W. Grimes  * and update the entry for host.
15848fae3551SRodney W. Grimes  */
15858fae3551SRodney W. Grimes void
1586a62dc406SDoug Rabson hang_dirp(dp, grp, ep, flags)
15878fae3551SRodney W. Grimes 	struct dirlist *dp;
15888fae3551SRodney W. Grimes 	struct grouplist *grp;
15898fae3551SRodney W. Grimes 	struct exportlist *ep;
1590a62dc406SDoug Rabson 	int flags;
15918fae3551SRodney W. Grimes {
15928fae3551SRodney W. Grimes 	struct hostlist *hp;
15938fae3551SRodney W. Grimes 	struct dirlist *dp2;
15948fae3551SRodney W. Grimes 
1595a62dc406SDoug Rabson 	if (flags & OP_ALLDIRS) {
15968fae3551SRodney W. Grimes 		if (ep->ex_defdir)
15978fae3551SRodney W. Grimes 			free((caddr_t)dp);
15988fae3551SRodney W. Grimes 		else
15998fae3551SRodney W. Grimes 			ep->ex_defdir = dp;
1600a62dc406SDoug Rabson 		if (grp == (struct grouplist *)NULL) {
16018fae3551SRodney W. Grimes 			ep->ex_defdir->dp_flag |= DP_DEFSET;
1602a62dc406SDoug Rabson 		} else while (grp) {
16038fae3551SRodney W. Grimes 			hp = get_ht();
16048fae3551SRodney W. Grimes 			hp->ht_grp = grp;
16058fae3551SRodney W. Grimes 			hp->ht_next = ep->ex_defdir->dp_hosts;
16068fae3551SRodney W. Grimes 			ep->ex_defdir->dp_hosts = hp;
16078fae3551SRodney W. Grimes 			grp = grp->gr_next;
16088fae3551SRodney W. Grimes 		}
16098fae3551SRodney W. Grimes 	} else {
16108fae3551SRodney W. Grimes 
16118fae3551SRodney W. Grimes 		/*
161274853402SPhilippe Charnier 		 * Loop through the directories adding them to the tree.
16138fae3551SRodney W. Grimes 		 */
16148fae3551SRodney W. Grimes 		while (dp) {
16158fae3551SRodney W. Grimes 			dp2 = dp->dp_left;
1616a62dc406SDoug Rabson 			add_dlist(&ep->ex_dirl, dp, grp, flags);
16178fae3551SRodney W. Grimes 			dp = dp2;
16188fae3551SRodney W. Grimes 		}
16198fae3551SRodney W. Grimes 	}
16208fae3551SRodney W. Grimes }
16218fae3551SRodney W. Grimes 
16228fae3551SRodney W. Grimes /*
16238fae3551SRodney W. Grimes  * Traverse the binary tree either updating a node that is already there
16248fae3551SRodney W. Grimes  * for the new directory or adding the new node.
16258fae3551SRodney W. Grimes  */
16268fae3551SRodney W. Grimes void
1627a62dc406SDoug Rabson add_dlist(dpp, newdp, grp, flags)
16288fae3551SRodney W. Grimes 	struct dirlist **dpp;
16298fae3551SRodney W. Grimes 	struct dirlist *newdp;
16308fae3551SRodney W. Grimes 	struct grouplist *grp;
1631a62dc406SDoug Rabson 	int flags;
16328fae3551SRodney W. Grimes {
16338fae3551SRodney W. Grimes 	struct dirlist *dp;
16348fae3551SRodney W. Grimes 	struct hostlist *hp;
16358fae3551SRodney W. Grimes 	int cmp;
16368fae3551SRodney W. Grimes 
16378fae3551SRodney W. Grimes 	dp = *dpp;
16388fae3551SRodney W. Grimes 	if (dp) {
16398fae3551SRodney W. Grimes 		cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
16408fae3551SRodney W. Grimes 		if (cmp > 0) {
1641a62dc406SDoug Rabson 			add_dlist(&dp->dp_left, newdp, grp, flags);
16428fae3551SRodney W. Grimes 			return;
16438fae3551SRodney W. Grimes 		} else if (cmp < 0) {
1644a62dc406SDoug Rabson 			add_dlist(&dp->dp_right, newdp, grp, flags);
16458fae3551SRodney W. Grimes 			return;
16468fae3551SRodney W. Grimes 		} else
16478fae3551SRodney W. Grimes 			free((caddr_t)newdp);
16488fae3551SRodney W. Grimes 	} else {
16498fae3551SRodney W. Grimes 		dp = newdp;
16508fae3551SRodney W. Grimes 		dp->dp_left = (struct dirlist *)NULL;
16518fae3551SRodney W. Grimes 		*dpp = dp;
16528fae3551SRodney W. Grimes 	}
16538fae3551SRodney W. Grimes 	if (grp) {
16548fae3551SRodney W. Grimes 
16558fae3551SRodney W. Grimes 		/*
16568fae3551SRodney W. Grimes 		 * Hang all of the host(s) off of the directory point.
16578fae3551SRodney W. Grimes 		 */
16588fae3551SRodney W. Grimes 		do {
16598fae3551SRodney W. Grimes 			hp = get_ht();
16608fae3551SRodney W. Grimes 			hp->ht_grp = grp;
16618fae3551SRodney W. Grimes 			hp->ht_next = dp->dp_hosts;
16628fae3551SRodney W. Grimes 			dp->dp_hosts = hp;
16638fae3551SRodney W. Grimes 			grp = grp->gr_next;
16648fae3551SRodney W. Grimes 		} while (grp);
1665a62dc406SDoug Rabson 	} else {
16668fae3551SRodney W. Grimes 		dp->dp_flag |= DP_DEFSET;
1667a62dc406SDoug Rabson 	}
16688fae3551SRodney W. Grimes }
16698fae3551SRodney W. Grimes 
16708fae3551SRodney W. Grimes /*
16718fae3551SRodney W. Grimes  * Search for a dirpath on the export point.
16728fae3551SRodney W. Grimes  */
16738fae3551SRodney W. Grimes struct dirlist *
16748360efbdSAlfred Perlstein dirp_search(dp, dirp)
16758fae3551SRodney W. Grimes 	struct dirlist *dp;
16768360efbdSAlfred Perlstein 	char *dirp;
16778fae3551SRodney W. Grimes {
16788fae3551SRodney W. Grimes 	int cmp;
16798fae3551SRodney W. Grimes 
16808fae3551SRodney W. Grimes 	if (dp) {
16818360efbdSAlfred Perlstein 		cmp = strcmp(dp->dp_dirp, dirp);
16828fae3551SRodney W. Grimes 		if (cmp > 0)
16838360efbdSAlfred Perlstein 			return (dirp_search(dp->dp_left, dirp));
16848fae3551SRodney W. Grimes 		else if (cmp < 0)
16858360efbdSAlfred Perlstein 			return (dirp_search(dp->dp_right, dirp));
16868fae3551SRodney W. Grimes 		else
16878fae3551SRodney W. Grimes 			return (dp);
16888fae3551SRodney W. Grimes 	}
16898fae3551SRodney W. Grimes 	return (dp);
16908fae3551SRodney W. Grimes }
16918fae3551SRodney W. Grimes 
16928fae3551SRodney W. Grimes /*
16938fae3551SRodney W. Grimes  * Scan for a host match in a directory tree.
16948fae3551SRodney W. Grimes  */
16958fae3551SRodney W. Grimes int
1696a62dc406SDoug Rabson chk_host(dp, saddr, defsetp, hostsetp)
16978fae3551SRodney W. Grimes 	struct dirlist *dp;
16988360efbdSAlfred Perlstein 	struct sockaddr *saddr;
16998fae3551SRodney W. Grimes 	int *defsetp;
1700a62dc406SDoug Rabson 	int *hostsetp;
17018fae3551SRodney W. Grimes {
17028fae3551SRodney W. Grimes 	struct hostlist *hp;
17038fae3551SRodney W. Grimes 	struct grouplist *grp;
17048360efbdSAlfred Perlstein 	struct addrinfo *ai;
17058fae3551SRodney W. Grimes 
17068fae3551SRodney W. Grimes 	if (dp) {
17078fae3551SRodney W. Grimes 		if (dp->dp_flag & DP_DEFSET)
1708a62dc406SDoug Rabson 			*defsetp = dp->dp_flag;
17098fae3551SRodney W. Grimes 		hp = dp->dp_hosts;
17108fae3551SRodney W. Grimes 		while (hp) {
17118fae3551SRodney W. Grimes 			grp = hp->ht_grp;
17128fae3551SRodney W. Grimes 			switch (grp->gr_type) {
17138fae3551SRodney W. Grimes 			case GT_HOST:
17148360efbdSAlfred Perlstein 				ai = grp->gr_ptr.gt_addrinfo;
17158360efbdSAlfred Perlstein 				for (; ai; ai = ai->ai_next) {
171660caaee2SIan Dowse 					if (!sacmp(ai->ai_addr, saddr, NULL)) {
17178360efbdSAlfred Perlstein 						*hostsetp =
17188360efbdSAlfred Perlstein 						    (hp->ht_flag | DP_HOSTSET);
17198fae3551SRodney W. Grimes 						return (1);
1720a62dc406SDoug Rabson 					}
17218fae3551SRodney W. Grimes 				}
17228fae3551SRodney W. Grimes 				break;
17238fae3551SRodney W. Grimes 			case GT_NET:
172460caaee2SIan Dowse 				if (!sacmp(saddr, (struct sockaddr *)
172560caaee2SIan Dowse 				    &grp->gr_ptr.gt_net.nt_net,
172660caaee2SIan Dowse 				    (struct sockaddr *)
172760caaee2SIan Dowse 				    &grp->gr_ptr.gt_net.nt_mask)) {
1728a62dc406SDoug Rabson 					*hostsetp = (hp->ht_flag | DP_HOSTSET);
17298fae3551SRodney W. Grimes 					return (1);
1730a62dc406SDoug Rabson 				}
17318fae3551SRodney W. Grimes 				break;
173260caaee2SIan Dowse 			}
17338fae3551SRodney W. Grimes 			hp = hp->ht_next;
17348fae3551SRodney W. Grimes 		}
17358fae3551SRodney W. Grimes 	}
17368fae3551SRodney W. Grimes 	return (0);
17378fae3551SRodney W. Grimes }
17388fae3551SRodney W. Grimes 
17398fae3551SRodney W. Grimes /*
17408fae3551SRodney W. Grimes  * Scan tree for a host that matches the address.
17418fae3551SRodney W. Grimes  */
17428fae3551SRodney W. Grimes int
17438fae3551SRodney W. Grimes scan_tree(dp, saddr)
17448fae3551SRodney W. Grimes 	struct dirlist *dp;
17458360efbdSAlfred Perlstein 	struct sockaddr *saddr;
17468fae3551SRodney W. Grimes {
1747a62dc406SDoug Rabson 	int defset, hostset;
17488fae3551SRodney W. Grimes 
17498fae3551SRodney W. Grimes 	if (dp) {
17508fae3551SRodney W. Grimes 		if (scan_tree(dp->dp_left, saddr))
17518fae3551SRodney W. Grimes 			return (1);
1752a62dc406SDoug Rabson 		if (chk_host(dp, saddr, &defset, &hostset))
17538fae3551SRodney W. Grimes 			return (1);
17548fae3551SRodney W. Grimes 		if (scan_tree(dp->dp_right, saddr))
17558fae3551SRodney W. Grimes 			return (1);
17568fae3551SRodney W. Grimes 	}
17578fae3551SRodney W. Grimes 	return (0);
17588fae3551SRodney W. Grimes }
17598fae3551SRodney W. Grimes 
17608fae3551SRodney W. Grimes /*
17618fae3551SRodney W. Grimes  * Traverse the dirlist tree and free it up.
17628fae3551SRodney W. Grimes  */
17638fae3551SRodney W. Grimes void
17648fae3551SRodney W. Grimes free_dir(dp)
17658fae3551SRodney W. Grimes 	struct dirlist *dp;
17668fae3551SRodney W. Grimes {
17678fae3551SRodney W. Grimes 
17688fae3551SRodney W. Grimes 	if (dp) {
17698fae3551SRodney W. Grimes 		free_dir(dp->dp_left);
17708fae3551SRodney W. Grimes 		free_dir(dp->dp_right);
17718fae3551SRodney W. Grimes 		free_host(dp->dp_hosts);
17728fae3551SRodney W. Grimes 		free((caddr_t)dp);
17738fae3551SRodney W. Grimes 	}
17748fae3551SRodney W. Grimes }
17758fae3551SRodney W. Grimes 
17768fae3551SRodney W. Grimes /*
17778fae3551SRodney W. Grimes  * Parse the option string and update fields.
17788fae3551SRodney W. Grimes  * Option arguments may either be -<option>=<value> or
17798fae3551SRodney W. Grimes  * -<option> <value>
17808fae3551SRodney W. Grimes  */
17818fae3551SRodney W. Grimes int
17828fae3551SRodney W. Grimes do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
17838fae3551SRodney W. Grimes 	char **cpp, **endcpp;
17848fae3551SRodney W. Grimes 	struct exportlist *ep;
17858fae3551SRodney W. Grimes 	struct grouplist *grp;
17868fae3551SRodney W. Grimes 	int *has_hostp;
17878fae3551SRodney W. Grimes 	int *exflagsp;
1788c0511d3bSBrian Feldman 	struct xucred *cr;
17898fae3551SRodney W. Grimes {
17908fae3551SRodney W. Grimes 	char *cpoptarg, *cpoptend;
17918fae3551SRodney W. Grimes 	char *cp, *endcp, *cpopt, savedc, savedc2;
17928fae3551SRodney W. Grimes 	int allflag, usedarg;
17938fae3551SRodney W. Grimes 
1794cb479b11SAlfred Perlstein 	savedc2 = '\0';
17958fae3551SRodney W. Grimes 	cpopt = *cpp;
17968fae3551SRodney W. Grimes 	cpopt++;
17978fae3551SRodney W. Grimes 	cp = *endcpp;
17988fae3551SRodney W. Grimes 	savedc = *cp;
17998fae3551SRodney W. Grimes 	*cp = '\0';
18008fae3551SRodney W. Grimes 	while (cpopt && *cpopt) {
18018fae3551SRodney W. Grimes 		allflag = 1;
18028fae3551SRodney W. Grimes 		usedarg = -2;
180374853402SPhilippe Charnier 		if ((cpoptend = strchr(cpopt, ','))) {
18048fae3551SRodney W. Grimes 			*cpoptend++ = '\0';
180574853402SPhilippe Charnier 			if ((cpoptarg = strchr(cpopt, '=')))
18068fae3551SRodney W. Grimes 				*cpoptarg++ = '\0';
18078fae3551SRodney W. Grimes 		} else {
180874853402SPhilippe Charnier 			if ((cpoptarg = strchr(cpopt, '=')))
18098fae3551SRodney W. Grimes 				*cpoptarg++ = '\0';
18108fae3551SRodney W. Grimes 			else {
18118fae3551SRodney W. Grimes 				*cp = savedc;
18128fae3551SRodney W. Grimes 				nextfield(&cp, &endcp);
18138fae3551SRodney W. Grimes 				**endcpp = '\0';
18148fae3551SRodney W. Grimes 				if (endcp > cp && *cp != '-') {
18158fae3551SRodney W. Grimes 					cpoptarg = cp;
18168fae3551SRodney W. Grimes 					savedc2 = *endcp;
18178fae3551SRodney W. Grimes 					*endcp = '\0';
18188fae3551SRodney W. Grimes 					usedarg = 0;
18198fae3551SRodney W. Grimes 				}
18208fae3551SRodney W. Grimes 			}
18218fae3551SRodney W. Grimes 		}
18228fae3551SRodney W. Grimes 		if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
18238fae3551SRodney W. Grimes 			*exflagsp |= MNT_EXRDONLY;
18248fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
18258fae3551SRodney W. Grimes 		    !(allflag = strcmp(cpopt, "mapall")) ||
18268fae3551SRodney W. Grimes 		    !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
18278fae3551SRodney W. Grimes 			usedarg++;
18288fae3551SRodney W. Grimes 			parsecred(cpoptarg, cr);
18298fae3551SRodney W. Grimes 			if (allflag == 0) {
18308fae3551SRodney W. Grimes 				*exflagsp |= MNT_EXPORTANON;
18318fae3551SRodney W. Grimes 				opt_flags |= OP_MAPALL;
18328fae3551SRodney W. Grimes 			} else
18338fae3551SRodney W. Grimes 				opt_flags |= OP_MAPROOT;
18348fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "mask") ||
18358fae3551SRodney W. Grimes 		    !strcmp(cpopt, "m"))) {
18368fae3551SRodney W. Grimes 			if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
183774853402SPhilippe Charnier 				syslog(LOG_ERR, "bad mask: %s", cpoptarg);
18388fae3551SRodney W. Grimes 				return (1);
18398fae3551SRodney W. Grimes 			}
18408fae3551SRodney W. Grimes 			usedarg++;
18418fae3551SRodney W. Grimes 			opt_flags |= OP_MASK;
18428fae3551SRodney W. Grimes 		} else if (cpoptarg && (!strcmp(cpopt, "network") ||
18438fae3551SRodney W. Grimes 			!strcmp(cpopt, "n"))) {
18448360efbdSAlfred Perlstein 			if (strchr(cpoptarg, '/') != NULL) {
18458360efbdSAlfred Perlstein 				if (debug)
18468360efbdSAlfred Perlstein 					fprintf(stderr, "setting OP_MASKLEN\n");
18478360efbdSAlfred Perlstein 				opt_flags |= OP_MASKLEN;
18488360efbdSAlfred Perlstein 			}
18498fae3551SRodney W. Grimes 			if (grp->gr_type != GT_NULL) {
185074853402SPhilippe Charnier 				syslog(LOG_ERR, "network/host conflict");
18518fae3551SRodney W. Grimes 				return (1);
18528fae3551SRodney W. Grimes 			} else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
185374853402SPhilippe Charnier 				syslog(LOG_ERR, "bad net: %s", cpoptarg);
18548fae3551SRodney W. Grimes 				return (1);
18558fae3551SRodney W. Grimes 			}
18568fae3551SRodney W. Grimes 			grp->gr_type = GT_NET;
18578fae3551SRodney W. Grimes 			*has_hostp = 1;
18588fae3551SRodney W. Grimes 			usedarg++;
18598fae3551SRodney W. Grimes 			opt_flags |= OP_NET;
18608fae3551SRodney W. Grimes 		} else if (!strcmp(cpopt, "alldirs")) {
18618fae3551SRodney W. Grimes 			opt_flags |= OP_ALLDIRS;
1862cb3923e0SDoug Rabson 		} else if (!strcmp(cpopt, "public")) {
1863cb3923e0SDoug Rabson 			*exflagsp |= MNT_EXPUBLIC;
1864cb3923e0SDoug Rabson 		} else if (!strcmp(cpopt, "webnfs")) {
1865cb3923e0SDoug Rabson 			*exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON);
1866cb3923e0SDoug Rabson 			opt_flags |= OP_MAPALL;
1867cb3923e0SDoug Rabson 		} else if (cpoptarg && !strcmp(cpopt, "index")) {
1868cb3923e0SDoug Rabson 			ep->ex_indexfile = strdup(cpoptarg);
1869288fa14aSJoerg Wunsch 		} else if (!strcmp(cpopt, "quiet")) {
1870288fa14aSJoerg Wunsch 			opt_flags |= OP_QUIET;
18718fae3551SRodney W. Grimes 		} else {
187274853402SPhilippe Charnier 			syslog(LOG_ERR, "bad opt %s", cpopt);
18738fae3551SRodney W. Grimes 			return (1);
18748fae3551SRodney W. Grimes 		}
18758fae3551SRodney W. Grimes 		if (usedarg >= 0) {
18768fae3551SRodney W. Grimes 			*endcp = savedc2;
18778fae3551SRodney W. Grimes 			**endcpp = savedc;
18788fae3551SRodney W. Grimes 			if (usedarg > 0) {
18798fae3551SRodney W. Grimes 				*cpp = cp;
18808fae3551SRodney W. Grimes 				*endcpp = endcp;
18818fae3551SRodney W. Grimes 			}
18828fae3551SRodney W. Grimes 			return (0);
18838fae3551SRodney W. Grimes 		}
18848fae3551SRodney W. Grimes 		cpopt = cpoptend;
18858fae3551SRodney W. Grimes 	}
18868fae3551SRodney W. Grimes 	**endcpp = savedc;
18878fae3551SRodney W. Grimes 	return (0);
18888fae3551SRodney W. Grimes }
18898fae3551SRodney W. Grimes 
18908fae3551SRodney W. Grimes /*
18918fae3551SRodney W. Grimes  * Translate a character string to the corresponding list of network
18928fae3551SRodney W. Grimes  * addresses for a hostname.
18938fae3551SRodney W. Grimes  */
18948fae3551SRodney W. Grimes int
18958b5a6d67SBill Paul get_host(cp, grp, tgrp)
18968fae3551SRodney W. Grimes 	char *cp;
18978fae3551SRodney W. Grimes 	struct grouplist *grp;
18988b5a6d67SBill Paul 	struct grouplist *tgrp;
18998fae3551SRodney W. Grimes {
19008b5a6d67SBill Paul 	struct grouplist *checkgrp;
190101709abfSIan Dowse 	struct addrinfo *ai, *tai, hints;
19028360efbdSAlfred Perlstein 	int ecode;
19038360efbdSAlfred Perlstein 	char host[NI_MAXHOST];
19048fae3551SRodney W. Grimes 
19058360efbdSAlfred Perlstein 	if (grp->gr_type != GT_NULL) {
19068360efbdSAlfred Perlstein 		syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp);
19078fae3551SRodney W. Grimes 		return (1);
19088fae3551SRodney W. Grimes 	}
19098360efbdSAlfred Perlstein 	memset(&hints, 0, sizeof hints);
19108360efbdSAlfred Perlstein 	hints.ai_flags = AI_CANONNAME;
19118360efbdSAlfred Perlstein 	hints.ai_protocol = IPPROTO_UDP;
19128360efbdSAlfred Perlstein 	ecode = getaddrinfo(cp, NULL, &hints, &ai);
19138360efbdSAlfred Perlstein 	if (ecode != 0) {
191401709abfSIan Dowse 		syslog(LOG_ERR,"can't get address info for host %s", cp);
19158360efbdSAlfred Perlstein 		return 1;
19168fae3551SRodney W. Grimes 	}
19178360efbdSAlfred Perlstein 	grp->gr_ptr.gt_addrinfo = ai;
19188360efbdSAlfred Perlstein 	while (ai != NULL) {
19198360efbdSAlfred Perlstein 		if (ai->ai_canonname == NULL) {
19208360efbdSAlfred Perlstein 			if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host,
19214f101318SHajimu UMEMOTO 			    sizeof host, NULL, 0, NI_NUMERICHOST) != 0)
19228360efbdSAlfred Perlstein 				strlcpy(host, "?", sizeof(host));
19238360efbdSAlfred Perlstein 			ai->ai_canonname = strdup(host);
19248360efbdSAlfred Perlstein 			ai->ai_flags |= AI_CANONNAME;
19256d359f31SIan Dowse 		}
19268fae3551SRodney W. Grimes 		if (debug)
192701709abfSIan Dowse 			fprintf(stderr, "got host %s\n", ai->ai_canonname);
192801709abfSIan Dowse 		/*
192901709abfSIan Dowse 		 * Sanity check: make sure we don't already have an entry
193001709abfSIan Dowse 		 * for this host in the grouplist.
193101709abfSIan Dowse 		 */
193201709abfSIan Dowse 		for (checkgrp = tgrp; checkgrp != NULL;
193301709abfSIan Dowse 		    checkgrp = checkgrp->gr_next) {
193401709abfSIan Dowse 			if (checkgrp->gr_type != GT_HOST)
193501709abfSIan Dowse 				continue;
193601709abfSIan Dowse 			for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL;
193701709abfSIan Dowse 			    tai = tai->ai_next) {
193860caaee2SIan Dowse 				if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0)
193901709abfSIan Dowse 					continue;
194001709abfSIan Dowse 				if (debug)
194101709abfSIan Dowse 					fprintf(stderr,
194201709abfSIan Dowse 					    "ignoring duplicate host %s\n",
194301709abfSIan Dowse 					    ai->ai_canonname);
194401709abfSIan Dowse 				grp->gr_type = GT_IGNORE;
194501709abfSIan Dowse 				return (0);
194601709abfSIan Dowse 			}
194701709abfSIan Dowse 		}
19488360efbdSAlfred Perlstein 		ai = ai->ai_next;
19498360efbdSAlfred Perlstein 	}
195001709abfSIan Dowse 	grp->gr_type = GT_HOST;
19518fae3551SRodney W. Grimes 	return (0);
19528fae3551SRodney W. Grimes }
19538fae3551SRodney W. Grimes 
19548fae3551SRodney W. Grimes /*
19558fae3551SRodney W. Grimes  * Free up an exports list component
19568fae3551SRodney W. Grimes  */
19578fae3551SRodney W. Grimes void
19588fae3551SRodney W. Grimes free_exp(ep)
19598fae3551SRodney W. Grimes 	struct exportlist *ep;
19608fae3551SRodney W. Grimes {
19618fae3551SRodney W. Grimes 
19628fae3551SRodney W. Grimes 	if (ep->ex_defdir) {
19638fae3551SRodney W. Grimes 		free_host(ep->ex_defdir->dp_hosts);
19648fae3551SRodney W. Grimes 		free((caddr_t)ep->ex_defdir);
19658fae3551SRodney W. Grimes 	}
19668fae3551SRodney W. Grimes 	if (ep->ex_fsdir)
19678fae3551SRodney W. Grimes 		free(ep->ex_fsdir);
1968cb3923e0SDoug Rabson 	if (ep->ex_indexfile)
1969cb3923e0SDoug Rabson 		free(ep->ex_indexfile);
19708fae3551SRodney W. Grimes 	free_dir(ep->ex_dirl);
19718fae3551SRodney W. Grimes 	free((caddr_t)ep);
19728fae3551SRodney W. Grimes }
19738fae3551SRodney W. Grimes 
19748fae3551SRodney W. Grimes /*
19758fae3551SRodney W. Grimes  * Free hosts.
19768fae3551SRodney W. Grimes  */
19778fae3551SRodney W. Grimes void
19788fae3551SRodney W. Grimes free_host(hp)
19798fae3551SRodney W. Grimes 	struct hostlist *hp;
19808fae3551SRodney W. Grimes {
19818fae3551SRodney W. Grimes 	struct hostlist *hp2;
19828fae3551SRodney W. Grimes 
19838fae3551SRodney W. Grimes 	while (hp) {
19848fae3551SRodney W. Grimes 		hp2 = hp;
19858fae3551SRodney W. Grimes 		hp = hp->ht_next;
19868fae3551SRodney W. Grimes 		free((caddr_t)hp2);
19878fae3551SRodney W. Grimes 	}
19888fae3551SRodney W. Grimes }
19898fae3551SRodney W. Grimes 
19908fae3551SRodney W. Grimes struct hostlist *
19918fae3551SRodney W. Grimes get_ht()
19928fae3551SRodney W. Grimes {
19938fae3551SRodney W. Grimes 	struct hostlist *hp;
19948fae3551SRodney W. Grimes 
19958fae3551SRodney W. Grimes 	hp = (struct hostlist *)malloc(sizeof (struct hostlist));
19968fae3551SRodney W. Grimes 	if (hp == (struct hostlist *)NULL)
19978fae3551SRodney W. Grimes 		out_of_mem();
19988fae3551SRodney W. Grimes 	hp->ht_next = (struct hostlist *)NULL;
1999a62dc406SDoug Rabson 	hp->ht_flag = 0;
20008fae3551SRodney W. Grimes 	return (hp);
20018fae3551SRodney W. Grimes }
20028fae3551SRodney W. Grimes 
20038fae3551SRodney W. Grimes /*
20048fae3551SRodney W. Grimes  * Out of memory, fatal
20058fae3551SRodney W. Grimes  */
20068fae3551SRodney W. Grimes void
20078fae3551SRodney W. Grimes out_of_mem()
20088fae3551SRodney W. Grimes {
20098fae3551SRodney W. Grimes 
201074853402SPhilippe Charnier 	syslog(LOG_ERR, "out of memory");
20118fae3551SRodney W. Grimes 	exit(2);
20128fae3551SRodney W. Grimes }
20138fae3551SRodney W. Grimes 
20148fae3551SRodney W. Grimes /*
20156a09faf2SCraig Rodrigues  * Do the nmount() syscall with the update flag to push the export info into
20168fae3551SRodney W. Grimes  * the kernel.
20178fae3551SRodney W. Grimes  */
20188fae3551SRodney W. Grimes int
20196a09faf2SCraig Rodrigues do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
20206a09faf2SCraig Rodrigues     struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb)
20218fae3551SRodney W. Grimes {
2022f93caef2SIan Dowse 	struct statfs fsb1;
20238360efbdSAlfred Perlstein 	struct addrinfo *ai;
20246a09faf2SCraig Rodrigues 	struct export_args eap;
20256a09faf2SCraig Rodrigues 	char errmsg[255];
20266a09faf2SCraig Rodrigues 	char *cp;
20278fae3551SRodney W. Grimes 	int done;
20286a09faf2SCraig Rodrigues 	char savedc;
20296a09faf2SCraig Rodrigues 	struct iovec *iov;
20306a09faf2SCraig Rodrigues 	int iovlen;
20316a09faf2SCraig Rodrigues 	int ret;
20328fae3551SRodney W. Grimes 
20336a09faf2SCraig Rodrigues 	cp = NULL;
20346a09faf2SCraig Rodrigues 	savedc = '\0';
20356a09faf2SCraig Rodrigues 	iov = NULL;
20366a09faf2SCraig Rodrigues 	iovlen = 0;
20376a09faf2SCraig Rodrigues 	ret = 0;
203860caaee2SIan Dowse 
20396a09faf2SCraig Rodrigues 	bzero(&eap, sizeof(eap));
20406a09faf2SCraig Rodrigues 	bzero(errmsg, sizeof(errmsg));
20416a09faf2SCraig Rodrigues 	eap.ex_flags = exflags;
20426a09faf2SCraig Rodrigues 	eap.ex_anon = *anoncrp;
20436a09faf2SCraig Rodrigues 	eap.ex_indexfile = ep->ex_indexfile;
20446d359f31SIan Dowse 	if (grp->gr_type == GT_HOST)
20458360efbdSAlfred Perlstein 		ai = grp->gr_ptr.gt_addrinfo;
20466d359f31SIan Dowse 	else
20476d359f31SIan Dowse 		ai = NULL;
20488fae3551SRodney W. Grimes 	done = FALSE;
20496a09faf2SCraig Rodrigues 
20506a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "fstype", NULL, 0);
20516a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "fspath", NULL, 0);
20526a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "from", NULL, 0);
20536a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "update", NULL, 0);
20546a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap));
20556a09faf2SCraig Rodrigues 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
20566a09faf2SCraig Rodrigues 
20578fae3551SRodney W. Grimes 	while (!done) {
20588fae3551SRodney W. Grimes 		switch (grp->gr_type) {
20598fae3551SRodney W. Grimes 		case GT_HOST:
20606d359f31SIan Dowse 			if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0)
20618360efbdSAlfred Perlstein 				goto skip;
20626a09faf2SCraig Rodrigues 			eap.ex_addr = ai->ai_addr;
20636a09faf2SCraig Rodrigues 			eap.ex_addrlen = ai->ai_addrlen;
20646a09faf2SCraig Rodrigues 			eap.ex_masklen = 0;
20658fae3551SRodney W. Grimes 			break;
20668fae3551SRodney W. Grimes 		case GT_NET:
206760caaee2SIan Dowse 			if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 &&
20688360efbdSAlfred Perlstein 			    have_v6 == 0)
20698360efbdSAlfred Perlstein 				goto skip;
20706a09faf2SCraig Rodrigues 			eap.ex_addr =
207160caaee2SIan Dowse 			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net;
20726a09faf2SCraig Rodrigues 			eap.ex_addrlen =
20736a09faf2SCraig Rodrigues 			    ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len;
20746a09faf2SCraig Rodrigues 			eap.ex_mask =
207560caaee2SIan Dowse 			    (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask;
20766a09faf2SCraig Rodrigues 			eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len;
20778fae3551SRodney W. Grimes 			break;
20786d359f31SIan Dowse 		case GT_DEFAULT:
20796a09faf2SCraig Rodrigues 			eap.ex_addr = NULL;
20806a09faf2SCraig Rodrigues 			eap.ex_addrlen = 0;
20816a09faf2SCraig Rodrigues 			eap.ex_mask = NULL;
20826a09faf2SCraig Rodrigues 			eap.ex_masklen = 0;
20836d359f31SIan Dowse 			break;
20848b5a6d67SBill Paul 		case GT_IGNORE:
20856a09faf2SCraig Rodrigues 			ret = 0;
20866a09faf2SCraig Rodrigues 			goto error_exit;
20878b5a6d67SBill Paul 			break;
20888fae3551SRodney W. Grimes 		default:
208974853402SPhilippe Charnier 			syslog(LOG_ERR, "bad grouptype");
20908fae3551SRodney W. Grimes 			if (cp)
20918fae3551SRodney W. Grimes 				*cp = savedc;
20926a09faf2SCraig Rodrigues 			ret = 1;
20936a09faf2SCraig Rodrigues 			goto error_exit;
20948fae3551SRodney W. Grimes 		};
20958fae3551SRodney W. Grimes 
20968fae3551SRodney W. Grimes 		/*
20978fae3551SRodney W. Grimes 		 * XXX:
20988fae3551SRodney W. Grimes 		 * Maybe I should just use the fsb->f_mntonname path instead
20998fae3551SRodney W. Grimes 		 * of looping back up the dirp to the mount point??
21008fae3551SRodney W. Grimes 		 * Also, needs to know how to export all types of local
210187564113SPeter Wemm 		 * exportable filesystems and not just "ufs".
21028fae3551SRodney W. Grimes 		 */
21036a09faf2SCraig Rodrigues 		iov[1].iov_base = fsb->f_fstypename; /* "fstype" */
21046a09faf2SCraig Rodrigues 		iov[1].iov_len = strlen(fsb->f_fstypename) + 1;
21056a09faf2SCraig Rodrigues 		iov[3].iov_base = fsb->f_mntonname; /* "fspath" */
21066a09faf2SCraig Rodrigues 		iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
21076a09faf2SCraig Rodrigues 		iov[5].iov_base = fsb->f_mntfromname; /* "from" */
21086a09faf2SCraig Rodrigues 		iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
21096a09faf2SCraig Rodrigues 
2110300a6ee8SRink Springer 		/*
2111300a6ee8SRink Springer 		 * Remount the filesystem, but chop off the MNT_ROOTFS flag
2112300a6ee8SRink Springer 		 * as it is used internally (and will result in an error if
2113300a6ee8SRink Springer 		 * specified)
2114300a6ee8SRink Springer 		 */
2115300a6ee8SRink Springer 		while (nmount(iov, iovlen, fsb->f_flags & ~MNT_ROOTFS) < 0) {
21168fae3551SRodney W. Grimes 			if (cp)
21178fae3551SRodney W. Grimes 				*cp-- = savedc;
21188fae3551SRodney W. Grimes 			else
21198fae3551SRodney W. Grimes 				cp = dirp + dirplen - 1;
21206a09faf2SCraig Rodrigues 			if (opt_flags & OP_QUIET) {
21216a09faf2SCraig Rodrigues 				ret = 1;
21226a09faf2SCraig Rodrigues 				goto error_exit;
21236a09faf2SCraig Rodrigues 			}
21248fae3551SRodney W. Grimes 			if (errno == EPERM) {
212501709abfSIan Dowse 				if (debug)
212601709abfSIan Dowse 					warnx("can't change attributes for %s",
212701709abfSIan Dowse 					    dirp);
21288fae3551SRodney W. Grimes 				syslog(LOG_ERR,
212974853402SPhilippe Charnier 				   "can't change attributes for %s", dirp);
21306a09faf2SCraig Rodrigues 				ret = 1;
21316a09faf2SCraig Rodrigues 				goto error_exit;
21328fae3551SRodney W. Grimes 			}
21338fae3551SRodney W. Grimes 			if (opt_flags & OP_ALLDIRS) {
2134288fa14aSJoerg Wunsch 				if (errno == EINVAL)
2135288fa14aSJoerg Wunsch 					syslog(LOG_ERR,
2136288fa14aSJoerg Wunsch 		"-alldirs requested but %s is not a filesystem mountpoint",
2137288fa14aSJoerg Wunsch 						dirp);
2138288fa14aSJoerg Wunsch 				else
2139288fa14aSJoerg Wunsch 					syslog(LOG_ERR,
2140288fa14aSJoerg Wunsch 						"could not remount %s: %m",
21413980ac4fSGarrett Wollman 						dirp);
21426a09faf2SCraig Rodrigues 				ret = 1;
21436a09faf2SCraig Rodrigues 				goto error_exit;
21448fae3551SRodney W. Grimes 			}
21458fae3551SRodney W. Grimes 			/* back up over the last component */
21468fae3551SRodney W. Grimes 			while (*cp == '/' && cp > dirp)
21478fae3551SRodney W. Grimes 				cp--;
21488fae3551SRodney W. Grimes 			while (*(cp - 1) != '/' && cp > dirp)
21498fae3551SRodney W. Grimes 				cp--;
21508fae3551SRodney W. Grimes 			if (cp == dirp) {
21518fae3551SRodney W. Grimes 				if (debug)
215274853402SPhilippe Charnier 					warnx("mnt unsucc");
215337518a88SCraig Rodrigues 				syslog(LOG_ERR, "can't export %s %s", dirp,
215437518a88SCraig Rodrigues 				    errmsg);
21556a09faf2SCraig Rodrigues 				ret = 1;
21566a09faf2SCraig Rodrigues 				goto error_exit;
21578fae3551SRodney W. Grimes 			}
21588fae3551SRodney W. Grimes 			savedc = *cp;
21598fae3551SRodney W. Grimes 			*cp = '\0';
2160f93caef2SIan Dowse 			/* Check that we're still on the same filesystem. */
2161f93caef2SIan Dowse 			if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid,
2162f93caef2SIan Dowse 			    &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) {
2163f93caef2SIan Dowse 				*cp = savedc;
216437518a88SCraig Rodrigues 				syslog(LOG_ERR, "can't export %s %s", dirp,
216537518a88SCraig Rodrigues 				    errmsg);
21666a09faf2SCraig Rodrigues 				ret = 1;
21676a09faf2SCraig Rodrigues 				goto error_exit;
2168f93caef2SIan Dowse 			}
21698fae3551SRodney W. Grimes 		}
21708360efbdSAlfred Perlstein skip:
21716d359f31SIan Dowse 		if (ai != NULL)
21728360efbdSAlfred Perlstein 			ai = ai->ai_next;
21738360efbdSAlfred Perlstein 		if (ai == NULL)
21748fae3551SRodney W. Grimes 			done = TRUE;
21758fae3551SRodney W. Grimes 	}
21768fae3551SRodney W. Grimes 	if (cp)
21778fae3551SRodney W. Grimes 		*cp = savedc;
21786a09faf2SCraig Rodrigues error_exit:
21796a09faf2SCraig Rodrigues 	/* free strings allocated by strdup() in getmntopts.c */
21806a09faf2SCraig Rodrigues 	if (iov != NULL) {
21816a09faf2SCraig Rodrigues 		free(iov[0].iov_base); /* fstype */
21826a09faf2SCraig Rodrigues 		free(iov[2].iov_base); /* fspath */
21836a09faf2SCraig Rodrigues 		free(iov[4].iov_base); /* from */
21846a09faf2SCraig Rodrigues 		free(iov[6].iov_base); /* update */
21856a09faf2SCraig Rodrigues 		free(iov[8].iov_base); /* export */
21866a09faf2SCraig Rodrigues 		free(iov[10].iov_base); /* errmsg */
21876a09faf2SCraig Rodrigues 
21886a09faf2SCraig Rodrigues 		/* free iov, allocated by realloc() */
21896a09faf2SCraig Rodrigues 		free(iov);
21906a09faf2SCraig Rodrigues 	}
21916a09faf2SCraig Rodrigues 	return (ret);
21928fae3551SRodney W. Grimes }
21938fae3551SRodney W. Grimes 
21948fae3551SRodney W. Grimes /*
21958fae3551SRodney W. Grimes  * Translate a net address.
219660caaee2SIan Dowse  *
219760caaee2SIan Dowse  * If `maskflg' is nonzero, then `cp' is a netmask, not a network address.
21988fae3551SRodney W. Grimes  */
21998fae3551SRodney W. Grimes int
22008fae3551SRodney W. Grimes get_net(cp, net, maskflg)
22018fae3551SRodney W. Grimes 	char *cp;
22028fae3551SRodney W. Grimes 	struct netmsk *net;
22038fae3551SRodney W. Grimes 	int maskflg;
22048fae3551SRodney W. Grimes {
2205931c04f1SIan Dowse 	struct netent *np = NULL;
22068360efbdSAlfred Perlstein 	char *name, *p, *prefp;
220760caaee2SIan Dowse 	struct sockaddr_in sin;
2208931c04f1SIan Dowse 	struct sockaddr *sa = NULL;
22098360efbdSAlfred Perlstein 	struct addrinfo hints, *ai = NULL;
22108360efbdSAlfred Perlstein 	char netname[NI_MAXHOST];
22118360efbdSAlfred Perlstein 	long preflen;
22128fae3551SRodney W. Grimes 
221301709abfSIan Dowse 	p = prefp = NULL;
22148360efbdSAlfred Perlstein 	if ((opt_flags & OP_MASKLEN) && !maskflg) {
22158360efbdSAlfred Perlstein 		p = strchr(cp, '/');
22168360efbdSAlfred Perlstein 		*p = '\0';
22178360efbdSAlfred Perlstein 		prefp = p + 1;
22188360efbdSAlfred Perlstein 	}
22198360efbdSAlfred Perlstein 
2220931c04f1SIan Dowse 	/*
2221931c04f1SIan Dowse 	 * Check for a numeric address first. We wish to avoid
2222931c04f1SIan Dowse 	 * possible DNS lookups in getnetbyname().
2223931c04f1SIan Dowse 	 */
2224931c04f1SIan Dowse 	if (isxdigit(*cp) || *cp == ':') {
22258360efbdSAlfred Perlstein 		memset(&hints, 0, sizeof hints);
222660caaee2SIan Dowse 		/* Ensure the mask and the network have the same family. */
222760caaee2SIan Dowse 		if (maskflg && (opt_flags & OP_NET))
222860caaee2SIan Dowse 			hints.ai_family = net->nt_net.ss_family;
222960caaee2SIan Dowse 		else if (!maskflg && (opt_flags & OP_HAVEMASK))
223060caaee2SIan Dowse 			hints.ai_family = net->nt_mask.ss_family;
223160caaee2SIan Dowse 		else
22328360efbdSAlfred Perlstein 			hints.ai_family = AF_UNSPEC;
22338360efbdSAlfred Perlstein 		hints.ai_flags = AI_NUMERICHOST;
2234931c04f1SIan Dowse 		if (getaddrinfo(cp, NULL, &hints, &ai) == 0)
2235931c04f1SIan Dowse 			sa = ai->ai_addr;
2236931c04f1SIan Dowse 		if (sa != NULL && ai->ai_family == AF_INET) {
22378fae3551SRodney W. Grimes 			/*
223860caaee2SIan Dowse 			 * The address in `cp' is really a network address, so
223960caaee2SIan Dowse 			 * use inet_network() to re-interpret this correctly.
224060caaee2SIan Dowse 			 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1.
22418fae3551SRodney W. Grimes 			 */
224260caaee2SIan Dowse 			bzero(&sin, sizeof sin);
22438360efbdSAlfred Perlstein 			sin.sin_family = AF_INET;
22448360efbdSAlfred Perlstein 			sin.sin_len = sizeof sin;
22458360efbdSAlfred Perlstein 			sin.sin_addr = inet_makeaddr(inet_network(cp), 0);
22468360efbdSAlfred Perlstein 			if (debug)
224760caaee2SIan Dowse 				fprintf(stderr, "get_net: v4 addr %s\n",
224860caaee2SIan Dowse 				    inet_ntoa(sin.sin_addr));
22498360efbdSAlfred Perlstein 			sa = (struct sockaddr *)&sin;
2250931c04f1SIan Dowse 		}
2251931c04f1SIan Dowse 	}
2252931c04f1SIan Dowse 	if (sa == NULL && (np = getnetbyname(cp)) != NULL) {
2253931c04f1SIan Dowse 		bzero(&sin, sizeof sin);
2254931c04f1SIan Dowse 		sin.sin_family = AF_INET;
2255931c04f1SIan Dowse 		sin.sin_len = sizeof sin;
2256931c04f1SIan Dowse 		sin.sin_addr = inet_makeaddr(np->n_net, 0);
2257931c04f1SIan Dowse 		sa = (struct sockaddr *)&sin;
2258931c04f1SIan Dowse 	}
2259931c04f1SIan Dowse 	if (sa == NULL)
22608360efbdSAlfred Perlstein 		goto fail;
22618360efbdSAlfred Perlstein 
226260caaee2SIan Dowse 	if (maskflg) {
226360caaee2SIan Dowse 		/* The specified sockaddr is a mask. */
226460caaee2SIan Dowse 		if (checkmask(sa) != 0)
22658360efbdSAlfred Perlstein 			goto fail;
226660caaee2SIan Dowse 		bcopy(sa, &net->nt_mask, sa->sa_len);
226760caaee2SIan Dowse 		opt_flags |= OP_HAVEMASK;
226860caaee2SIan Dowse 	} else {
226960caaee2SIan Dowse 		/* The specified sockaddr is a network address. */
227060caaee2SIan Dowse 		bcopy(sa, &net->nt_net, sa->sa_len);
22710f4b7baaSPaul Traina 
227260caaee2SIan Dowse 		/* Get a network name for the export list. */
227360caaee2SIan Dowse 		if (np) {
227460caaee2SIan Dowse 			name = np->n_name;
227560caaee2SIan Dowse 		} else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname,
22764f101318SHajimu UMEMOTO 		   NULL, 0, NI_NUMERICHOST) == 0) {
227760caaee2SIan Dowse 			name = netname;
227860caaee2SIan Dowse 		} else {
227960caaee2SIan Dowse 			goto fail;
228060caaee2SIan Dowse 		}
228160caaee2SIan Dowse 		if ((net->nt_name = strdup(name)) == NULL)
228260caaee2SIan Dowse 			out_of_mem();
228360caaee2SIan Dowse 
228460caaee2SIan Dowse 		/*
228560caaee2SIan Dowse 		 * Extract a mask from either a "/<masklen>" suffix, or
228660caaee2SIan Dowse 		 * from the class of an IPv4 address.
228760caaee2SIan Dowse 		 */
22888360efbdSAlfred Perlstein 		if (opt_flags & OP_MASKLEN) {
22898360efbdSAlfred Perlstein 			preflen = strtol(prefp, NULL, 10);
229060caaee2SIan Dowse 			if (preflen < 0L || preflen == LONG_MAX)
22918360efbdSAlfred Perlstein 				goto fail;
229260caaee2SIan Dowse 			bcopy(sa, &net->nt_mask, sa->sa_len);
229360caaee2SIan Dowse 			if (makemask(&net->nt_mask, (int)preflen) != 0)
229460caaee2SIan Dowse 				goto fail;
229560caaee2SIan Dowse 			opt_flags |= OP_HAVEMASK;
22968360efbdSAlfred Perlstein 			*p = '/';
229760caaee2SIan Dowse 		} else if (sa->sa_family == AF_INET &&
229860caaee2SIan Dowse 		    (opt_flags & OP_MASK) == 0) {
229960caaee2SIan Dowse 			in_addr_t addr;
23008360efbdSAlfred Perlstein 
230160caaee2SIan Dowse 			addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr;
230260caaee2SIan Dowse 			if (IN_CLASSA(addr))
230360caaee2SIan Dowse 				preflen = 8;
230460caaee2SIan Dowse 			else if (IN_CLASSB(addr))
230560caaee2SIan Dowse 				preflen = 16;
230660caaee2SIan Dowse 			else if (IN_CLASSC(addr))
230760caaee2SIan Dowse 				preflen = 24;
230860caaee2SIan Dowse 			else if (IN_CLASSD(addr))
230960caaee2SIan Dowse 				preflen = 28;
23108360efbdSAlfred Perlstein 			else
231160caaee2SIan Dowse 				preflen = 32;	/* XXX */
231260caaee2SIan Dowse 
231360caaee2SIan Dowse 			bcopy(sa, &net->nt_mask, sa->sa_len);
231460caaee2SIan Dowse 			makemask(&net->nt_mask, (int)preflen);
231560caaee2SIan Dowse 			opt_flags |= OP_HAVEMASK;
231660caaee2SIan Dowse 		}
23178360efbdSAlfred Perlstein 	}
23188360efbdSAlfred Perlstein 
23198360efbdSAlfred Perlstein 	if (ai)
23208360efbdSAlfred Perlstein 		freeaddrinfo(ai);
23218360efbdSAlfred Perlstein 	return 0;
23228360efbdSAlfred Perlstein 
23238360efbdSAlfred Perlstein fail:
23248360efbdSAlfred Perlstein 	if (ai)
23258360efbdSAlfred Perlstein 		freeaddrinfo(ai);
23268360efbdSAlfred Perlstein 	return 1;
23278fae3551SRodney W. Grimes }
23288fae3551SRodney W. Grimes 
23298fae3551SRodney W. Grimes /*
23308fae3551SRodney W. Grimes  * Parse out the next white space separated field
23318fae3551SRodney W. Grimes  */
23328fae3551SRodney W. Grimes void
23338fae3551SRodney W. Grimes nextfield(cp, endcp)
23348fae3551SRodney W. Grimes 	char **cp;
23358fae3551SRodney W. Grimes 	char **endcp;
23368fae3551SRodney W. Grimes {
23378fae3551SRodney W. Grimes 	char *p;
23388fae3551SRodney W. Grimes 
23398fae3551SRodney W. Grimes 	p = *cp;
23408fae3551SRodney W. Grimes 	while (*p == ' ' || *p == '\t')
23418fae3551SRodney W. Grimes 		p++;
23428fae3551SRodney W. Grimes 	if (*p == '\n' || *p == '\0')
23438fae3551SRodney W. Grimes 		*cp = *endcp = p;
23448fae3551SRodney W. Grimes 	else {
23458fae3551SRodney W. Grimes 		*cp = p++;
23468fae3551SRodney W. Grimes 		while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
23478fae3551SRodney W. Grimes 			p++;
23488fae3551SRodney W. Grimes 		*endcp = p;
23498fae3551SRodney W. Grimes 	}
23508fae3551SRodney W. Grimes }
23518fae3551SRodney W. Grimes 
23528fae3551SRodney W. Grimes /*
23538fae3551SRodney W. Grimes  * Get an exports file line. Skip over blank lines and handle line
23548fae3551SRodney W. Grimes  * continuations.
23558fae3551SRodney W. Grimes  */
23568fae3551SRodney W. Grimes int
23578fae3551SRodney W. Grimes get_line()
23588fae3551SRodney W. Grimes {
23598fae3551SRodney W. Grimes 	char *p, *cp;
236091ca1a91SIan Dowse 	size_t len;
23618fae3551SRodney W. Grimes 	int totlen, cont_line;
23628fae3551SRodney W. Grimes 
23638fae3551SRodney W. Grimes 	/*
23648fae3551SRodney W. Grimes 	 * Loop around ignoring blank lines and getting all continuation lines.
23658fae3551SRodney W. Grimes 	 */
23668fae3551SRodney W. Grimes 	p = line;
23678fae3551SRodney W. Grimes 	totlen = 0;
23688fae3551SRodney W. Grimes 	do {
236991ca1a91SIan Dowse 		if ((p = fgetln(exp_file, &len)) == NULL)
23708fae3551SRodney W. Grimes 			return (0);
23718fae3551SRodney W. Grimes 		cp = p + len - 1;
23728fae3551SRodney W. Grimes 		cont_line = 0;
23738fae3551SRodney W. Grimes 		while (cp >= p &&
23748fae3551SRodney W. Grimes 		    (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
23758fae3551SRodney W. Grimes 			if (*cp == '\\')
23768fae3551SRodney W. Grimes 				cont_line = 1;
23778fae3551SRodney W. Grimes 			cp--;
23788fae3551SRodney W. Grimes 			len--;
23798fae3551SRodney W. Grimes 		}
2380376f8390SDima Dorfman 		if (cont_line) {
2381376f8390SDima Dorfman 			*++cp = ' ';
2382376f8390SDima Dorfman 			len++;
2383376f8390SDima Dorfman 		}
238491ca1a91SIan Dowse 		if (linesize < len + totlen + 1) {
238591ca1a91SIan Dowse 			linesize = len + totlen + 1;
238691ca1a91SIan Dowse 			line = realloc(line, linesize);
238791ca1a91SIan Dowse 			if (line == NULL)
238891ca1a91SIan Dowse 				out_of_mem();
238991ca1a91SIan Dowse 		}
239091ca1a91SIan Dowse 		memcpy(line + totlen, p, len);
23918fae3551SRodney W. Grimes 		totlen += len;
239291ca1a91SIan Dowse 		line[totlen] = '\0';
23938fae3551SRodney W. Grimes 	} while (totlen == 0 || cont_line);
23948fae3551SRodney W. Grimes 	return (1);
23958fae3551SRodney W. Grimes }
23968fae3551SRodney W. Grimes 
23978fae3551SRodney W. Grimes /*
23988fae3551SRodney W. Grimes  * Parse a description of a credential.
23998fae3551SRodney W. Grimes  */
24008fae3551SRodney W. Grimes void
24018fae3551SRodney W. Grimes parsecred(namelist, cr)
24028fae3551SRodney W. Grimes 	char *namelist;
2403c0511d3bSBrian Feldman 	struct xucred *cr;
24048fae3551SRodney W. Grimes {
24058fae3551SRodney W. Grimes 	char *name;
24068fae3551SRodney W. Grimes 	int cnt;
24078fae3551SRodney W. Grimes 	char *names;
24088fae3551SRodney W. Grimes 	struct passwd *pw;
24098fae3551SRodney W. Grimes 	struct group *gr;
2410950cc395SStefan Farfeleder 	gid_t groups[NGROUPS + 1];
2411950cc395SStefan Farfeleder 	int ngroups;
24128fae3551SRodney W. Grimes 
241376183f34SDima Dorfman 	cr->cr_version = XUCRED_VERSION;
24148fae3551SRodney W. Grimes 	/*
241574853402SPhilippe Charnier 	 * Set up the unprivileged user.
24168fae3551SRodney W. Grimes 	 */
24178fae3551SRodney W. Grimes 	cr->cr_uid = -2;
24188fae3551SRodney W. Grimes 	cr->cr_groups[0] = -2;
24198fae3551SRodney W. Grimes 	cr->cr_ngroups = 1;
24208fae3551SRodney W. Grimes 	/*
24218fae3551SRodney W. Grimes 	 * Get the user's password table entry.
24228fae3551SRodney W. Grimes 	 */
24238fae3551SRodney W. Grimes 	names = strsep(&namelist, " \t\n");
24248fae3551SRodney W. Grimes 	name = strsep(&names, ":");
24258fae3551SRodney W. Grimes 	if (isdigit(*name) || *name == '-')
24268fae3551SRodney W. Grimes 		pw = getpwuid(atoi(name));
24278fae3551SRodney W. Grimes 	else
24288fae3551SRodney W. Grimes 		pw = getpwnam(name);
24298fae3551SRodney W. Grimes 	/*
24308fae3551SRodney W. Grimes 	 * Credentials specified as those of a user.
24318fae3551SRodney W. Grimes 	 */
24328fae3551SRodney W. Grimes 	if (names == NULL) {
24338fae3551SRodney W. Grimes 		if (pw == NULL) {
243474853402SPhilippe Charnier 			syslog(LOG_ERR, "unknown user: %s", name);
24358fae3551SRodney W. Grimes 			return;
24368fae3551SRodney W. Grimes 		}
24378fae3551SRodney W. Grimes 		cr->cr_uid = pw->pw_uid;
24388fae3551SRodney W. Grimes 		ngroups = NGROUPS + 1;
24398fae3551SRodney W. Grimes 		if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
244074853402SPhilippe Charnier 			syslog(LOG_ERR, "too many groups");
24418fae3551SRodney W. Grimes 		/*
2442950cc395SStefan Farfeleder 		 * Compress out duplicate.
24438fae3551SRodney W. Grimes 		 */
24448fae3551SRodney W. Grimes 		cr->cr_ngroups = ngroups - 1;
24458fae3551SRodney W. Grimes 		cr->cr_groups[0] = groups[0];
24468fae3551SRodney W. Grimes 		for (cnt = 2; cnt < ngroups; cnt++)
24478fae3551SRodney W. Grimes 			cr->cr_groups[cnt - 1] = groups[cnt];
24488fae3551SRodney W. Grimes 		return;
24498fae3551SRodney W. Grimes 	}
24508fae3551SRodney W. Grimes 	/*
24518fae3551SRodney W. Grimes 	 * Explicit credential specified as a colon separated list:
24528fae3551SRodney W. Grimes 	 *	uid:gid:gid:...
24538fae3551SRodney W. Grimes 	 */
24548fae3551SRodney W. Grimes 	if (pw != NULL)
24558fae3551SRodney W. Grimes 		cr->cr_uid = pw->pw_uid;
24568fae3551SRodney W. Grimes 	else if (isdigit(*name) || *name == '-')
24578fae3551SRodney W. Grimes 		cr->cr_uid = atoi(name);
24588fae3551SRodney W. Grimes 	else {
245974853402SPhilippe Charnier 		syslog(LOG_ERR, "unknown user: %s", name);
24608fae3551SRodney W. Grimes 		return;
24618fae3551SRodney W. Grimes 	}
24628fae3551SRodney W. Grimes 	cr->cr_ngroups = 0;
24638fae3551SRodney W. Grimes 	while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
24648fae3551SRodney W. Grimes 		name = strsep(&names, ":");
24658fae3551SRodney W. Grimes 		if (isdigit(*name) || *name == '-') {
24668fae3551SRodney W. Grimes 			cr->cr_groups[cr->cr_ngroups++] = atoi(name);
24678fae3551SRodney W. Grimes 		} else {
24688fae3551SRodney W. Grimes 			if ((gr = getgrnam(name)) == NULL) {
246974853402SPhilippe Charnier 				syslog(LOG_ERR, "unknown group: %s", name);
24708fae3551SRodney W. Grimes 				continue;
24718fae3551SRodney W. Grimes 			}
24728fae3551SRodney W. Grimes 			cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
24738fae3551SRodney W. Grimes 		}
24748fae3551SRodney W. Grimes 	}
24758fae3551SRodney W. Grimes 	if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
247674853402SPhilippe Charnier 		syslog(LOG_ERR, "too many groups");
24778fae3551SRodney W. Grimes }
24788fae3551SRodney W. Grimes 
24798fae3551SRodney W. Grimes #define	STRSIZ	(RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
24808fae3551SRodney W. Grimes /*
24818fae3551SRodney W. Grimes  * Routines that maintain the remote mounttab
24828fae3551SRodney W. Grimes  */
24838fae3551SRodney W. Grimes void
24848fae3551SRodney W. Grimes get_mountlist()
24858fae3551SRodney W. Grimes {
24868fae3551SRodney W. Grimes 	struct mountlist *mlp, **mlpp;
248787564113SPeter Wemm 	char *host, *dirp, *cp;
24888fae3551SRodney W. Grimes 	char str[STRSIZ];
24898fae3551SRodney W. Grimes 	FILE *mlfile;
24908fae3551SRodney W. Grimes 
24918fae3551SRodney W. Grimes 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
249239539916SBill Fumerola 		if (errno == ENOENT)
249339539916SBill Fumerola 			return;
249439539916SBill Fumerola 		else {
249574853402SPhilippe Charnier 			syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST);
24968fae3551SRodney W. Grimes 			return;
24978fae3551SRodney W. Grimes 		}
249839539916SBill Fumerola 	}
24998fae3551SRodney W. Grimes 	mlpp = &mlhead;
25008fae3551SRodney W. Grimes 	while (fgets(str, STRSIZ, mlfile) != NULL) {
250187564113SPeter Wemm 		cp = str;
250287564113SPeter Wemm 		host = strsep(&cp, " \t\n");
250387564113SPeter Wemm 		dirp = strsep(&cp, " \t\n");
250487564113SPeter Wemm 		if (host == NULL || dirp == NULL)
25058fae3551SRodney W. Grimes 			continue;
25068fae3551SRodney W. Grimes 		mlp = (struct mountlist *)malloc(sizeof (*mlp));
250774853402SPhilippe Charnier 		if (mlp == (struct mountlist *)NULL)
250874853402SPhilippe Charnier 			out_of_mem();
250987564113SPeter Wemm 		strncpy(mlp->ml_host, host, RPCMNT_NAMELEN);
251087564113SPeter Wemm 		mlp->ml_host[RPCMNT_NAMELEN] = '\0';
251187564113SPeter Wemm 		strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
251287564113SPeter Wemm 		mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
25138fae3551SRodney W. Grimes 		mlp->ml_next = (struct mountlist *)NULL;
25148fae3551SRodney W. Grimes 		*mlpp = mlp;
25158fae3551SRodney W. Grimes 		mlpp = &mlp->ml_next;
25168fae3551SRodney W. Grimes 	}
25178fae3551SRodney W. Grimes 	fclose(mlfile);
25188fae3551SRodney W. Grimes }
25198fae3551SRodney W. Grimes 
252001709abfSIan Dowse void
252101709abfSIan Dowse del_mlist(char *hostp, char *dirp)
25228fae3551SRodney W. Grimes {
25238fae3551SRodney W. Grimes 	struct mountlist *mlp, **mlpp;
25248fae3551SRodney W. Grimes 	struct mountlist *mlp2;
25258fae3551SRodney W. Grimes 	FILE *mlfile;
25268fae3551SRodney W. Grimes 	int fnd = 0;
25278fae3551SRodney W. Grimes 
25288fae3551SRodney W. Grimes 	mlpp = &mlhead;
25298fae3551SRodney W. Grimes 	mlp = mlhead;
25308fae3551SRodney W. Grimes 	while (mlp) {
25318fae3551SRodney W. Grimes 		if (!strcmp(mlp->ml_host, hostp) &&
25328fae3551SRodney W. Grimes 		    (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
25338fae3551SRodney W. Grimes 			fnd = 1;
25348fae3551SRodney W. Grimes 			mlp2 = mlp;
25358fae3551SRodney W. Grimes 			*mlpp = mlp = mlp->ml_next;
25368fae3551SRodney W. Grimes 			free((caddr_t)mlp2);
25378fae3551SRodney W. Grimes 		} else {
25388fae3551SRodney W. Grimes 			mlpp = &mlp->ml_next;
25398fae3551SRodney W. Grimes 			mlp = mlp->ml_next;
25408fae3551SRodney W. Grimes 		}
25418fae3551SRodney W. Grimes 	}
25428fae3551SRodney W. Grimes 	if (fnd) {
25438fae3551SRodney W. Grimes 		if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
254474853402SPhilippe Charnier 			syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST);
25458fae3551SRodney W. Grimes 			return;
25468fae3551SRodney W. Grimes 		}
25478fae3551SRodney W. Grimes 		mlp = mlhead;
25488fae3551SRodney W. Grimes 		while (mlp) {
25498fae3551SRodney W. Grimes 			fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
25508fae3551SRodney W. Grimes 			mlp = mlp->ml_next;
25518fae3551SRodney W. Grimes 		}
25528fae3551SRodney W. Grimes 		fclose(mlfile);
25538fae3551SRodney W. Grimes 	}
25548fae3551SRodney W. Grimes }
25558fae3551SRodney W. Grimes 
25568fae3551SRodney W. Grimes void
25578fae3551SRodney W. Grimes add_mlist(hostp, dirp)
25588fae3551SRodney W. Grimes 	char *hostp, *dirp;
25598fae3551SRodney W. Grimes {
25608fae3551SRodney W. Grimes 	struct mountlist *mlp, **mlpp;
25618fae3551SRodney W. Grimes 	FILE *mlfile;
25628fae3551SRodney W. Grimes 
25638fae3551SRodney W. Grimes 	mlpp = &mlhead;
25648fae3551SRodney W. Grimes 	mlp = mlhead;
25658fae3551SRodney W. Grimes 	while (mlp) {
25668fae3551SRodney W. Grimes 		if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
25678fae3551SRodney W. Grimes 			return;
25688fae3551SRodney W. Grimes 		mlpp = &mlp->ml_next;
25698fae3551SRodney W. Grimes 		mlp = mlp->ml_next;
25708fae3551SRodney W. Grimes 	}
25718fae3551SRodney W. Grimes 	mlp = (struct mountlist *)malloc(sizeof (*mlp));
257274853402SPhilippe Charnier 	if (mlp == (struct mountlist *)NULL)
257374853402SPhilippe Charnier 		out_of_mem();
25748fae3551SRodney W. Grimes 	strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
25758fae3551SRodney W. Grimes 	mlp->ml_host[RPCMNT_NAMELEN] = '\0';
25768fae3551SRodney W. Grimes 	strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
25778fae3551SRodney W. Grimes 	mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
25788fae3551SRodney W. Grimes 	mlp->ml_next = (struct mountlist *)NULL;
25798fae3551SRodney W. Grimes 	*mlpp = mlp;
25808fae3551SRodney W. Grimes 	if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
258174853402SPhilippe Charnier 		syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST);
25828fae3551SRodney W. Grimes 		return;
25838fae3551SRodney W. Grimes 	}
25848fae3551SRodney W. Grimes 	fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
25858fae3551SRodney W. Grimes 	fclose(mlfile);
25868fae3551SRodney W. Grimes }
25878fae3551SRodney W. Grimes 
25888fae3551SRodney W. Grimes /*
25898fae3551SRodney W. Grimes  * Free up a group list.
25908fae3551SRodney W. Grimes  */
25918fae3551SRodney W. Grimes void
25928fae3551SRodney W. Grimes free_grp(grp)
25938fae3551SRodney W. Grimes 	struct grouplist *grp;
25948fae3551SRodney W. Grimes {
25958fae3551SRodney W. Grimes 	if (grp->gr_type == GT_HOST) {
25968360efbdSAlfred Perlstein 		if (grp->gr_ptr.gt_addrinfo != NULL)
25978360efbdSAlfred Perlstein 			freeaddrinfo(grp->gr_ptr.gt_addrinfo);
25988fae3551SRodney W. Grimes 	} else if (grp->gr_type == GT_NET) {
25998fae3551SRodney W. Grimes 		if (grp->gr_ptr.gt_net.nt_name)
26008fae3551SRodney W. Grimes 			free(grp->gr_ptr.gt_net.nt_name);
26018fae3551SRodney W. Grimes 	}
26028fae3551SRodney W. Grimes 	free((caddr_t)grp);
26038fae3551SRodney W. Grimes }
26048fae3551SRodney W. Grimes 
26058fae3551SRodney W. Grimes #ifdef DEBUG
26068fae3551SRodney W. Grimes void
26078fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...)
26088fae3551SRodney W. Grimes {
26098fae3551SRodney W. Grimes 	va_list ap;
26108fae3551SRodney W. Grimes 
26118fae3551SRodney W. Grimes 	va_start(ap, fmt);
26128fae3551SRodney W. Grimes 	vfprintf(stderr, fmt, ap);
26138fae3551SRodney W. Grimes 	va_end(ap);
26148fae3551SRodney W. Grimes }
26158fae3551SRodney W. Grimes #endif /* DEBUG */
26168fae3551SRodney W. Grimes 
26178fae3551SRodney W. Grimes /*
26188fae3551SRodney W. Grimes  * Check options for consistency.
26198fae3551SRodney W. Grimes  */
26208fae3551SRodney W. Grimes int
26218fae3551SRodney W. Grimes check_options(dp)
26228fae3551SRodney W. Grimes 	struct dirlist *dp;
26238fae3551SRodney W. Grimes {
26248fae3551SRodney W. Grimes 
26258fae3551SRodney W. Grimes 	if (dp == (struct dirlist *)NULL)
26268fae3551SRodney W. Grimes 	    return (1);
262791196234SPeter Wemm 	if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) {
262891196234SPeter Wemm 	    syslog(LOG_ERR, "-mapall and -maproot mutually exclusive");
26298fae3551SRodney W. Grimes 	    return (1);
26308fae3551SRodney W. Grimes 	}
26318fae3551SRodney W. Grimes 	if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
263260caaee2SIan Dowse 		syslog(LOG_ERR, "-mask requires -network");
263360caaee2SIan Dowse 		return (1);
263460caaee2SIan Dowse 	}
263560caaee2SIan Dowse 	if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) {
263660caaee2SIan Dowse 		syslog(LOG_ERR, "-network requires mask specification");
263760caaee2SIan Dowse 		return (1);
263860caaee2SIan Dowse 	}
263960caaee2SIan Dowse 	if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) {
264060caaee2SIan Dowse 		syslog(LOG_ERR, "-mask and /masklen are mutually exclusive");
26418fae3551SRodney W. Grimes 		return (1);
26428fae3551SRodney W. Grimes 	}
26438fae3551SRodney W. Grimes 	if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
26446436fcb9SAlexander Langer 	    syslog(LOG_ERR, "-alldirs has multiple directories");
26458fae3551SRodney W. Grimes 	    return (1);
26468fae3551SRodney W. Grimes 	}
26478fae3551SRodney W. Grimes 	return (0);
26488fae3551SRodney W. Grimes }
26498fae3551SRodney W. Grimes 
26508fae3551SRodney W. Grimes /*
26518fae3551SRodney W. Grimes  * Check an absolute directory path for any symbolic links. Return true
26528fae3551SRodney W. Grimes  */
26538fae3551SRodney W. Grimes int
26548fae3551SRodney W. Grimes check_dirpath(dirp)
26558fae3551SRodney W. Grimes 	char *dirp;
26568fae3551SRodney W. Grimes {
26578fae3551SRodney W. Grimes 	char *cp;
26588fae3551SRodney W. Grimes 	int ret = 1;
26598fae3551SRodney W. Grimes 	struct stat sb;
26608fae3551SRodney W. Grimes 
26618fae3551SRodney W. Grimes 	cp = dirp + 1;
26628fae3551SRodney W. Grimes 	while (*cp && ret) {
26638fae3551SRodney W. Grimes 		if (*cp == '/') {
26648fae3551SRodney W. Grimes 			*cp = '\0';
2665a62dc406SDoug Rabson 			if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
26668fae3551SRodney W. Grimes 				ret = 0;
26678fae3551SRodney W. Grimes 			*cp = '/';
26688fae3551SRodney W. Grimes 		}
26698fae3551SRodney W. Grimes 		cp++;
26708fae3551SRodney W. Grimes 	}
2671a62dc406SDoug Rabson 	if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
26728fae3551SRodney W. Grimes 		ret = 0;
26738fae3551SRodney W. Grimes 	return (ret);
26748fae3551SRodney W. Grimes }
2675a62dc406SDoug Rabson 
267660caaee2SIan Dowse /*
267760caaee2SIan Dowse  * Make a netmask according to the specified prefix length. The ss_family
267860caaee2SIan Dowse  * and other non-address fields must be initialised before calling this.
267960caaee2SIan Dowse  */
268060caaee2SIan Dowse int
268160caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen)
26828360efbdSAlfred Perlstein {
268360caaee2SIan Dowse 	u_char *p;
268460caaee2SIan Dowse 	int bits, i, len;
26858360efbdSAlfred Perlstein 
268660caaee2SIan Dowse 	if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL)
268760caaee2SIan Dowse 		return (-1);
268889fdc4e1SMike Barcroft 	if (bitlen > len * CHAR_BIT)
268960caaee2SIan Dowse 		return (-1);
26908360efbdSAlfred Perlstein 
269160caaee2SIan Dowse 	for (i = 0; i < len; i++) {
269289fdc4e1SMike Barcroft 		bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen;
269360caaee2SIan Dowse 		*p++ = (1 << bits) - 1;
269460caaee2SIan Dowse 		bitlen -= bits;
26958360efbdSAlfred Perlstein 	}
26968360efbdSAlfred Perlstein 	return 0;
26978360efbdSAlfred Perlstein }
26988360efbdSAlfred Perlstein 
269960caaee2SIan Dowse /*
270060caaee2SIan Dowse  * Check that the sockaddr is a valid netmask. Returns 0 if the mask
270160caaee2SIan Dowse  * is acceptable (i.e. of the form 1...10....0).
270260caaee2SIan Dowse  */
270360caaee2SIan Dowse int
270460caaee2SIan Dowse checkmask(struct sockaddr *sa)
27058360efbdSAlfred Perlstein {
270660caaee2SIan Dowse 	u_char *mask;
270760caaee2SIan Dowse 	int i, len;
270860caaee2SIan Dowse 
270960caaee2SIan Dowse 	if ((mask = sa_rawaddr(sa, &len)) == NULL)
271060caaee2SIan Dowse 		return (-1);
271160caaee2SIan Dowse 
271260caaee2SIan Dowse 	for (i = 0; i < len; i++)
271360caaee2SIan Dowse 		if (mask[i] != 0xff)
271460caaee2SIan Dowse 			break;
271560caaee2SIan Dowse 	if (i < len) {
271660caaee2SIan Dowse 		if (~mask[i] & (u_char)(~mask[i] + 1))
271760caaee2SIan Dowse 			return (-1);
271860caaee2SIan Dowse 		i++;
271960caaee2SIan Dowse 	}
272060caaee2SIan Dowse 	for (; i < len; i++)
272160caaee2SIan Dowse 		if (mask[i] != 0)
272260caaee2SIan Dowse 			return (-1);
272360caaee2SIan Dowse 	return (0);
272460caaee2SIan Dowse }
272560caaee2SIan Dowse 
272660caaee2SIan Dowse /*
272760caaee2SIan Dowse  * Compare two sockaddrs according to a specified mask. Return zero if
272860caaee2SIan Dowse  * `sa1' matches `sa2' when filtered by the netmask in `samask'.
272960caaee2SIan Dowse  * If samask is NULL, perform a full comparision.
273060caaee2SIan Dowse  */
273160caaee2SIan Dowse int
273260caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask)
273360caaee2SIan Dowse {
273460caaee2SIan Dowse 	unsigned char *p1, *p2, *mask;
273560caaee2SIan Dowse 	int len, i;
273660caaee2SIan Dowse 
273760caaee2SIan Dowse 	if (sa1->sa_family != sa2->sa_family ||
273860caaee2SIan Dowse 	    (p1 = sa_rawaddr(sa1, &len)) == NULL ||
273960caaee2SIan Dowse 	    (p2 = sa_rawaddr(sa2, NULL)) == NULL)
274060caaee2SIan Dowse 		return (1);
274160caaee2SIan Dowse 
274260caaee2SIan Dowse 	switch (sa1->sa_family) {
274360caaee2SIan Dowse 	case AF_INET6:
274460caaee2SIan Dowse 		if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
274560caaee2SIan Dowse 		    ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
274660caaee2SIan Dowse 			return (1);
274760caaee2SIan Dowse 		break;
274860caaee2SIan Dowse 	}
274960caaee2SIan Dowse 
275060caaee2SIan Dowse 	/* Simple binary comparison if no mask specified. */
275160caaee2SIan Dowse 	if (samask == NULL)
275260caaee2SIan Dowse 		return (memcmp(p1, p2, len));
275360caaee2SIan Dowse 
275460caaee2SIan Dowse 	/* Set up the mask, and do a mask-based comparison. */
275560caaee2SIan Dowse 	if (sa1->sa_family != samask->sa_family ||
275660caaee2SIan Dowse 	    (mask = sa_rawaddr(samask, NULL)) == NULL)
275760caaee2SIan Dowse 		return (1);
275860caaee2SIan Dowse 
275960caaee2SIan Dowse 	for (i = 0; i < len; i++)
276060caaee2SIan Dowse 		if ((p1[i] & mask[i]) != (p2[i] & mask[i]))
276160caaee2SIan Dowse 			return (1);
276260caaee2SIan Dowse 	return (0);
276360caaee2SIan Dowse }
276460caaee2SIan Dowse 
276560caaee2SIan Dowse /*
276660caaee2SIan Dowse  * Return a pointer to the part of the sockaddr that contains the
276760caaee2SIan Dowse  * raw address, and set *nbytes to its length in bytes. Returns
276860caaee2SIan Dowse  * NULL if the address family is unknown.
276960caaee2SIan Dowse  */
277060caaee2SIan Dowse void *
277160caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) {
277260caaee2SIan Dowse 	void *p;
277360caaee2SIan Dowse 	int len;
27748360efbdSAlfred Perlstein 
27758360efbdSAlfred Perlstein 	switch (sa->sa_family) {
27768360efbdSAlfred Perlstein 	case AF_INET:
277760caaee2SIan Dowse 		len = sizeof(((struct sockaddr_in *)sa)->sin_addr);
277860caaee2SIan Dowse 		p = &((struct sockaddr_in *)sa)->sin_addr;
27798360efbdSAlfred Perlstein 		break;
27808360efbdSAlfred Perlstein 	case AF_INET6:
278160caaee2SIan Dowse 		len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr);
278260caaee2SIan Dowse 		p = &((struct sockaddr_in6 *)sa)->sin6_addr;
27838360efbdSAlfred Perlstein 		break;
27848360efbdSAlfred Perlstein 	default:
278560caaee2SIan Dowse 		p = NULL;
278660caaee2SIan Dowse 		len = 0;
27878360efbdSAlfred Perlstein 	}
27888360efbdSAlfred Perlstein 
278960caaee2SIan Dowse 	if (nbytes != NULL)
279060caaee2SIan Dowse 		*nbytes = len;
279160caaee2SIan Dowse 	return (p);
27928360efbdSAlfred Perlstein }
27938360efbdSAlfred Perlstein 
279469d65572SIan Dowse void
279569d65572SIan Dowse huphandler(int sig)
279669d65572SIan Dowse {
279769d65572SIan Dowse 	got_sighup = 1;
279869d65572SIan Dowse }
279969d65572SIan Dowse 
28008360efbdSAlfred Perlstein void terminate(sig)
28018360efbdSAlfred Perlstein int sig;
28028360efbdSAlfred Perlstein {
2803a032b226SPawel Jakub Dawidek 	pidfile_remove(pfh);
28047b98a1d6SAlfred Perlstein 	rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL);
28057b98a1d6SAlfred Perlstein 	rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL);
28068360efbdSAlfred Perlstein 	exit (0);
28078360efbdSAlfred Perlstein }
2808