18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 48fae3551SRodney W. Grimes * Copyright (c) 1989, 1993 58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 68fae3551SRodney W. Grimes * 78fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 88fae3551SRodney W. Grimes * Herb Hasler and Rick Macklem at The University of Guelph. 98fae3551SRodney W. Grimes * 108fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 118fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 128fae3551SRodney W. Grimes * are met: 138fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 158fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 168fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 178fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 198fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 208fae3551SRodney W. Grimes * without specific prior written permission. 218fae3551SRodney W. Grimes * 228fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 238fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 248fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 258fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 268fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 278fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 288fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 298fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 308fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 318fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 328fae3551SRodney W. Grimes * SUCH DAMAGE. 338fae3551SRodney W. Grimes */ 348fae3551SRodney W. Grimes 358fae3551SRodney W. Grimes #ifndef lint 3674853402SPhilippe Charnier static const char copyright[] = 378fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\ 388fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 39d599144dSGarrett Wollman #endif /*not lint*/ 408fae3551SRodney W. Grimes 4174853402SPhilippe Charnier #if 0 4275201fa4SPhilippe Charnier #ifndef lint 4374853402SPhilippe Charnier static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 44d599144dSGarrett Wollman #endif /*not lint*/ 4575201fa4SPhilippe Charnier #endif 4675201fa4SPhilippe Charnier 4775201fa4SPhilippe Charnier #include <sys/cdefs.h> 4875201fa4SPhilippe Charnier __FBSDID("$FreeBSD$"); 498fae3551SRodney W. Grimes 508fae3551SRodney W. Grimes #include <sys/param.h> 513e2d36ffSRick Macklem #include <sys/conf.h> 528360efbdSAlfred Perlstein #include <sys/fcntl.h> 5346a6b5c4SRick Macklem #include <sys/fnv_hash.h> 5491ca1a91SIan Dowse #include <sys/linker.h> 5591ca1a91SIan Dowse #include <sys/module.h> 56bcc1d071SRick Macklem #include <sys/mount.h> 57c9ac0f71SEmmanuel Vadot #include <sys/queue.h> 58bcc1d071SRick Macklem #include <sys/stat.h> 59bcc1d071SRick Macklem #include <sys/sysctl.h> 60bcc1d071SRick Macklem #include <sys/syslog.h> 618fae3551SRodney W. Grimes 628fae3551SRodney W. Grimes #include <rpc/rpc.h> 63bcb53b16SMartin Blapp #include <rpc/rpc_com.h> 648fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 658360efbdSAlfred Perlstein #include <rpc/pmap_prot.h> 668360efbdSAlfred Perlstein #include <rpcsvc/mount.h> 67a62dc406SDoug Rabson #include <nfs/nfsproto.h> 68bcc1d071SRick Macklem #include <nfs/nfssvc.h> 6991196234SPeter Wemm #include <nfsserver/nfs.h> 708fae3551SRodney W. Grimes 71bcc1d071SRick Macklem #include <fs/nfs/nfsport.h> 72bcc1d071SRick Macklem 738fae3551SRodney W. Grimes #include <arpa/inet.h> 748fae3551SRodney W. Grimes 758fae3551SRodney W. Grimes #include <ctype.h> 7674853402SPhilippe Charnier #include <err.h> 778fae3551SRodney W. Grimes #include <errno.h> 788fae3551SRodney W. Grimes #include <grp.h> 79a032b226SPawel Jakub Dawidek #include <libutil.h> 8089fdc4e1SMike Barcroft #include <limits.h> 818fae3551SRodney W. Grimes #include <netdb.h> 828fae3551SRodney W. Grimes #include <pwd.h> 838fae3551SRodney W. Grimes #include <signal.h> 848fae3551SRodney W. Grimes #include <stdio.h> 858fae3551SRodney W. Grimes #include <stdlib.h> 868fae3551SRodney W. Grimes #include <string.h> 878fae3551SRodney W. Grimes #include <unistd.h> 888fae3551SRodney W. Grimes #include "pathnames.h" 896a09faf2SCraig Rodrigues #include "mntopts.h" 908fae3551SRodney W. Grimes 918fae3551SRodney W. Grimes #ifdef DEBUG 928fae3551SRodney W. Grimes #include <stdarg.h> 938fae3551SRodney W. Grimes #endif 948fae3551SRodney W. Grimes 958fae3551SRodney W. Grimes /* 968fae3551SRodney W. Grimes * Structures for keeping the mount list and export list 978fae3551SRodney W. Grimes */ 988fae3551SRodney W. Grimes struct mountlist { 990775314bSDoug Rabson char ml_host[MNTNAMLEN+1]; 1000775314bSDoug Rabson char ml_dirp[MNTPATHLEN+1]; 1011da3e8b0SEmmanuel Vadot 1021da3e8b0SEmmanuel Vadot SLIST_ENTRY(mountlist) next; 1038fae3551SRodney W. Grimes }; 1048fae3551SRodney W. Grimes 1058fae3551SRodney W. Grimes struct dirlist { 1068fae3551SRodney W. Grimes struct dirlist *dp_left; 1078fae3551SRodney W. Grimes struct dirlist *dp_right; 1088fae3551SRodney W. Grimes int dp_flag; 1098fae3551SRodney W. Grimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 110380a3fcdSEmmanuel Vadot char *dp_dirp; 1118fae3551SRodney W. Grimes }; 1128fae3551SRodney W. Grimes /* dp_flag bits */ 1138fae3551SRodney W. Grimes #define DP_DEFSET 0x1 114a62dc406SDoug Rabson #define DP_HOSTSET 0x2 1158fae3551SRodney W. Grimes 116cc5efddeSRick Macklem /* 117cc5efddeSRick Macklem * maproot/mapall credentials. 118*2ffad162SRick Macklem * cr_smallgrps can be used for a group list up to SMALLNGROUPS in size. 119*2ffad162SRick Macklem * Larger group lists are malloc'd/free'd. 120cc5efddeSRick Macklem */ 121*2ffad162SRick Macklem #define SMALLNGROUPS 32 122cc5efddeSRick Macklem struct expcred { 123cc5efddeSRick Macklem uid_t cr_uid; 124cc5efddeSRick Macklem int cr_ngroups; 125*2ffad162SRick Macklem gid_t cr_smallgrps[SMALLNGROUPS]; 126*2ffad162SRick Macklem gid_t *cr_groups; 127cc5efddeSRick Macklem }; 128cc5efddeSRick Macklem 1298fae3551SRodney W. Grimes struct exportlist { 1308fae3551SRodney W. Grimes struct dirlist *ex_dirl; 1318fae3551SRodney W. Grimes struct dirlist *ex_defdir; 132711d44eeSRick Macklem struct grouplist *ex_grphead; 1338fae3551SRodney W. Grimes int ex_flag; 1348fae3551SRodney W. Grimes fsid_t ex_fs; 1358fae3551SRodney W. Grimes char *ex_fsdir; 136cb3923e0SDoug Rabson char *ex_indexfile; 137cc5efddeSRick Macklem struct expcred ex_defanon; 138cc5efddeSRick Macklem uint64_t ex_defexflags; 139a9148abdSDoug Rabson int ex_numsecflavors; 140a9148abdSDoug Rabson int ex_secflavors[MAXSECFLAVORS]; 141c3f86a25SRick Macklem int ex_defnumsecflavors; 142c3f86a25SRick Macklem int ex_defsecflavors[MAXSECFLAVORS]; 143c9ac0f71SEmmanuel Vadot 144c9ac0f71SEmmanuel Vadot SLIST_ENTRY(exportlist) entries; 1458fae3551SRodney W. Grimes }; 1468fae3551SRodney W. Grimes /* ex_flag bits */ 1478fae3551SRodney W. Grimes #define EX_LINKED 0x1 1480f0869bcSRick Macklem #define EX_DONE 0x2 1490f0869bcSRick Macklem #define EX_DEFSET 0x4 1500f0869bcSRick Macklem #define EX_PUBLICFH 0x8 1518fae3551SRodney W. Grimes 1521a9a992fSRick Macklem SLIST_HEAD(exportlisthead, exportlist); 1531a9a992fSRick Macklem 1548fae3551SRodney W. Grimes struct netmsk { 1558360efbdSAlfred Perlstein struct sockaddr_storage nt_net; 15660caaee2SIan Dowse struct sockaddr_storage nt_mask; 1578fae3551SRodney W. Grimes char *nt_name; 1588fae3551SRodney W. Grimes }; 1598fae3551SRodney W. Grimes 1608fae3551SRodney W. Grimes union grouptypes { 1618360efbdSAlfred Perlstein struct addrinfo *gt_addrinfo; 1628fae3551SRodney W. Grimes struct netmsk gt_net; 1638fae3551SRodney W. Grimes }; 1648fae3551SRodney W. Grimes 1658fae3551SRodney W. Grimes struct grouplist { 1668fae3551SRodney W. Grimes int gr_type; 1678fae3551SRodney W. Grimes union grouptypes gr_ptr; 1688fae3551SRodney W. Grimes struct grouplist *gr_next; 169cc5efddeSRick Macklem struct expcred gr_anon; 170cc5efddeSRick Macklem uint64_t gr_exflags; 1710f0869bcSRick Macklem int gr_flag; 172c3f86a25SRick Macklem int gr_numsecflavors; 173c3f86a25SRick Macklem int gr_secflavors[MAXSECFLAVORS]; 1748fae3551SRodney W. Grimes }; 1758fae3551SRodney W. Grimes /* Group types */ 1768fae3551SRodney W. Grimes #define GT_NULL 0x0 1778fae3551SRodney W. Grimes #define GT_HOST 0x1 1788fae3551SRodney W. Grimes #define GT_NET 0x2 1796d359f31SIan Dowse #define GT_DEFAULT 0x3 1808b5a6d67SBill Paul #define GT_IGNORE 0x5 1818fae3551SRodney W. Grimes 1820f0869bcSRick Macklem /* Group flags */ 1830f0869bcSRick Macklem #define GR_FND 0x1 1840f0869bcSRick Macklem 1858fae3551SRodney W. Grimes struct hostlist { 186a62dc406SDoug Rabson int ht_flag; /* Uses DP_xx bits */ 1878fae3551SRodney W. Grimes struct grouplist *ht_grp; 1888fae3551SRodney W. Grimes struct hostlist *ht_next; 1898fae3551SRodney W. Grimes }; 1908fae3551SRodney W. Grimes 191a62dc406SDoug Rabson struct fhreturn { 192a62dc406SDoug Rabson int fhr_flag; 193a62dc406SDoug Rabson int fhr_vers; 194a62dc406SDoug Rabson nfsfh_t fhr_fh; 195a9148abdSDoug Rabson int fhr_numsecflavors; 196a9148abdSDoug Rabson int *fhr_secflavors; 197a62dc406SDoug Rabson }; 198a62dc406SDoug Rabson 1998fb6ad5dSRick Macklem #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 2008fb6ad5dSRick Macklem 2017674d489SRick Macklem /* 2027674d489SRick Macklem * How long to delay a reload of exports when there are RPC request(s) 2037674d489SRick Macklem * to process, in usec. Must be less than 1second. 2047674d489SRick Macklem */ 2057674d489SRick Macklem #define RELOADDELAY 250000 2067674d489SRick Macklem 2078fae3551SRodney W. Grimes /* Global defs */ 20819c46d8cSEdward Tomasz Napierala static char *add_expdir(struct dirlist **, char *, int); 20919c46d8cSEdward Tomasz Napierala static void add_dlist(struct dirlist **, struct dirlist *, 2100f0869bcSRick Macklem struct grouplist *, int, struct exportlist *, 211cc5efddeSRick Macklem struct expcred *, uint64_t); 21219c46d8cSEdward Tomasz Napierala static void add_mlist(char *, char *); 21319c46d8cSEdward Tomasz Napierala static int check_dirpath(char *); 21419c46d8cSEdward Tomasz Napierala static int check_options(struct dirlist *); 21519c46d8cSEdward Tomasz Napierala static int checkmask(struct sockaddr *sa); 21619c46d8cSEdward Tomasz Napierala static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, 21719c46d8cSEdward Tomasz Napierala int *, int **); 218b875c2e9SJosh Paetzel static char *strsep_quote(char **stringp, const char *delim); 2198fb6ad5dSRick Macklem static int create_service(struct netconfig *nconf); 2208fb6ad5dSRick Macklem static void complete_service(struct netconfig *nconf, char *port_str); 2218fb6ad5dSRick Macklem static void clearout_service(void); 22219c46d8cSEdward Tomasz Napierala static void del_mlist(char *hostp, char *dirp); 22319c46d8cSEdward Tomasz Napierala static struct dirlist *dirp_search(struct dirlist *, char *); 2240f0869bcSRick Macklem static int do_export_mount(struct exportlist *, struct statfs *); 225cc5efddeSRick Macklem static int do_mount(struct exportlist *, struct grouplist *, uint64_t, 226cc5efddeSRick Macklem struct expcred *, char *, int, struct statfs *, int, int *); 22719c46d8cSEdward Tomasz Napierala static int do_opt(char **, char **, struct exportlist *, 228cc5efddeSRick Macklem struct grouplist *, int *, uint64_t *, struct expcred *); 2291a9a992fSRick Macklem static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); 23019c46d8cSEdward Tomasz Napierala static struct exportlist *get_exp(void); 23119c46d8cSEdward Tomasz Napierala static void free_dir(struct dirlist *); 23219c46d8cSEdward Tomasz Napierala static void free_exp(struct exportlist *); 23319c46d8cSEdward Tomasz Napierala static void free_grp(struct grouplist *); 23419c46d8cSEdward Tomasz Napierala static void free_host(struct hostlist *); 2350f0869bcSRick Macklem static void free_v4rootexp(void); 2360f0869bcSRick Macklem static void get_exportlist_one(int); 2370f0869bcSRick Macklem static void get_exportlist(int); 2381a9a992fSRick Macklem static void insert_exports(struct exportlist *, struct exportlisthead *); 2391a9a992fSRick Macklem static void free_exports(struct exportlisthead *); 2400f0869bcSRick Macklem static void read_exportfile(int); 2410f0869bcSRick Macklem static int compare_nmount_exportlist(struct iovec *, int, char *); 2420f0869bcSRick Macklem static int compare_export(struct exportlist *, struct exportlist *); 243cc5efddeSRick Macklem static int compare_cred(struct expcred *, struct expcred *); 2440f0869bcSRick Macklem static int compare_secflavor(int *, int *, int); 2453e08dc74SRick Macklem static void delete_export(struct iovec *, int, struct statfs *, char *); 24619c46d8cSEdward Tomasz Napierala static int get_host(char *, struct grouplist *, struct grouplist *); 24719c46d8cSEdward Tomasz Napierala static struct hostlist *get_ht(void); 24819c46d8cSEdward Tomasz Napierala static int get_line(void); 24919c46d8cSEdward Tomasz Napierala static void get_mountlist(void); 25019c46d8cSEdward Tomasz Napierala static int get_net(char *, struct netmsk *, int); 251354fce28SConrad Meyer static void getexp_err(struct exportlist *, struct grouplist *, const char *); 25219c46d8cSEdward Tomasz Napierala static struct grouplist *get_grp(void); 25319c46d8cSEdward Tomasz Napierala static void hang_dirp(struct dirlist *, struct grouplist *, 254cc5efddeSRick Macklem struct exportlist *, int, struct expcred *, uint64_t); 25519c46d8cSEdward Tomasz Napierala static void huphandler(int sig); 25619c46d8cSEdward Tomasz Napierala static int makemask(struct sockaddr_storage *ssp, int bitlen); 25719c46d8cSEdward Tomasz Napierala static void mntsrv(struct svc_req *, SVCXPRT *); 25819c46d8cSEdward Tomasz Napierala static void nextfield(char **, char **); 25919c46d8cSEdward Tomasz Napierala static void out_of_mem(void); 260cc5efddeSRick Macklem static void parsecred(char *, struct expcred *); 26119c46d8cSEdward Tomasz Napierala static int parsesec(char *, struct exportlist *); 26219c46d8cSEdward Tomasz Napierala static int put_exlist(struct dirlist *, XDR *, struct dirlist *, 26319c46d8cSEdward Tomasz Napierala int *, int); 26419c46d8cSEdward Tomasz Napierala static void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 26519c46d8cSEdward Tomasz Napierala static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 26660caaee2SIan Dowse struct sockaddr *samask); 26719c46d8cSEdward Tomasz Napierala static int scan_tree(struct dirlist *, struct sockaddr *); 26885429990SWarner Losh static void usage(void); 26919c46d8cSEdward Tomasz Napierala static int xdr_dir(XDR *, char *); 27019c46d8cSEdward Tomasz Napierala static int xdr_explist(XDR *, caddr_t); 27119c46d8cSEdward Tomasz Napierala static int xdr_explist_brief(XDR *, caddr_t); 27219c46d8cSEdward Tomasz Napierala static int xdr_explist_common(XDR *, caddr_t, int); 27319c46d8cSEdward Tomasz Napierala static int xdr_fhs(XDR *, caddr_t); 27419c46d8cSEdward Tomasz Napierala static int xdr_mlist(XDR *, caddr_t); 27519c46d8cSEdward Tomasz Napierala static void terminate(int); 276cc5efddeSRick Macklem static void cp_cred(struct expcred *, struct expcred *); 2778fae3551SRodney W. Grimes 27846a6b5c4SRick Macklem #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) 27946a6b5c4SRick Macklem static struct exportlisthead *exphead = NULL; 2800f0869bcSRick Macklem static struct exportlisthead *oldexphead = NULL; 28146a6b5c4SRick Macklem static int exphashsize = 0; 2821a9a992fSRick Macklem static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); 28319c46d8cSEdward Tomasz Napierala static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 28419c46d8cSEdward Tomasz Napierala static char **exnames; 28519c46d8cSEdward Tomasz Napierala static char **hosts = NULL; 28619c46d8cSEdward Tomasz Napierala static int force_v2 = 0; 28719c46d8cSEdward Tomasz Napierala static int resvport_only = 1; 28819c46d8cSEdward Tomasz Napierala static int nhosts = 0; 28919c46d8cSEdward Tomasz Napierala static int dir_only = 1; 29019c46d8cSEdward Tomasz Napierala static int dolog = 0; 29119c46d8cSEdward Tomasz Napierala static int got_sighup = 0; 29219c46d8cSEdward Tomasz Napierala static int xcreated = 0; 293d11e3645SMatteo Riondato 29419c46d8cSEdward Tomasz Napierala static char *svcport_str = NULL; 2958fb6ad5dSRick Macklem static int mallocd_svcport = 0; 2968fb6ad5dSRick Macklem static int *sock_fd; 2978fb6ad5dSRick Macklem static int sock_fdcnt; 2988fb6ad5dSRick Macklem static int sock_fdpos; 299c548eb5cSRick Macklem static int suspend_nfsd = 0; 3008360efbdSAlfred Perlstein 30119c46d8cSEdward Tomasz Napierala static int opt_flags; 3028360efbdSAlfred Perlstein static int have_v6 = 1; 3038360efbdSAlfred Perlstein 30419c46d8cSEdward Tomasz Napierala static int v4root_phase = 0; 30519c46d8cSEdward Tomasz Napierala static char v4root_dirpath[PATH_MAX + 1]; 3060f0869bcSRick Macklem static struct exportlist *v4root_ep = NULL; 30719c46d8cSEdward Tomasz Napierala static int has_publicfh = 0; 3080f0869bcSRick Macklem static int has_set_publicfh = 0; 309bcc1d071SRick Macklem 31019c46d8cSEdward Tomasz Napierala static struct pidfh *pfh = NULL; 31160caaee2SIan Dowse /* Bits for opt_flags above */ 3128fae3551SRodney W. Grimes #define OP_MAPROOT 0x01 3138fae3551SRodney W. Grimes #define OP_MAPALL 0x02 31491196234SPeter Wemm /* 0x4 free */ 3158fae3551SRodney W. Grimes #define OP_MASK 0x08 3168fae3551SRodney W. Grimes #define OP_NET 0x10 3178fae3551SRodney W. Grimes #define OP_ALLDIRS 0x40 31860caaee2SIan Dowse #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 319288fa14aSJoerg Wunsch #define OP_QUIET 0x100 3208360efbdSAlfred Perlstein #define OP_MASKLEN 0x200 321a9148abdSDoug Rabson #define OP_SEC 0x400 3228fae3551SRodney W. Grimes 3238fae3551SRodney W. Grimes #ifdef DEBUG 32419c46d8cSEdward Tomasz Napierala static int debug = 1; 32519c46d8cSEdward Tomasz Napierala static void SYSLOG(int, const char *, ...) __printflike(2, 3); 3268fae3551SRodney W. Grimes #define syslog SYSLOG 3278fae3551SRodney W. Grimes #else 32819c46d8cSEdward Tomasz Napierala static int debug = 0; 3298fae3551SRodney W. Grimes #endif 3308fae3551SRodney W. Grimes 3318fae3551SRodney W. Grimes /* 3320f0869bcSRick Macklem * The LOGDEBUG() syslog() calls are always compiled into the daemon. 3330f0869bcSRick Macklem * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty. 3340f0869bcSRick Macklem * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG. 3350f0869bcSRick Macklem */ 3360f0869bcSRick Macklem static int logdebug = 0; 3370f0869bcSRick Macklem #define LOGDEBUG(format, ...) \ 3380f0869bcSRick Macklem (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0) 3390f0869bcSRick Macklem 3400f0869bcSRick Macklem /* 341b875c2e9SJosh Paetzel * Similar to strsep(), but it allows for quoted strings 342b875c2e9SJosh Paetzel * and escaped characters. 343b875c2e9SJosh Paetzel * 344b875c2e9SJosh Paetzel * It returns the string (or NULL, if *stringp is NULL), 345b875c2e9SJosh Paetzel * which is a de-quoted version of the string if necessary. 346b875c2e9SJosh Paetzel * 347b875c2e9SJosh Paetzel * It modifies *stringp in place. 348b875c2e9SJosh Paetzel */ 349b875c2e9SJosh Paetzel static char * 350b875c2e9SJosh Paetzel strsep_quote(char **stringp, const char *delim) 351b875c2e9SJosh Paetzel { 352b875c2e9SJosh Paetzel char *srcptr, *dstptr, *retval; 353b875c2e9SJosh Paetzel char quot = 0; 354b875c2e9SJosh Paetzel 355b875c2e9SJosh Paetzel if (stringp == NULL || *stringp == NULL) 356b875c2e9SJosh Paetzel return (NULL); 357b875c2e9SJosh Paetzel 358b875c2e9SJosh Paetzel srcptr = dstptr = retval = *stringp; 359b875c2e9SJosh Paetzel 360b875c2e9SJosh Paetzel while (*srcptr) { 361b875c2e9SJosh Paetzel /* 362b875c2e9SJosh Paetzel * We're looking for several edge cases here. 363b875c2e9SJosh Paetzel * First: if we're in quote state (quot != 0), 364b875c2e9SJosh Paetzel * then we ignore the delim characters, but otherwise 365b875c2e9SJosh Paetzel * process as normal, unless it is the quote character. 366b875c2e9SJosh Paetzel * Second: if the current character is a backslash, 367b875c2e9SJosh Paetzel * we take the next character as-is, without checking 368b875c2e9SJosh Paetzel * for delim, quote, or backslash. Exception: if the 369b875c2e9SJosh Paetzel * next character is a NUL, that's the end of the string. 370b875c2e9SJosh Paetzel * Third: if the character is a quote character, we toggle 371b875c2e9SJosh Paetzel * quote state. 372b875c2e9SJosh Paetzel * Otherwise: check the current character for NUL, or 373b875c2e9SJosh Paetzel * being in delim, and end the string if either is true. 374b875c2e9SJosh Paetzel */ 375b875c2e9SJosh Paetzel if (*srcptr == '\\') { 376b875c2e9SJosh Paetzel srcptr++; 377b875c2e9SJosh Paetzel /* 378b875c2e9SJosh Paetzel * The edge case here is if the next character 379b875c2e9SJosh Paetzel * is NUL, we want to stop processing. But if 380b875c2e9SJosh Paetzel * it's not NUL, then we simply want to copy it. 381b875c2e9SJosh Paetzel */ 382b875c2e9SJosh Paetzel if (*srcptr) { 383b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 384b875c2e9SJosh Paetzel } 385b875c2e9SJosh Paetzel continue; 386b875c2e9SJosh Paetzel } 387b875c2e9SJosh Paetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 388b875c2e9SJosh Paetzel quot = *srcptr++; 389b875c2e9SJosh Paetzel continue; 390b875c2e9SJosh Paetzel } 391b875c2e9SJosh Paetzel if (quot && *srcptr == quot) { 392b875c2e9SJosh Paetzel /* End of the quoted part */ 393b875c2e9SJosh Paetzel quot = 0; 394b875c2e9SJosh Paetzel srcptr++; 395b875c2e9SJosh Paetzel continue; 396b875c2e9SJosh Paetzel } 397b875c2e9SJosh Paetzel if (!quot && strchr(delim, *srcptr)) 398b875c2e9SJosh Paetzel break; 399b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 400b875c2e9SJosh Paetzel } 401b875c2e9SJosh Paetzel 402b875c2e9SJosh Paetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 4034ae6e084SAlexander Motin *dstptr = 0; /* Terminate the string */ 404b875c2e9SJosh Paetzel return (retval); 405b875c2e9SJosh Paetzel } 406b875c2e9SJosh Paetzel 407b875c2e9SJosh Paetzel /* 4088fae3551SRodney W. Grimes * Mountd server for NFS mount protocol as described in: 4098fae3551SRodney W. Grimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 4108fae3551SRodney W. Grimes * The optional arguments are the exports file name 4118fae3551SRodney W. Grimes * default: _PATH_EXPORTS 4128fae3551SRodney W. Grimes * and "-n" to allow nonroot mount. 4138fae3551SRodney W. Grimes */ 4148fae3551SRodney W. Grimes int 415a7a7d96cSPhilippe Charnier main(int argc, char **argv) 4168fae3551SRodney W. Grimes { 41769d65572SIan Dowse fd_set readfds; 418d11e3645SMatteo Riondato struct netconfig *nconf; 419d11e3645SMatteo Riondato char *endptr, **hosts_bak; 420d11e3645SMatteo Riondato void *nc_handle; 421a032b226SPawel Jakub Dawidek pid_t otherpid; 422d11e3645SMatteo Riondato in_port_t svcport; 423d11e3645SMatteo Riondato int c, k, s; 424bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE; 4258fb6ad5dSRick Macklem int attempt_cnt, port_len, port_pos, ret; 4268fb6ad5dSRick Macklem char **port_list; 4277674d489SRick Macklem uint64_t curtime, nexttime; 4287674d489SRick Macklem struct timeval tv; 4297674d489SRick Macklem struct timespec tp; 4307674d489SRick Macklem sigset_t sighup_mask; 4318360efbdSAlfred Perlstein 43201709abfSIan Dowse /* Check that another mountd isn't already running. */ 4338b28aef2SPawel Jakub Dawidek pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 434a032b226SPawel Jakub Dawidek if (pfh == NULL) { 435a032b226SPawel Jakub Dawidek if (errno == EEXIST) 436a032b226SPawel Jakub Dawidek errx(1, "mountd already running, pid: %d.", otherpid); 437a032b226SPawel Jakub Dawidek warn("cannot open or create pidfile"); 438a032b226SPawel Jakub Dawidek } 4398360efbdSAlfred Perlstein 4408360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 4418360efbdSAlfred Perlstein if (s < 0) 4428360efbdSAlfred Perlstein have_v6 = 0; 4438360efbdSAlfred Perlstein else 4448360efbdSAlfred Perlstein close(s); 4458fae3551SRodney W. Grimes 44679b86807SEdward Tomasz Napierala while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) 4478fae3551SRodney W. Grimes switch (c) { 4482a66cfc5SDoug Rabson case '2': 4492a66cfc5SDoug Rabson force_v2 = 1; 4502a66cfc5SDoug Rabson break; 4512179ae1eSRick Macklem case 'e': 4522a85df8cSRick Macklem /* now a no-op, since this is the default */ 453bcc1d071SRick Macklem break; 454a62dc406SDoug Rabson case 'n': 455a62dc406SDoug Rabson resvport_only = 0; 456a62dc406SDoug Rabson break; 457a62dc406SDoug Rabson case 'r': 458a62dc406SDoug Rabson dir_only = 0; 459a62dc406SDoug Rabson break; 4606444ef3bSPoul-Henning Kamp case 'd': 4616444ef3bSPoul-Henning Kamp debug = debug ? 0 : 1; 4626444ef3bSPoul-Henning Kamp break; 463f51631d7SGuido van Rooij case 'l': 464c903443aSPeter Wemm dolog = 1; 465f51631d7SGuido van Rooij break; 466c203da27SBruce M Simpson case 'p': 467c203da27SBruce M Simpson endptr = NULL; 468c203da27SBruce M Simpson svcport = (in_port_t)strtoul(optarg, &endptr, 10); 469c203da27SBruce M Simpson if (endptr == NULL || *endptr != '\0' || 470c203da27SBruce M Simpson svcport == 0 || svcport >= IPPORT_MAX) 471c203da27SBruce M Simpson usage(); 472d11e3645SMatteo Riondato svcport_str = strdup(optarg); 473d11e3645SMatteo Riondato break; 474d11e3645SMatteo Riondato case 'h': 475d11e3645SMatteo Riondato ++nhosts; 476d11e3645SMatteo Riondato hosts_bak = hosts; 477d11e3645SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 478d11e3645SMatteo Riondato if (hosts_bak == NULL) { 479d11e3645SMatteo Riondato if (hosts != NULL) { 480d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 481d11e3645SMatteo Riondato free(hosts[k]); 482d11e3645SMatteo Riondato free(hosts); 483d11e3645SMatteo Riondato out_of_mem(); 484d11e3645SMatteo Riondato } 485d11e3645SMatteo Riondato } 486d11e3645SMatteo Riondato hosts = hosts_bak; 487d11e3645SMatteo Riondato hosts[nhosts - 1] = strdup(optarg); 488d11e3645SMatteo Riondato if (hosts[nhosts - 1] == NULL) { 489d11e3645SMatteo Riondato for (k = 0; k < (nhosts - 1); k++) 490d11e3645SMatteo Riondato free(hosts[k]); 491d11e3645SMatteo Riondato free(hosts); 492d11e3645SMatteo Riondato out_of_mem(); 493d11e3645SMatteo Riondato } 494c203da27SBruce M Simpson break; 495c548eb5cSRick Macklem case 'S': 496c548eb5cSRick Macklem suspend_nfsd = 1; 497c548eb5cSRick Macklem break; 4988fae3551SRodney W. Grimes default: 49974853402SPhilippe Charnier usage(); 50080c7cc1cSPedro F. Giffuni } 501bcc1d071SRick Macklem 502bcc1d071SRick Macklem if (modfind("nfsd") < 0) { 503bcc1d071SRick Macklem /* Not present in kernel, try loading it */ 504bcc1d071SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 505bcc1d071SRick Macklem errx(1, "NFS server is not available"); 506bcc1d071SRick Macklem } 507bcc1d071SRick Macklem 5088fae3551SRodney W. Grimes argc -= optind; 5098fae3551SRodney W. Grimes argv += optind; 51096968c22SPawel Jakub Dawidek if (argc > 0) 51196968c22SPawel Jakub Dawidek exnames = argv; 51296968c22SPawel Jakub Dawidek else 51396968c22SPawel Jakub Dawidek exnames = exnames_default; 5148fae3551SRodney W. Grimes openlog("mountd", LOG_PID, LOG_DAEMON); 5158fae3551SRodney W. Grimes if (debug) 51674853402SPhilippe Charnier warnx("getting export list"); 5170f0869bcSRick Macklem get_exportlist(0); 5188fae3551SRodney W. Grimes if (debug) 51974853402SPhilippe Charnier warnx("getting mount list"); 5208fae3551SRodney W. Grimes get_mountlist(); 5218fae3551SRodney W. Grimes if (debug) 52274853402SPhilippe Charnier warnx("here we go"); 5238fae3551SRodney W. Grimes if (debug == 0) { 5248fae3551SRodney W. Grimes daemon(0, 0); 5258fae3551SRodney W. Grimes signal(SIGINT, SIG_IGN); 5268fae3551SRodney W. Grimes signal(SIGQUIT, SIG_IGN); 5278fae3551SRodney W. Grimes } 52869d65572SIan Dowse signal(SIGHUP, huphandler); 5298360efbdSAlfred Perlstein signal(SIGTERM, terminate); 53009fc9dc6SCraig Rodrigues signal(SIGPIPE, SIG_IGN); 531a032b226SPawel Jakub Dawidek 532a032b226SPawel Jakub Dawidek pidfile_write(pfh); 533a032b226SPawel Jakub Dawidek 5340775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 5350775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 536bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 537bcb53b16SMartin Blapp 538c6e5e158SGuido van Rooij if (!resvport_only) { 5395ebee88dSRick Macklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL, 5404a0785aaSPeter Wemm &resvport_only, sizeof(resvport_only)) != 0 && 5414a0785aaSPeter Wemm errno != ENOENT) { 542394da4c1SGuido van Rooij syslog(LOG_ERR, "sysctl: %m"); 543394da4c1SGuido van Rooij exit(1); 544394da4c1SGuido van Rooij } 545c6e5e158SGuido van Rooij } 546c203da27SBruce M Simpson 547d11e3645SMatteo Riondato /* 548d11e3645SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to 549d11e3645SMatteo Riondato * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 550d11e3645SMatteo Riondato * list. 551d11e3645SMatteo Riondato */ 552d11e3645SMatteo Riondato if (nhosts == 0) { 553c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *)); 554d11e3645SMatteo Riondato if (hosts == NULL) 555d11e3645SMatteo Riondato out_of_mem(); 556d11e3645SMatteo Riondato hosts[0] = "*"; 557d11e3645SMatteo Riondato nhosts = 1; 558d11e3645SMatteo Riondato } else { 559d11e3645SMatteo Riondato hosts_bak = hosts; 560d11e3645SMatteo Riondato if (have_v6) { 561d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) * 562d11e3645SMatteo Riondato sizeof(char *)); 563d11e3645SMatteo Riondato if (hosts_bak == NULL) { 564d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 565d11e3645SMatteo Riondato free(hosts[k]); 566d11e3645SMatteo Riondato free(hosts); 567d11e3645SMatteo Riondato out_of_mem(); 568c203da27SBruce M Simpson } else 569d11e3645SMatteo Riondato hosts = hosts_bak; 570d11e3645SMatteo Riondato nhosts += 2; 571d11e3645SMatteo Riondato hosts[nhosts - 2] = "::1"; 572d11e3645SMatteo Riondato } else { 573d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 574d11e3645SMatteo Riondato if (hosts_bak == NULL) { 575d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 576d11e3645SMatteo Riondato free(hosts[k]); 577d11e3645SMatteo Riondato free(hosts); 578d11e3645SMatteo Riondato out_of_mem(); 579d11e3645SMatteo Riondato } else { 580d11e3645SMatteo Riondato nhosts += 1; 581d11e3645SMatteo Riondato hosts = hosts_bak; 5828fae3551SRodney W. Grimes } 583d11e3645SMatteo Riondato } 5848360efbdSAlfred Perlstein 585d11e3645SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1"; 5868360efbdSAlfred Perlstein } 5878360efbdSAlfred Perlstein 5888fb6ad5dSRick Macklem attempt_cnt = 1; 5898fb6ad5dSRick Macklem sock_fdcnt = 0; 5908fb6ad5dSRick Macklem sock_fd = NULL; 5918fb6ad5dSRick Macklem port_list = NULL; 5928fb6ad5dSRick Macklem port_len = 0; 593d11e3645SMatteo Riondato nc_handle = setnetconfig(); 594d11e3645SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) { 595d11e3645SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) { 596d11e3645SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 597d11e3645SMatteo Riondato "inet6") == 0) { 598d11e3645SMatteo Riondato /* DO NOTHING */ 5998fb6ad5dSRick Macklem } else { 6008fb6ad5dSRick Macklem ret = create_service(nconf); 6018fb6ad5dSRick Macklem if (ret == 1) 6028fb6ad5dSRick Macklem /* Ignore this call */ 6038fb6ad5dSRick Macklem continue; 6048fb6ad5dSRick Macklem if (ret < 0) { 6058fb6ad5dSRick Macklem /* 6068fb6ad5dSRick Macklem * Failed to bind port, so close off 6078fb6ad5dSRick Macklem * all sockets created and try again 6088fb6ad5dSRick Macklem * if the port# was dynamically 6098fb6ad5dSRick Macklem * assigned via bind(2). 6108fb6ad5dSRick Macklem */ 6118fb6ad5dSRick Macklem clearout_service(); 6128fb6ad5dSRick Macklem if (mallocd_svcport != 0 && 6138fb6ad5dSRick Macklem attempt_cnt < GETPORT_MAXTRY) { 6148fb6ad5dSRick Macklem free(svcport_str); 6158fb6ad5dSRick Macklem svcport_str = NULL; 6168fb6ad5dSRick Macklem mallocd_svcport = 0; 6178fb6ad5dSRick Macklem } else { 6188fb6ad5dSRick Macklem errno = EADDRINUSE; 6198fb6ad5dSRick Macklem syslog(LOG_ERR, 6208fb6ad5dSRick Macklem "bindresvport_sa: %m"); 6218fb6ad5dSRick Macklem exit(1); 6228fb6ad5dSRick Macklem } 6238fb6ad5dSRick Macklem 6248fb6ad5dSRick Macklem /* Start over at the first service. */ 6258fb6ad5dSRick Macklem free(sock_fd); 6268fb6ad5dSRick Macklem sock_fdcnt = 0; 6278fb6ad5dSRick Macklem sock_fd = NULL; 6288fb6ad5dSRick Macklem nc_handle = setnetconfig(); 6298fb6ad5dSRick Macklem attempt_cnt++; 6308fb6ad5dSRick Macklem } else if (mallocd_svcport != 0 && 6318fb6ad5dSRick Macklem attempt_cnt == GETPORT_MAXTRY) { 6328fb6ad5dSRick Macklem /* 6338fb6ad5dSRick Macklem * For the last attempt, allow 6348fb6ad5dSRick Macklem * different port #s for each nconf 6358fb6ad5dSRick Macklem * by saving the svcport_str and 6368fb6ad5dSRick Macklem * setting it back to NULL. 6378fb6ad5dSRick Macklem */ 6388fb6ad5dSRick Macklem port_list = realloc(port_list, 6398fb6ad5dSRick Macklem (port_len + 1) * sizeof(char *)); 6408fb6ad5dSRick Macklem if (port_list == NULL) 6418fb6ad5dSRick Macklem out_of_mem(); 6428fb6ad5dSRick Macklem port_list[port_len++] = svcport_str; 6438fb6ad5dSRick Macklem svcport_str = NULL; 6448fb6ad5dSRick Macklem mallocd_svcport = 0; 6458fb6ad5dSRick Macklem } 6468fb6ad5dSRick Macklem } 6478fb6ad5dSRick Macklem } 6488fb6ad5dSRick Macklem } 6498fb6ad5dSRick Macklem 6508fb6ad5dSRick Macklem /* 6518fb6ad5dSRick Macklem * Successfully bound the ports, so call complete_service() to 6528fb6ad5dSRick Macklem * do the rest of the setup on the service(s). 6538fb6ad5dSRick Macklem */ 6548fb6ad5dSRick Macklem sock_fdpos = 0; 6558fb6ad5dSRick Macklem port_pos = 0; 6568fb6ad5dSRick Macklem nc_handle = setnetconfig(); 6578fb6ad5dSRick Macklem while ((nconf = getnetconfig(nc_handle))) { 6588fb6ad5dSRick Macklem if (nconf->nc_flag & NC_VISIBLE) { 6598fb6ad5dSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 6608fb6ad5dSRick Macklem "inet6") == 0) { 6618fb6ad5dSRick Macklem /* DO NOTHING */ 6628fb6ad5dSRick Macklem } else if (port_list != NULL) { 6638fb6ad5dSRick Macklem if (port_pos >= port_len) { 6648fb6ad5dSRick Macklem syslog(LOG_ERR, "too many port#s"); 6658fb6ad5dSRick Macklem exit(1); 6668fb6ad5dSRick Macklem } 6678fb6ad5dSRick Macklem complete_service(nconf, port_list[port_pos++]); 668c203da27SBruce M Simpson } else 6698fb6ad5dSRick Macklem complete_service(nconf, svcport_str); 6708360efbdSAlfred Perlstein } 671d11e3645SMatteo Riondato } 672d11e3645SMatteo Riondato endnetconfig(nc_handle); 6738fb6ad5dSRick Macklem free(sock_fd); 6748fb6ad5dSRick Macklem if (port_list != NULL) { 6758fb6ad5dSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++) 6768fb6ad5dSRick Macklem free(port_list[port_pos]); 6778fb6ad5dSRick Macklem free(port_list); 6788fb6ad5dSRick Macklem } 6798360efbdSAlfred Perlstein 6808360efbdSAlfred Perlstein if (xcreated == 0) { 6818360efbdSAlfred Perlstein syslog(LOG_ERR, "could not create any services"); 6822a66cfc5SDoug Rabson exit(1); 6832a66cfc5SDoug Rabson } 68469d65572SIan Dowse 68569d65572SIan Dowse /* Expand svc_run() here so that we can call get_exportlist(). */ 6867674d489SRick Macklem curtime = nexttime = 0; 6877674d489SRick Macklem sigemptyset(&sighup_mask); 6887674d489SRick Macklem sigaddset(&sighup_mask, SIGHUP); 68969d65572SIan Dowse for (;;) { 6907674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp); 6917674d489SRick Macklem curtime = tp.tv_sec; 6927674d489SRick Macklem curtime = curtime * 1000000 + tp.tv_nsec / 1000; 6937674d489SRick Macklem sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 6947674d489SRick Macklem if (got_sighup && curtime >= nexttime) { 69569d65572SIan Dowse got_sighup = 0; 6967674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 6977674d489SRick Macklem get_exportlist(1); 6987674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp); 6997674d489SRick Macklem nexttime = tp.tv_sec; 7007674d489SRick Macklem nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 + 7017674d489SRick Macklem RELOADDELAY; 7027674d489SRick Macklem } else 7037674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 7047674d489SRick Macklem 7057674d489SRick Macklem /* 7067674d489SRick Macklem * If a reload is pending, poll for received request(s), 7077674d489SRick Macklem * otherwise set a RELOADDELAY timeout, since a SIGHUP 7087674d489SRick Macklem * could be processed between the got_sighup test and 7097674d489SRick Macklem * the select() system call. 7107674d489SRick Macklem */ 7117674d489SRick Macklem tv.tv_sec = 0; 7127674d489SRick Macklem if (got_sighup) 7137674d489SRick Macklem tv.tv_usec = 0; 7147674d489SRick Macklem else 7157674d489SRick Macklem tv.tv_usec = RELOADDELAY; 71669d65572SIan Dowse readfds = svc_fdset; 7177674d489SRick Macklem switch (select(svc_maxfd + 1, &readfds, NULL, NULL, &tv)) { 71869d65572SIan Dowse case -1: 7197674d489SRick Macklem if (errno == EINTR) { 7207674d489SRick Macklem /* Allow a reload now. */ 7217674d489SRick Macklem nexttime = 0; 72269d65572SIan Dowse continue; 7237674d489SRick Macklem } 72469d65572SIan Dowse syslog(LOG_ERR, "mountd died: select: %m"); 72574853402SPhilippe Charnier exit(1); 72669d65572SIan Dowse case 0: 7277674d489SRick Macklem /* Allow a reload now. */ 7287674d489SRick Macklem nexttime = 0; 72969d65572SIan Dowse continue; 73069d65572SIan Dowse default: 73169d65572SIan Dowse svc_getreqset(&readfds); 73269d65572SIan Dowse } 73369d65572SIan Dowse } 73474853402SPhilippe Charnier } 73574853402SPhilippe Charnier 736d11e3645SMatteo Riondato /* 737d11e3645SMatteo Riondato * This routine creates and binds sockets on the appropriate 7388fb6ad5dSRick Macklem * addresses. It gets called one time for each transport. 7398fb6ad5dSRick Macklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 7408fb6ad5dSRick Macklem * bind failed with EADDRINUSE. 7418fb6ad5dSRick Macklem * Any file descriptors that have been created are stored in sock_fd and 7428fb6ad5dSRick Macklem * the total count of them is maintained in sock_fdcnt. 743d11e3645SMatteo Riondato */ 7448fb6ad5dSRick Macklem static int 745d11e3645SMatteo Riondato create_service(struct netconfig *nconf) 746d11e3645SMatteo Riondato { 747d11e3645SMatteo Riondato struct addrinfo hints, *res = NULL; 748d11e3645SMatteo Riondato struct sockaddr_in *sin; 749d11e3645SMatteo Riondato struct sockaddr_in6 *sin6; 750d11e3645SMatteo Riondato struct __rpc_sockinfo si; 751d11e3645SMatteo Riondato int aicode; 752d11e3645SMatteo Riondato int fd; 753d11e3645SMatteo Riondato int nhostsbak; 754d11e3645SMatteo Riondato int one = 1; 755d11e3645SMatteo Riondato int r; 756d11e3645SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 7578fb6ad5dSRick Macklem int mallocd_res; 758d11e3645SMatteo Riondato 759d11e3645SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) && 760d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) && 761d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD)) 7628fb6ad5dSRick Macklem return (1); /* not my type */ 763d11e3645SMatteo Riondato 764d11e3645SMatteo Riondato /* 765d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 766d11e3645SMatteo Riondato */ 767d11e3645SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) { 768d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s", 769d11e3645SMatteo Riondato nconf->nc_netid); 7708fb6ad5dSRick Macklem return (1); 771d11e3645SMatteo Riondato } 772d11e3645SMatteo Riondato 773d11e3645SMatteo Riondato /* Get mountd's address on this transport */ 774d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 775d11e3645SMatteo Riondato hints.ai_family = si.si_af; 776d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 777d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 778d11e3645SMatteo Riondato 779d11e3645SMatteo Riondato /* 780d11e3645SMatteo Riondato * Bind to specific IPs if asked to 781d11e3645SMatteo Riondato */ 782d11e3645SMatteo Riondato nhostsbak = nhosts; 783d11e3645SMatteo Riondato while (nhostsbak > 0) { 784d11e3645SMatteo Riondato --nhostsbak; 7858fb6ad5dSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 7868fb6ad5dSRick Macklem if (sock_fd == NULL) 7878fb6ad5dSRick Macklem out_of_mem(); 7888fb6ad5dSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 7898fb6ad5dSRick Macklem mallocd_res = 0; 7908fb6ad5dSRick Macklem 7919745de4cSRyan Stone hints.ai_flags = AI_PASSIVE; 7929745de4cSRyan Stone 793d11e3645SMatteo Riondato /* 794d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 795d11e3645SMatteo Riondato */ 796d11e3645SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) { 797d11e3645SMatteo Riondato int non_fatal = 0; 798a5752d55SKevin Lo if (errno == EAFNOSUPPORT && 799d11e3645SMatteo Riondato nconf->nc_semantics != NC_TPI_CLTS) 800d11e3645SMatteo Riondato non_fatal = 1; 801d11e3645SMatteo Riondato 802d11e3645SMatteo Riondato syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 803d11e3645SMatteo Riondato "cannot create socket for %s", nconf->nc_netid); 8048fb6ad5dSRick Macklem if (non_fatal != 0) 8058fb6ad5dSRick Macklem continue; 8068fb6ad5dSRick Macklem exit(1); 807d11e3645SMatteo Riondato } 808d11e3645SMatteo Riondato 809d11e3645SMatteo Riondato switch (hints.ai_family) { 810d11e3645SMatteo Riondato case AF_INET: 811d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 812d11e3645SMatteo Riondato host_addr) == 1) { 8138fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 814d11e3645SMatteo Riondato } else { 815d11e3645SMatteo Riondato /* 816d11e3645SMatteo Riondato * Skip if we have an AF_INET6 address. 817d11e3645SMatteo Riondato */ 818d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 819d11e3645SMatteo Riondato host_addr) == 1) { 820d11e3645SMatteo Riondato close(fd); 821d11e3645SMatteo Riondato continue; 822d11e3645SMatteo Riondato } 823d11e3645SMatteo Riondato } 824d11e3645SMatteo Riondato break; 825d11e3645SMatteo Riondato case AF_INET6: 826d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 827d11e3645SMatteo Riondato host_addr) == 1) { 8288fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 829d11e3645SMatteo Riondato } else { 830d11e3645SMatteo Riondato /* 831d11e3645SMatteo Riondato * Skip if we have an AF_INET address. 832d11e3645SMatteo Riondato */ 833d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 834d11e3645SMatteo Riondato host_addr) == 1) { 835d11e3645SMatteo Riondato close(fd); 836d11e3645SMatteo Riondato continue; 837d11e3645SMatteo Riondato } 838d11e3645SMatteo Riondato } 839d11e3645SMatteo Riondato 840d11e3645SMatteo Riondato /* 841d11e3645SMatteo Riondato * We're doing host-based access checks here, so don't 842d11e3645SMatteo Riondato * allow v4-in-v6 to confuse things. The kernel will 843d11e3645SMatteo Riondato * disable it by default on NFS sockets too. 844d11e3645SMatteo Riondato */ 845d11e3645SMatteo Riondato if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 846d11e3645SMatteo Riondato sizeof one) < 0) { 847d11e3645SMatteo Riondato syslog(LOG_ERR, 848d11e3645SMatteo Riondato "can't disable v4-in-v6 on IPv6 socket"); 849d11e3645SMatteo Riondato exit(1); 850d11e3645SMatteo Riondato } 851d11e3645SMatteo Riondato break; 852d11e3645SMatteo Riondato default: 853d11e3645SMatteo Riondato break; 854d11e3645SMatteo Riondato } 855d11e3645SMatteo Riondato 856d11e3645SMatteo Riondato /* 857d11e3645SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY 858d11e3645SMatteo Riondato */ 859d11e3645SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) { 860d11e3645SMatteo Riondato if (svcport_str == NULL) { 861d11e3645SMatteo Riondato res = malloc(sizeof(struct addrinfo)); 862d11e3645SMatteo Riondato if (res == NULL) 863d11e3645SMatteo Riondato out_of_mem(); 8648fb6ad5dSRick Macklem mallocd_res = 1; 865d11e3645SMatteo Riondato res->ai_flags = hints.ai_flags; 866d11e3645SMatteo Riondato res->ai_family = hints.ai_family; 867d11e3645SMatteo Riondato res->ai_protocol = hints.ai_protocol; 868d11e3645SMatteo Riondato switch (res->ai_family) { 869d11e3645SMatteo Riondato case AF_INET: 870d11e3645SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in)); 871d11e3645SMatteo Riondato if (sin == NULL) 872d11e3645SMatteo Riondato out_of_mem(); 873d11e3645SMatteo Riondato sin->sin_family = AF_INET; 874d11e3645SMatteo Riondato sin->sin_port = htons(0); 875d11e3645SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY); 876d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin; 877d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 8788fb6ad5dSRick Macklem sizeof(struct sockaddr_in); 879d11e3645SMatteo Riondato break; 880d11e3645SMatteo Riondato case AF_INET6: 881d11e3645SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6)); 88289ca9145SSimon L. B. Nielsen if (sin6 == NULL) 883d11e3645SMatteo Riondato out_of_mem(); 884d11e3645SMatteo Riondato sin6->sin6_family = AF_INET6; 885d11e3645SMatteo Riondato sin6->sin6_port = htons(0); 886d11e3645SMatteo Riondato sin6->sin6_addr = in6addr_any; 887d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6; 888d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 8898fb6ad5dSRick Macklem sizeof(struct sockaddr_in6); 890d11e3645SMatteo Riondato break; 891d11e3645SMatteo Riondato default: 8928fb6ad5dSRick Macklem syslog(LOG_ERR, "bad addr fam %d", 8938fb6ad5dSRick Macklem res->ai_family); 8948fb6ad5dSRick Macklem exit(1); 895d11e3645SMatteo Riondato } 896d11e3645SMatteo Riondato } else { 897d11e3645SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str, 898d11e3645SMatteo Riondato &hints, &res)) != 0) { 899d11e3645SMatteo Riondato syslog(LOG_ERR, 900d11e3645SMatteo Riondato "cannot get local address for %s: %s", 901d11e3645SMatteo Riondato nconf->nc_netid, 902d11e3645SMatteo Riondato gai_strerror(aicode)); 9038fb6ad5dSRick Macklem close(fd); 904d11e3645SMatteo Riondato continue; 905d11e3645SMatteo Riondato } 906d11e3645SMatteo Riondato } 907d11e3645SMatteo Riondato } else { 908d11e3645SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 909d11e3645SMatteo Riondato &hints, &res)) != 0) { 910d11e3645SMatteo Riondato syslog(LOG_ERR, 911d11e3645SMatteo Riondato "cannot get local address for %s: %s", 912d11e3645SMatteo Riondato nconf->nc_netid, gai_strerror(aicode)); 9138fb6ad5dSRick Macklem close(fd); 914d11e3645SMatteo Riondato continue; 915d11e3645SMatteo Riondato } 916d11e3645SMatteo Riondato } 917d11e3645SMatteo Riondato 9188fb6ad5dSRick Macklem /* Store the fd. */ 9198fb6ad5dSRick Macklem sock_fd[sock_fdcnt - 1] = fd; 9208fb6ad5dSRick Macklem 9218fb6ad5dSRick Macklem /* Now, attempt the bind. */ 922d11e3645SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr); 923d11e3645SMatteo Riondato if (r != 0) { 9248fb6ad5dSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 9258fb6ad5dSRick Macklem if (mallocd_res != 0) { 9268fb6ad5dSRick Macklem free(res->ai_addr); 9278fb6ad5dSRick Macklem free(res); 9288fb6ad5dSRick Macklem } else 9298fb6ad5dSRick Macklem freeaddrinfo(res); 9308fb6ad5dSRick Macklem return (-1); 9318fb6ad5dSRick Macklem } 932d11e3645SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m"); 933d11e3645SMatteo Riondato exit(1); 934d11e3645SMatteo Riondato } 935d11e3645SMatteo Riondato 9368fb6ad5dSRick Macklem if (svcport_str == NULL) { 9378fb6ad5dSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 9388fb6ad5dSRick Macklem if (svcport_str == NULL) 9398fb6ad5dSRick Macklem out_of_mem(); 9408fb6ad5dSRick Macklem mallocd_svcport = 1; 9418fb6ad5dSRick Macklem 9428fb6ad5dSRick Macklem if (getnameinfo(res->ai_addr, 9438fb6ad5dSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 9448fb6ad5dSRick Macklem svcport_str, NI_MAXSERV * sizeof(char), 9458fb6ad5dSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV)) 9468fb6ad5dSRick Macklem errx(1, "Cannot get port number"); 9478fb6ad5dSRick Macklem } 9488fb6ad5dSRick Macklem if (mallocd_res != 0) { 9498fb6ad5dSRick Macklem free(res->ai_addr); 9508fb6ad5dSRick Macklem free(res); 9518fb6ad5dSRick Macklem } else 9528fb6ad5dSRick Macklem freeaddrinfo(res); 9538fb6ad5dSRick Macklem res = NULL; 9548fb6ad5dSRick Macklem } 9558fb6ad5dSRick Macklem return (0); 9568fb6ad5dSRick Macklem } 9578fb6ad5dSRick Macklem 9588fb6ad5dSRick Macklem /* 9598fb6ad5dSRick Macklem * Called after all the create_service() calls have succeeded, to complete 9608fb6ad5dSRick Macklem * the setup and registration. 9618fb6ad5dSRick Macklem */ 9628fb6ad5dSRick Macklem static void 9638fb6ad5dSRick Macklem complete_service(struct netconfig *nconf, char *port_str) 9648fb6ad5dSRick Macklem { 9658fb6ad5dSRick Macklem struct addrinfo hints, *res = NULL; 9668fb6ad5dSRick Macklem struct __rpc_sockinfo si; 9678fb6ad5dSRick Macklem struct netbuf servaddr; 9688fb6ad5dSRick Macklem SVCXPRT *transp = NULL; 9698fb6ad5dSRick Macklem int aicode, fd, nhostsbak; 9708fb6ad5dSRick Macklem int registered = 0; 9718fb6ad5dSRick Macklem 9728fb6ad5dSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 9738fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) && 9748fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 9758fb6ad5dSRick Macklem return; /* not my type */ 9768fb6ad5dSRick Macklem 9778fb6ad5dSRick Macklem /* 9788fb6ad5dSRick Macklem * XXX - using RPC library internal functions. 9798fb6ad5dSRick Macklem */ 9808fb6ad5dSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 9818fb6ad5dSRick Macklem syslog(LOG_ERR, "cannot get information for %s", 9828fb6ad5dSRick Macklem nconf->nc_netid); 9838fb6ad5dSRick Macklem return; 9848fb6ad5dSRick Macklem } 9858fb6ad5dSRick Macklem 9868fb6ad5dSRick Macklem nhostsbak = nhosts; 9878fb6ad5dSRick Macklem while (nhostsbak > 0) { 9888fb6ad5dSRick Macklem --nhostsbak; 9898fb6ad5dSRick Macklem if (sock_fdpos >= sock_fdcnt) { 9908fb6ad5dSRick Macklem /* Should never happen. */ 9918fb6ad5dSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's"); 9928fb6ad5dSRick Macklem return; 9938fb6ad5dSRick Macklem } 9948fb6ad5dSRick Macklem fd = sock_fd[sock_fdpos++]; 9958fb6ad5dSRick Macklem if (fd < 0) 9968fb6ad5dSRick Macklem continue; 9978fb6ad5dSRick Macklem 99893840fdeSSean Eric Fagan /* 99993840fdeSSean Eric Fagan * Using -1 tells listen(2) to use 100093840fdeSSean Eric Fagan * kern.ipc.soacceptqueue for the backlog. 100193840fdeSSean Eric Fagan */ 1002d11e3645SMatteo Riondato if (nconf->nc_semantics != NC_TPI_CLTS) 100393840fdeSSean Eric Fagan listen(fd, -1); 1004d11e3645SMatteo Riondato 1005d11e3645SMatteo Riondato if (nconf->nc_semantics == NC_TPI_CLTS ) 1006d11e3645SMatteo Riondato transp = svc_dg_create(fd, 0, 0); 1007d11e3645SMatteo Riondato else 1008d11e3645SMatteo Riondato transp = svc_vc_create(fd, RPC_MAXDATASIZE, 1009d11e3645SMatteo Riondato RPC_MAXDATASIZE); 1010d11e3645SMatteo Riondato 1011d11e3645SMatteo Riondato if (transp != (SVCXPRT *) NULL) { 10120775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 1013d11e3645SMatteo Riondato NULL)) 1014d11e3645SMatteo Riondato syslog(LOG_ERR, 10150775314bSDoug Rabson "can't register %s MOUNTVERS service", 1016d11e3645SMatteo Riondato nconf->nc_netid); 1017d11e3645SMatteo Riondato if (!force_v2) { 10180775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 1019d11e3645SMatteo Riondato mntsrv, NULL)) 1020d11e3645SMatteo Riondato syslog(LOG_ERR, 10210775314bSDoug Rabson "can't register %s MOUNTVERS3 service", 1022d11e3645SMatteo Riondato nconf->nc_netid); 1023d11e3645SMatteo Riondato } 1024d11e3645SMatteo Riondato } else 1025d11e3645SMatteo Riondato syslog(LOG_WARNING, "can't create %s services", 1026d11e3645SMatteo Riondato nconf->nc_netid); 1027d11e3645SMatteo Riondato 1028d11e3645SMatteo Riondato if (registered == 0) { 1029d11e3645SMatteo Riondato registered = 1; 1030d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 1031d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE; 1032d11e3645SMatteo Riondato hints.ai_family = si.si_af; 1033d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 1034d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 1035d11e3645SMatteo Riondato 10368fb6ad5dSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 1037d11e3645SMatteo Riondato &res)) != 0) { 1038d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s", 1039d11e3645SMatteo Riondato gai_strerror(aicode)); 1040d11e3645SMatteo Riondato exit(1); 1041d11e3645SMatteo Riondato } 1042d11e3645SMatteo Riondato 1043d11e3645SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen); 1044d11e3645SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 1045d11e3645SMatteo Riondato servaddr.len = res->ai_addrlen; 1046d11e3645SMatteo Riondato 10470775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 10480775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 1049d11e3645SMatteo Riondato 1050d11e3645SMatteo Riondato xcreated++; 1051d11e3645SMatteo Riondato freeaddrinfo(res); 1052d11e3645SMatteo Riondato } 1053d11e3645SMatteo Riondato } /* end while */ 1054d11e3645SMatteo Riondato } 1055d11e3645SMatteo Riondato 10568fb6ad5dSRick Macklem /* 10578fb6ad5dSRick Macklem * Clear out sockets after a failure to bind one of them, so that the 10588fb6ad5dSRick Macklem * cycle of socket creation/binding can start anew. 10598fb6ad5dSRick Macklem */ 10608fb6ad5dSRick Macklem static void 10618fb6ad5dSRick Macklem clearout_service(void) 10628fb6ad5dSRick Macklem { 10638fb6ad5dSRick Macklem int i; 10648fb6ad5dSRick Macklem 10658fb6ad5dSRick Macklem for (i = 0; i < sock_fdcnt; i++) { 10668fb6ad5dSRick Macklem if (sock_fd[i] >= 0) { 10678fb6ad5dSRick Macklem shutdown(sock_fd[i], SHUT_RDWR); 10688fb6ad5dSRick Macklem close(sock_fd[i]); 10698fb6ad5dSRick Macklem } 10708fb6ad5dSRick Macklem } 10718fb6ad5dSRick Macklem } 10728fb6ad5dSRick Macklem 107374853402SPhilippe Charnier static void 1074a7a7d96cSPhilippe Charnier usage(void) 107574853402SPhilippe Charnier { 107674853402SPhilippe Charnier fprintf(stderr, 10772179ae1eSRick Macklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 1078c548eb5cSRick Macklem "[-S] [-h <bindip>] [export_file ...]\n"); 10798fae3551SRodney W. Grimes exit(1); 10808fae3551SRodney W. Grimes } 10818fae3551SRodney W. Grimes 10828fae3551SRodney W. Grimes /* 10838fae3551SRodney W. Grimes * The mount rpc service 10848fae3551SRodney W. Grimes */ 10858fae3551SRodney W. Grimes void 1086a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 10878fae3551SRodney W. Grimes { 10888fae3551SRodney W. Grimes struct exportlist *ep; 10898fae3551SRodney W. Grimes struct dirlist *dp; 1090a62dc406SDoug Rabson struct fhreturn fhr; 10918fae3551SRodney W. Grimes struct stat stb; 10928fae3551SRodney W. Grimes struct statfs fsb; 10938360efbdSAlfred Perlstein char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 10948360efbdSAlfred Perlstein int lookup_failed = 1; 10958360efbdSAlfred Perlstein struct sockaddr *saddr; 1096a62dc406SDoug Rabson u_short sport; 10970775314bSDoug Rabson char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 1098e9b21d43SBrooks Davis int defset, hostset; 1099e9b21d43SBrooks Davis long bad = 0; 1100a62dc406SDoug Rabson sigset_t sighup_mask; 1101c3f86a25SRick Macklem int numsecflavors, *secflavorsp; 11028fae3551SRodney W. Grimes 1103a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1104a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 11058360efbdSAlfred Perlstein saddr = svc_getrpccaller(transp)->buf; 11068360efbdSAlfred Perlstein switch (saddr->sa_family) { 11078360efbdSAlfred Perlstein case AF_INET6: 110801709abfSIan Dowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 11098360efbdSAlfred Perlstein break; 11108360efbdSAlfred Perlstein case AF_INET: 111101709abfSIan Dowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 11128360efbdSAlfred Perlstein break; 11138360efbdSAlfred Perlstein default: 11148360efbdSAlfred Perlstein syslog(LOG_ERR, "request from unknown address family"); 11158360efbdSAlfred Perlstein return; 11168360efbdSAlfred Perlstein } 111754ff4a6aSSean Eric Fagan switch (rqstp->rq_proc) { 111854ff4a6aSSean Eric Fagan case MOUNTPROC_MNT: 111954ff4a6aSSean Eric Fagan case MOUNTPROC_UMNT: 112054ff4a6aSSean Eric Fagan case MOUNTPROC_UMNTALL: 112154ff4a6aSSean Eric Fagan lookup_failed = getnameinfo(saddr, saddr->sa_len, host, 112254ff4a6aSSean Eric Fagan sizeof host, NULL, 0, 0); 112354ff4a6aSSean Eric Fagan } 11248360efbdSAlfred Perlstein getnameinfo(saddr, saddr->sa_len, numerichost, 11258360efbdSAlfred Perlstein sizeof numerichost, NULL, 0, NI_NUMERICHOST); 11268fae3551SRodney W. Grimes switch (rqstp->rq_proc) { 11278fae3551SRodney W. Grimes case NULLPROC: 1128389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 112974853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 11308fae3551SRodney W. Grimes return; 11310775314bSDoug Rabson case MOUNTPROC_MNT: 1132a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1133f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1134f51631d7SGuido van Rooij "mount request from %s from unprivileged port", 11358360efbdSAlfred Perlstein numerichost); 11368fae3551SRodney W. Grimes svcerr_weakauth(transp); 11378fae3551SRodney W. Grimes return; 11388fae3551SRodney W. Grimes } 1139389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1140f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable mount request from %s", 11418360efbdSAlfred Perlstein numerichost); 11428fae3551SRodney W. Grimes svcerr_decode(transp); 11438fae3551SRodney W. Grimes return; 11448fae3551SRodney W. Grimes } 11458fae3551SRodney W. Grimes 11468fae3551SRodney W. Grimes /* 11478fae3551SRodney W. Grimes * Get the real pathname and make sure it is a directory 1148a62dc406SDoug Rabson * or a regular file if the -r option was specified 1149a62dc406SDoug Rabson * and it exists. 11508fae3551SRodney W. Grimes */ 1151cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL || 11528fae3551SRodney W. Grimes stat(dirpath, &stb) < 0 || 11538fae3551SRodney W. Grimes statfs(dirpath, &fsb) < 0) { 11548fae3551SRodney W. Grimes chdir("/"); /* Just in case realpath doesn't */ 1155f51631d7SGuido van Rooij syslog(LOG_NOTICE, 115674853402SPhilippe Charnier "mount request from %s for non existent path %s", 11578360efbdSAlfred Perlstein numerichost, dirpath); 11588fae3551SRodney W. Grimes if (debug) 115974853402SPhilippe Charnier warnx("stat failed on %s", dirpath); 1160e90cdb54SGuido van Rooij bad = ENOENT; /* We will send error reply later */ 11618fae3551SRodney W. Grimes } 1162b235f015SRavi Pokala if (!bad && 1163b235f015SRavi Pokala !S_ISDIR(stb.st_mode) && 1164b235f015SRavi Pokala (dir_only || !S_ISREG(stb.st_mode))) { 1165b235f015SRavi Pokala syslog(LOG_NOTICE, 1166b235f015SRavi Pokala "mount request from %s for non-directory path %s", 1167b235f015SRavi Pokala numerichost, dirpath); 1168b235f015SRavi Pokala if (debug) 1169b235f015SRavi Pokala warnx("mounting non-directory %s", dirpath); 1170b235f015SRavi Pokala bad = ENOTDIR; /* We will send error reply later */ 1171b235f015SRavi Pokala } 11728fae3551SRodney W. Grimes 11738fae3551SRodney W. Grimes /* Check in the exports list */ 1174a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1175b235f015SRavi Pokala if (bad) 1176b235f015SRavi Pokala ep = NULL; 1177b235f015SRavi Pokala else 117846a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead); 1179a62dc406SDoug Rabson hostset = defset = 0; 1180c3f86a25SRick Macklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1181c3f86a25SRick Macklem &numsecflavors, &secflavorsp) || 11828fae3551SRodney W. Grimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1183c3f86a25SRick Macklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1184c3f86a25SRick Macklem &secflavorsp)) || 11858fae3551SRodney W. Grimes (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 11868fae3551SRodney W. Grimes scan_tree(ep->ex_dirl, saddr) == 0))) { 1187e90cdb54SGuido van Rooij if (bad) { 1188389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 1189e90cdb54SGuido van Rooij (caddr_t)&bad)) 119074853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1191e90cdb54SGuido van Rooij sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1192e90cdb54SGuido van Rooij return; 1193e90cdb54SGuido van Rooij } 1194c3f86a25SRick Macklem if (hostset & DP_HOSTSET) { 1195a62dc406SDoug Rabson fhr.fhr_flag = hostset; 1196c3f86a25SRick Macklem fhr.fhr_numsecflavors = numsecflavors; 1197c3f86a25SRick Macklem fhr.fhr_secflavors = secflavorsp; 1198c3f86a25SRick Macklem } else { 1199a62dc406SDoug Rabson fhr.fhr_flag = defset; 1200c3f86a25SRick Macklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1201c3f86a25SRick Macklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1202c3f86a25SRick Macklem } 1203a62dc406SDoug Rabson fhr.fhr_vers = rqstp->rq_vers; 12048fae3551SRodney W. Grimes /* Get the file handle */ 120587564113SPeter Wemm memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 1206a62dc406SDoug Rabson if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 12078fae3551SRodney W. Grimes bad = errno; 120874853402SPhilippe Charnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1209389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 12108fae3551SRodney W. Grimes (caddr_t)&bad)) 121174853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1212a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12138fae3551SRodney W. Grimes return; 12148fae3551SRodney W. Grimes } 1215389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1216389b8446SPeter Wemm (caddr_t)&fhr)) 121774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 12188360efbdSAlfred Perlstein if (!lookup_failed) 12198360efbdSAlfred Perlstein add_mlist(host, dirpath); 12208fae3551SRodney W. Grimes else 12218360efbdSAlfred Perlstein add_mlist(numerichost, dirpath); 12228fae3551SRodney W. Grimes if (debug) 122374853402SPhilippe Charnier warnx("mount successful"); 1224c903443aSPeter Wemm if (dolog) 1225f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1226f51631d7SGuido van Rooij "mount request succeeded from %s for %s", 12278360efbdSAlfred Perlstein numerichost, dirpath); 1228f51631d7SGuido van Rooij } else { 1229b235f015SRavi Pokala if (!bad) 12308fae3551SRodney W. Grimes bad = EACCES; 1231f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1232f51631d7SGuido van Rooij "mount request denied from %s for %s", 12338360efbdSAlfred Perlstein numerichost, dirpath); 1234f51631d7SGuido van Rooij } 1235e90cdb54SGuido van Rooij 1236389b8446SPeter Wemm if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1237389b8446SPeter Wemm (caddr_t)&bad)) 123874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1239a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12408fae3551SRodney W. Grimes return; 12410775314bSDoug Rabson case MOUNTPROC_DUMP: 1242389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 124374853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1244c903443aSPeter Wemm else if (dolog) 1245f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1246f51631d7SGuido van Rooij "dump request succeeded from %s", 12478360efbdSAlfred Perlstein numerichost); 12488fae3551SRodney W. Grimes return; 12490775314bSDoug Rabson case MOUNTPROC_UMNT: 1250a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1251f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1252f51631d7SGuido van Rooij "umount request from %s from unprivileged port", 12538360efbdSAlfred Perlstein numerichost); 12548fae3551SRodney W. Grimes svcerr_weakauth(transp); 12558fae3551SRodney W. Grimes return; 12568fae3551SRodney W. Grimes } 1257389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1258f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable umount request from %s", 12598360efbdSAlfred Perlstein numerichost); 12608fae3551SRodney W. Grimes svcerr_decode(transp); 12618fae3551SRodney W. Grimes return; 12628fae3551SRodney W. Grimes } 1263cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL) { 1264cb479b11SAlfred Perlstein syslog(LOG_NOTICE, "umount request from %s " 1265cb479b11SAlfred Perlstein "for non existent path %s", 12668360efbdSAlfred Perlstein numerichost, dirpath); 1267cb479b11SAlfred Perlstein } 1268389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 126974853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 12708360efbdSAlfred Perlstein if (!lookup_failed) 127101709abfSIan Dowse del_mlist(host, dirpath); 127201709abfSIan Dowse del_mlist(numerichost, dirpath); 1273c903443aSPeter Wemm if (dolog) 1274f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1275f51631d7SGuido van Rooij "umount request succeeded from %s for %s", 12768360efbdSAlfred Perlstein numerichost, dirpath); 12778fae3551SRodney W. Grimes return; 12780775314bSDoug Rabson case MOUNTPROC_UMNTALL: 1279a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1280f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1281f51631d7SGuido van Rooij "umountall request from %s from unprivileged port", 12828360efbdSAlfred Perlstein numerichost); 12838fae3551SRodney W. Grimes svcerr_weakauth(transp); 12848fae3551SRodney W. Grimes return; 12858fae3551SRodney W. Grimes } 1286389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 128774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 12888360efbdSAlfred Perlstein if (!lookup_failed) 128901709abfSIan Dowse del_mlist(host, NULL); 129001709abfSIan Dowse del_mlist(numerichost, NULL); 1291c903443aSPeter Wemm if (dolog) 1292f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1293f51631d7SGuido van Rooij "umountall request succeeded from %s", 12948360efbdSAlfred Perlstein numerichost); 12958fae3551SRodney W. Grimes return; 12960775314bSDoug Rabson case MOUNTPROC_EXPORT: 1297389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1298389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1299389b8446SPeter Wemm (caddr_t)NULL)) 130074853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1301c903443aSPeter Wemm if (dolog) 1302f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1303f51631d7SGuido van Rooij "export request succeeded from %s", 13048360efbdSAlfred Perlstein numerichost); 13058fae3551SRodney W. Grimes return; 13068fae3551SRodney W. Grimes default: 13078fae3551SRodney W. Grimes svcerr_noproc(transp); 13088fae3551SRodney W. Grimes return; 13098fae3551SRodney W. Grimes } 13108fae3551SRodney W. Grimes } 13118fae3551SRodney W. Grimes 13128fae3551SRodney W. Grimes /* 13138fae3551SRodney W. Grimes * Xdr conversion for a dirpath string 13148fae3551SRodney W. Grimes */ 131519c46d8cSEdward Tomasz Napierala static int 1316a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp) 13178fae3551SRodney W. Grimes { 13180775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 13198fae3551SRodney W. Grimes } 13208fae3551SRodney W. Grimes 13218fae3551SRodney W. Grimes /* 1322a62dc406SDoug Rabson * Xdr routine to generate file handle reply 13238fae3551SRodney W. Grimes */ 132419c46d8cSEdward Tomasz Napierala static int 1325a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp) 13268fae3551SRodney W. Grimes { 13273d438ad6SDavid E. O'Brien struct fhreturn *fhrp = (struct fhreturn *)cp; 1328a62dc406SDoug Rabson u_long ok = 0, len, auth; 1329a9148abdSDoug Rabson int i; 13308fae3551SRodney W. Grimes 13318fae3551SRodney W. Grimes if (!xdr_long(xdrsp, &ok)) 13328fae3551SRodney W. Grimes return (0); 1333a62dc406SDoug Rabson switch (fhrp->fhr_vers) { 1334a62dc406SDoug Rabson case 1: 1335a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 1336a62dc406SDoug Rabson case 3: 1337a62dc406SDoug Rabson len = NFSX_V3FH; 1338a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1339a62dc406SDoug Rabson return (0); 1340a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 1341a62dc406SDoug Rabson return (0); 1342a9148abdSDoug Rabson if (fhrp->fhr_numsecflavors) { 1343a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1344a9148abdSDoug Rabson return (0); 1345a9148abdSDoug Rabson for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1346a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1347a9148abdSDoug Rabson return (0); 1348a9148abdSDoug Rabson return (1); 1349a9148abdSDoug Rabson } else { 1350a9148abdSDoug Rabson auth = AUTH_SYS; 1351a62dc406SDoug Rabson len = 1; 1352a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1353a62dc406SDoug Rabson return (0); 1354a62dc406SDoug Rabson return (xdr_long(xdrsp, &auth)); 1355a9148abdSDoug Rabson } 135680c7cc1cSPedro F. Giffuni } 1357a62dc406SDoug Rabson return (0); 13588fae3551SRodney W. Grimes } 13598fae3551SRodney W. Grimes 136019c46d8cSEdward Tomasz Napierala static int 1361a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused) 13628fae3551SRodney W. Grimes { 13638fae3551SRodney W. Grimes struct mountlist *mlp; 13648fae3551SRodney W. Grimes int true = 1; 13658fae3551SRodney W. Grimes int false = 0; 13668fae3551SRodney W. Grimes char *strp; 13678fae3551SRodney W. Grimes 13681da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 13698fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 13708fae3551SRodney W. Grimes return (0); 13718fae3551SRodney W. Grimes strp = &mlp->ml_host[0]; 13720775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 13738fae3551SRodney W. Grimes return (0); 13748fae3551SRodney W. Grimes strp = &mlp->ml_dirp[0]; 13750775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 13768fae3551SRodney W. Grimes return (0); 13778fae3551SRodney W. Grimes } 13788fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 13798fae3551SRodney W. Grimes return (0); 13808fae3551SRodney W. Grimes return (1); 13818fae3551SRodney W. Grimes } 13828fae3551SRodney W. Grimes 13838fae3551SRodney W. Grimes /* 13848fae3551SRodney W. Grimes * Xdr conversion for export list 13858fae3551SRodney W. Grimes */ 138619c46d8cSEdward Tomasz Napierala static int 1387a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 13888fae3551SRodney W. Grimes { 13898fae3551SRodney W. Grimes struct exportlist *ep; 13908fae3551SRodney W. Grimes int false = 0; 1391a62dc406SDoug Rabson int putdef; 1392a62dc406SDoug Rabson sigset_t sighup_mask; 139346a6b5c4SRick Macklem int i; 13948fae3551SRodney W. Grimes 1395a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1396a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 1397a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1398c9ac0f71SEmmanuel Vadot 139946a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++) 140046a6b5c4SRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) { 14018fae3551SRodney W. Grimes putdef = 0; 140291acb349SAlfred Perlstein if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 140391acb349SAlfred Perlstein &putdef, brief)) 14048fae3551SRodney W. Grimes goto errout; 14058fae3551SRodney W. Grimes if (ep->ex_defdir && putdef == 0 && 140646a6b5c4SRick Macklem put_exlist(ep->ex_defdir, xdrsp, NULL, 140791acb349SAlfred Perlstein &putdef, brief)) 14088fae3551SRodney W. Grimes goto errout; 14098fae3551SRodney W. Grimes } 1410a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 14118fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 14128fae3551SRodney W. Grimes return (0); 14138fae3551SRodney W. Grimes return (1); 14148fae3551SRodney W. Grimes errout: 1415a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 14168fae3551SRodney W. Grimes return (0); 14178fae3551SRodney W. Grimes } 14188fae3551SRodney W. Grimes 14198fae3551SRodney W. Grimes /* 14208fae3551SRodney W. Grimes * Called from xdr_explist() to traverse the tree and export the 14218fae3551SRodney W. Grimes * directory paths. 14228fae3551SRodney W. Grimes */ 142319c46d8cSEdward Tomasz Napierala static int 1424a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1425a7a7d96cSPhilippe Charnier int brief) 14268fae3551SRodney W. Grimes { 14278fae3551SRodney W. Grimes struct grouplist *grp; 14288fae3551SRodney W. Grimes struct hostlist *hp; 14298fae3551SRodney W. Grimes int true = 1; 14308fae3551SRodney W. Grimes int false = 0; 14318fae3551SRodney W. Grimes int gotalldir = 0; 14328fae3551SRodney W. Grimes char *strp; 14338fae3551SRodney W. Grimes 14348fae3551SRodney W. Grimes if (dp) { 143591acb349SAlfred Perlstein if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 14368fae3551SRodney W. Grimes return (1); 14378fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 14388fae3551SRodney W. Grimes return (1); 14398fae3551SRodney W. Grimes strp = dp->dp_dirp; 14400775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 14418fae3551SRodney W. Grimes return (1); 14428fae3551SRodney W. Grimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 14438fae3551SRodney W. Grimes gotalldir = 1; 14448fae3551SRodney W. Grimes *putdefp = 1; 14458fae3551SRodney W. Grimes } 144691acb349SAlfred Perlstein if (brief) { 144791acb349SAlfred Perlstein if (!xdr_bool(xdrsp, &true)) 144891acb349SAlfred Perlstein return (1); 144991acb349SAlfred Perlstein strp = "(...)"; 14500775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 145191acb349SAlfred Perlstein return (1); 145291acb349SAlfred Perlstein } else if ((dp->dp_flag & DP_DEFSET) == 0 && 14538fae3551SRodney W. Grimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 14548fae3551SRodney W. Grimes hp = dp->dp_hosts; 14558fae3551SRodney W. Grimes while (hp) { 14568fae3551SRodney W. Grimes grp = hp->ht_grp; 14578fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 14588fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 14598fae3551SRodney W. Grimes return (1); 14608360efbdSAlfred Perlstein strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 14618fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 14620775314bSDoug Rabson MNTNAMLEN)) 14638fae3551SRodney W. Grimes return (1); 14648fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 14658fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 14668fae3551SRodney W. Grimes return (1); 14678fae3551SRodney W. Grimes strp = grp->gr_ptr.gt_net.nt_name; 14688fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 14690775314bSDoug Rabson MNTNAMLEN)) 14708fae3551SRodney W. Grimes return (1); 14718fae3551SRodney W. Grimes } 14728fae3551SRodney W. Grimes hp = hp->ht_next; 14738fae3551SRodney W. Grimes if (gotalldir && hp == (struct hostlist *)NULL) { 14748fae3551SRodney W. Grimes hp = adp->dp_hosts; 14758fae3551SRodney W. Grimes gotalldir = 0; 14768fae3551SRodney W. Grimes } 14778fae3551SRodney W. Grimes } 14788fae3551SRodney W. Grimes } 14798fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 14808fae3551SRodney W. Grimes return (1); 148191acb349SAlfred Perlstein if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 14828fae3551SRodney W. Grimes return (1); 14838fae3551SRodney W. Grimes } 14848fae3551SRodney W. Grimes return (0); 14858fae3551SRodney W. Grimes } 14868fae3551SRodney W. Grimes 148719c46d8cSEdward Tomasz Napierala static int 1488a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp) 148991acb349SAlfred Perlstein { 149091acb349SAlfred Perlstein 149191acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 0); 149291acb349SAlfred Perlstein } 149391acb349SAlfred Perlstein 149419c46d8cSEdward Tomasz Napierala static int 1495a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp) 149691acb349SAlfred Perlstein { 149791acb349SAlfred Perlstein 149891acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 1); 149991acb349SAlfred Perlstein } 150091acb349SAlfred Perlstein 150119c46d8cSEdward Tomasz Napierala static char *line; 150219c46d8cSEdward Tomasz Napierala static size_t linesize; 150319c46d8cSEdward Tomasz Napierala static FILE *exp_file; 15048fae3551SRodney W. Grimes 15058fae3551SRodney W. Grimes /* 150696968c22SPawel Jakub Dawidek * Get the export list from one, currently open file 15078fae3551SRodney W. Grimes */ 150896968c22SPawel Jakub Dawidek static void 15090f0869bcSRick Macklem get_exportlist_one(int passno) 15108fae3551SRodney W. Grimes { 1511c9ac0f71SEmmanuel Vadot struct exportlist *ep; 15120f0869bcSRick Macklem struct grouplist *grp, *tgrp, *savgrp; 15138fae3551SRodney W. Grimes struct dirlist *dirhead; 151496968c22SPawel Jakub Dawidek struct statfs fsb; 1515cc5efddeSRick Macklem struct expcred anon; 15168fae3551SRodney W. Grimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1517cc5efddeSRick Macklem int len, has_host, got_nondir, dirplen, netgrp; 1518cc5efddeSRick Macklem uint64_t exflags; 15198fae3551SRodney W. Grimes 1520bcc1d071SRick Macklem v4root_phase = 0; 1521*2ffad162SRick Macklem anon.cr_groups = NULL; 15228fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 15238fae3551SRodney W. Grimes while (get_line()) { 15248fae3551SRodney W. Grimes if (debug) 152574853402SPhilippe Charnier warnx("got line %s", line); 15268fae3551SRodney W. Grimes cp = line; 15278fae3551SRodney W. Grimes nextfield(&cp, &endcp); 15288fae3551SRodney W. Grimes if (*cp == '#') 15298fae3551SRodney W. Grimes goto nextline; 15308fae3551SRodney W. Grimes 15318fae3551SRodney W. Grimes /* 15328fae3551SRodney W. Grimes * Set defaults. 15338fae3551SRodney W. Grimes */ 15348fae3551SRodney W. Grimes has_host = FALSE; 1535*2ffad162SRick Macklem anon.cr_groups = anon.cr_smallgrps; 15363e2d36ffSRick Macklem anon.cr_uid = UID_NOBODY; 1537cc5efddeSRick Macklem anon.cr_ngroups = 1; 15383e2d36ffSRick Macklem anon.cr_groups[0] = GID_NOGROUP; 15398fae3551SRodney W. Grimes exflags = MNT_EXPORTED; 15408fae3551SRodney W. Grimes got_nondir = 0; 15418fae3551SRodney W. Grimes opt_flags = 0; 15428fae3551SRodney W. Grimes ep = (struct exportlist *)NULL; 1543bcc1d071SRick Macklem dirp = NULL; 1544bcc1d071SRick Macklem 1545bcc1d071SRick Macklem /* 1546bcc1d071SRick Macklem * Handle the V4 root dir. 1547bcc1d071SRick Macklem */ 1548bcc1d071SRick Macklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1549bcc1d071SRick Macklem /* 1550bcc1d071SRick Macklem * V4: just indicates that it is the v4 root point, 1551bcc1d071SRick Macklem * so skip over that and set v4root_phase. 1552bcc1d071SRick Macklem */ 1553bcc1d071SRick Macklem if (v4root_phase > 0) { 1554bcc1d071SRick Macklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1555bcc1d071SRick Macklem goto nextline; 1556bcc1d071SRick Macklem } 1557bcc1d071SRick Macklem v4root_phase = 1; 1558bcc1d071SRick Macklem cp += 3; 1559bcc1d071SRick Macklem nextfield(&cp, &endcp); 1560bcc1d071SRick Macklem } 15618fae3551SRodney W. Grimes 15628fae3551SRodney W. Grimes /* 15638fae3551SRodney W. Grimes * Create new exports list entry 15648fae3551SRodney W. Grimes */ 15658fae3551SRodney W. Grimes len = endcp-cp; 15668fae3551SRodney W. Grimes tgrp = grp = get_grp(); 15678fae3551SRodney W. Grimes while (len > 0) { 15680775314bSDoug Rabson if (len > MNTNAMLEN) { 1569354fce28SConrad Meyer getexp_err(ep, tgrp, "mountpoint too long"); 15708fae3551SRodney W. Grimes goto nextline; 15718fae3551SRodney W. Grimes } 15728fae3551SRodney W. Grimes if (*cp == '-') { 15738fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1574354fce28SConrad Meyer getexp_err(ep, tgrp, 1575354fce28SConrad Meyer "flag before export path definition"); 15768fae3551SRodney W. Grimes goto nextline; 15778fae3551SRodney W. Grimes } 15788fae3551SRodney W. Grimes if (debug) 157974853402SPhilippe Charnier warnx("doing opt %s", cp); 15808fae3551SRodney W. Grimes got_nondir = 1; 15818fae3551SRodney W. Grimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 15828fae3551SRodney W. Grimes &exflags, &anon)) { 1583354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 15848fae3551SRodney W. Grimes goto nextline; 15858fae3551SRodney W. Grimes } 15868fae3551SRodney W. Grimes } else if (*cp == '/') { 15878fae3551SRodney W. Grimes savedc = *endcp; 15888fae3551SRodney W. Grimes *endcp = '\0'; 1589bcc1d071SRick Macklem if (v4root_phase > 1) { 1590bcc1d071SRick Macklem if (dirp != NULL) { 1591354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1592bcc1d071SRick Macklem goto nextline; 1593bcc1d071SRick Macklem } 1594bcc1d071SRick Macklem } 15958fae3551SRodney W. Grimes if (check_dirpath(cp) && 15968fae3551SRodney W. Grimes statfs(cp, &fsb) >= 0) { 15979896584aSRick Macklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 15989896584aSRick Macklem syslog(LOG_ERR, "Warning: exporting of " 15999896584aSRick Macklem "automounted fs %s not supported", cp); 16008fae3551SRodney W. Grimes if (got_nondir) { 1601354fce28SConrad Meyer getexp_err(ep, tgrp, "dirs must be first"); 16028fae3551SRodney W. Grimes goto nextline; 16038fae3551SRodney W. Grimes } 1604bcc1d071SRick Macklem if (v4root_phase == 1) { 1605bcc1d071SRick Macklem if (dirp != NULL) { 1606354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1607bcc1d071SRick Macklem goto nextline; 1608bcc1d071SRick Macklem } 1609bcc1d071SRick Macklem if (strlen(v4root_dirpath) == 0) { 1610bcc1d071SRick Macklem strlcpy(v4root_dirpath, cp, 1611bcc1d071SRick Macklem sizeof (v4root_dirpath)); 1612bcc1d071SRick Macklem } else if (strcmp(v4root_dirpath, cp) 1613bcc1d071SRick Macklem != 0) { 1614bcc1d071SRick Macklem syslog(LOG_ERR, 1615bcc1d071SRick Macklem "different V4 dirpath %s", cp); 1616354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 1617bcc1d071SRick Macklem goto nextline; 1618bcc1d071SRick Macklem } 1619bcc1d071SRick Macklem dirp = cp; 1620bcc1d071SRick Macklem v4root_phase = 2; 1621bcc1d071SRick Macklem got_nondir = 1; 1622bcc1d071SRick Macklem ep = get_exp(); 1623bcc1d071SRick Macklem } else { 16248fae3551SRodney W. Grimes if (ep) { 1625245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, &fsb.f_fsid) 1626245bfd34SRyan Moeller != 0) { 1627354fce28SConrad Meyer getexp_err(ep, tgrp, 1628354fce28SConrad Meyer "fsid mismatch"); 16298fae3551SRodney W. Grimes goto nextline; 16308fae3551SRodney W. Grimes } 16318fae3551SRodney W. Grimes } else { 16328fae3551SRodney W. Grimes /* 16338fae3551SRodney W. Grimes * See if this directory is already 16348fae3551SRodney W. Grimes * in the list. 16358fae3551SRodney W. Grimes */ 163646a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead); 16378fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 16388fae3551SRodney W. Grimes ep = get_exp(); 16398fae3551SRodney W. Grimes ep->ex_fs = fsb.f_fsid; 1640380a3fcdSEmmanuel Vadot ep->ex_fsdir = strdup(fsb.f_mntonname); 1641380a3fcdSEmmanuel Vadot if (ep->ex_fsdir == NULL) 16428fae3551SRodney W. Grimes out_of_mem(); 16438fae3551SRodney W. Grimes if (debug) 1644bcc1d071SRick Macklem warnx( 1645bcc1d071SRick Macklem "making new ep fs=0x%x,0x%x", 16468fae3551SRodney W. Grimes fsb.f_fsid.val[0], 16478fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 16488fae3551SRodney W. Grimes } else if (debug) 164974853402SPhilippe Charnier warnx("found ep fs=0x%x,0x%x", 16508fae3551SRodney W. Grimes fsb.f_fsid.val[0], 16518fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 16528fae3551SRodney W. Grimes } 16538fae3551SRodney W. Grimes 16548fae3551SRodney W. Grimes /* 16558fae3551SRodney W. Grimes * Add dirpath to export mount point. 16568fae3551SRodney W. Grimes */ 16578fae3551SRodney W. Grimes dirp = add_expdir(&dirhead, cp, len); 16588fae3551SRodney W. Grimes dirplen = len; 1659bcc1d071SRick Macklem } 16608fae3551SRodney W. Grimes } else { 1661354fce28SConrad Meyer getexp_err(ep, tgrp, 1662354fce28SConrad Meyer "symbolic link in export path or statfs failed"); 16638fae3551SRodney W. Grimes goto nextline; 16648fae3551SRodney W. Grimes } 16658fae3551SRodney W. Grimes *endcp = savedc; 16668fae3551SRodney W. Grimes } else { 16678fae3551SRodney W. Grimes savedc = *endcp; 16688fae3551SRodney W. Grimes *endcp = '\0'; 16698fae3551SRodney W. Grimes got_nondir = 1; 16708fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1671354fce28SConrad Meyer getexp_err(ep, tgrp, 1672354fce28SConrad Meyer "host(s) before export path definition"); 16738fae3551SRodney W. Grimes goto nextline; 16748fae3551SRodney W. Grimes } 16758fae3551SRodney W. Grimes 16768fae3551SRodney W. Grimes /* 16778fae3551SRodney W. Grimes * Get the host or netgroup. 16788fae3551SRodney W. Grimes */ 16798fae3551SRodney W. Grimes setnetgrent(cp); 16808fae3551SRodney W. Grimes netgrp = getnetgrent(&hst, &usr, &dom); 16818fae3551SRodney W. Grimes do { 16828fae3551SRodney W. Grimes if (has_host) { 16838fae3551SRodney W. Grimes grp->gr_next = get_grp(); 16848fae3551SRodney W. Grimes grp = grp->gr_next; 16858fae3551SRodney W. Grimes } 16868fae3551SRodney W. Grimes if (netgrp) { 16879d70a156SJoerg Wunsch if (hst == 0) { 168874853402SPhilippe Charnier syslog(LOG_ERR, 168974853402SPhilippe Charnier "null hostname in netgroup %s, skipping", cp); 169001d48801SJoerg Wunsch grp->gr_type = GT_IGNORE; 16919d70a156SJoerg Wunsch } else if (get_host(hst, grp, tgrp)) { 169274853402SPhilippe Charnier syslog(LOG_ERR, 169374853402SPhilippe Charnier "bad host %s in netgroup %s, skipping", hst, cp); 1694a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 16958fae3551SRodney W. Grimes } 16968b5a6d67SBill Paul } else if (get_host(cp, grp, tgrp)) { 169774853402SPhilippe Charnier syslog(LOG_ERR, "bad host %s, skipping", cp); 1698a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 16998fae3551SRodney W. Grimes } 17008fae3551SRodney W. Grimes has_host = TRUE; 17018fae3551SRodney W. Grimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 17028fae3551SRodney W. Grimes endnetgrent(); 17038fae3551SRodney W. Grimes *endcp = savedc; 17048fae3551SRodney W. Grimes } 17058fae3551SRodney W. Grimes cp = endcp; 17068fae3551SRodney W. Grimes nextfield(&cp, &endcp); 17078fae3551SRodney W. Grimes len = endcp - cp; 17088fae3551SRodney W. Grimes } 17098fae3551SRodney W. Grimes if (check_options(dirhead)) { 1710354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 17118fae3551SRodney W. Grimes goto nextline; 17128fae3551SRodney W. Grimes } 17138fae3551SRodney W. Grimes if (!has_host) { 17146d359f31SIan Dowse grp->gr_type = GT_DEFAULT; 17158fae3551SRodney W. Grimes if (debug) 171674853402SPhilippe Charnier warnx("adding a default entry"); 17178fae3551SRodney W. Grimes 17188fae3551SRodney W. Grimes /* 17198fae3551SRodney W. Grimes * Don't allow a network export coincide with a list of 17208fae3551SRodney W. Grimes * host(s) on the same line. 17218fae3551SRodney W. Grimes */ 17228fae3551SRodney W. Grimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1723354fce28SConrad Meyer getexp_err(ep, tgrp, "network/host conflict"); 17248fae3551SRodney W. Grimes goto nextline; 1725a968cfd8SJonathan Lemon 1726a968cfd8SJonathan Lemon /* 1727a968cfd8SJonathan Lemon * If an export list was specified on this line, make sure 1728a968cfd8SJonathan Lemon * that we have at least one valid entry, otherwise skip it. 1729a968cfd8SJonathan Lemon */ 1730a968cfd8SJonathan Lemon } else { 1731a968cfd8SJonathan Lemon grp = tgrp; 1732a968cfd8SJonathan Lemon while (grp && grp->gr_type == GT_IGNORE) 1733a968cfd8SJonathan Lemon grp = grp->gr_next; 1734a968cfd8SJonathan Lemon if (! grp) { 1735354fce28SConrad Meyer getexp_err(ep, tgrp, "no valid entries"); 1736a968cfd8SJonathan Lemon goto nextline; 1737a968cfd8SJonathan Lemon } 17388fae3551SRodney W. Grimes } 17398fae3551SRodney W. Grimes 1740bcc1d071SRick Macklem if (v4root_phase == 1) { 1741354fce28SConrad Meyer getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); 1742bcc1d071SRick Macklem goto nextline; 1743bcc1d071SRick Macklem } 1744bcc1d071SRick Macklem 17458fae3551SRodney W. Grimes /* 17468fae3551SRodney W. Grimes * Loop through hosts, pushing the exports into the kernel. 17478fae3551SRodney W. Grimes * After loop, tgrp points to the start of the list and 17488fae3551SRodney W. Grimes * grp points to the last entry in the list. 17490f0869bcSRick Macklem * Do not do the do_mount() for passno == 1, since the 17500f0869bcSRick Macklem * second pass will do it, as required. 17518fae3551SRodney W. Grimes */ 17528fae3551SRodney W. Grimes grp = tgrp; 17538fae3551SRodney W. Grimes do { 17540f0869bcSRick Macklem grp->gr_exflags = exflags; 1755cc5efddeSRick Macklem cp_cred(&grp->gr_anon, &anon); 17560f0869bcSRick Macklem if (v4root_phase == 2 && passno == 0) 17570f0869bcSRick Macklem LOGDEBUG("do_mount v4root"); 17580f0869bcSRick Macklem if (passno == 0 && do_mount(ep, grp, exflags, &anon, 17590f0869bcSRick Macklem dirp, dirplen, &fsb, ep->ex_numsecflavors, 17600f0869bcSRick Macklem ep->ex_secflavors)) { 1761354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 17628fae3551SRodney W. Grimes goto nextline; 17638fae3551SRodney W. Grimes } 17648fae3551SRodney W. Grimes } while (grp->gr_next && (grp = grp->gr_next)); 17658fae3551SRodney W. Grimes 17668fae3551SRodney W. Grimes /* 1767bcc1d071SRick Macklem * For V4: don't enter in mount lists. 1768bcc1d071SRick Macklem */ 176973f4ccbdSRick Macklem if (v4root_phase > 0 && v4root_phase <= 2) { 177073f4ccbdSRick Macklem /* 1771c2ec1113SRick Macklem * These structures are used for the reload, 17720f0869bcSRick Macklem * so save them for that case. Otherwise, just 177373f4ccbdSRick Macklem * free them up now. 177473f4ccbdSRick Macklem */ 17750f0869bcSRick Macklem if (passno == 1 && ep != NULL) { 17760f0869bcSRick Macklem savgrp = tgrp; 17770f0869bcSRick Macklem while (tgrp != NULL) { 17780f0869bcSRick Macklem /* 17790f0869bcSRick Macklem * Save the security flavors and exflags 17800f0869bcSRick Macklem * for this host set in the groups. 17810f0869bcSRick Macklem */ 17820f0869bcSRick Macklem tgrp->gr_numsecflavors = 17830f0869bcSRick Macklem ep->ex_numsecflavors; 17840f0869bcSRick Macklem if (ep->ex_numsecflavors > 0) 17850f0869bcSRick Macklem memcpy(tgrp->gr_secflavors, 17860f0869bcSRick Macklem ep->ex_secflavors, 17870f0869bcSRick Macklem sizeof(ep->ex_secflavors)); 17880f0869bcSRick Macklem tgrp = tgrp->gr_next; 17890f0869bcSRick Macklem } 17900f0869bcSRick Macklem if (v4root_ep == NULL) { 17910f0869bcSRick Macklem v4root_ep = ep; 17920f0869bcSRick Macklem ep = NULL; /* Don't free below. */ 17930f0869bcSRick Macklem } 17940f0869bcSRick Macklem grp->gr_next = v4root_ep->ex_grphead; 17950f0869bcSRick Macklem v4root_ep->ex_grphead = savgrp; 17960f0869bcSRick Macklem } 179773f4ccbdSRick Macklem if (ep != NULL) 179873f4ccbdSRick Macklem free_exp(ep); 179973f4ccbdSRick Macklem while (tgrp != NULL) { 180073f4ccbdSRick Macklem grp = tgrp; 180173f4ccbdSRick Macklem tgrp = tgrp->gr_next; 180273f4ccbdSRick Macklem free_grp(grp); 180373f4ccbdSRick Macklem } 1804bcc1d071SRick Macklem goto nextline; 180573f4ccbdSRick Macklem } 1806bcc1d071SRick Macklem 1807bcc1d071SRick Macklem /* 18088fae3551SRodney W. Grimes * Success. Update the data structures. 18098fae3551SRodney W. Grimes */ 18108fae3551SRodney W. Grimes if (has_host) { 18110f0869bcSRick Macklem hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags); 1812711d44eeSRick Macklem grp->gr_next = ep->ex_grphead; 1813711d44eeSRick Macklem ep->ex_grphead = tgrp; 18148fae3551SRodney W. Grimes } else { 18158fae3551SRodney W. Grimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 18160f0869bcSRick Macklem opt_flags, &anon, exflags); 18178fae3551SRodney W. Grimes free_grp(grp); 18188fae3551SRodney W. Grimes } 18198fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 18208fae3551SRodney W. Grimes if ((ep->ex_flag & EX_LINKED) == 0) { 182146a6b5c4SRick Macklem insert_exports(ep, exphead); 18228fae3551SRodney W. Grimes 18238fae3551SRodney W. Grimes ep->ex_flag |= EX_LINKED; 18248fae3551SRodney W. Grimes } 18258fae3551SRodney W. Grimes nextline: 1826bcc1d071SRick Macklem v4root_phase = 0; 18278fae3551SRodney W. Grimes if (dirhead) { 18288fae3551SRodney W. Grimes free_dir(dirhead); 18298fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 18308fae3551SRodney W. Grimes } 1831*2ffad162SRick Macklem if (anon.cr_groups != anon.cr_smallgrps) { 1832*2ffad162SRick Macklem free(anon.cr_groups); 1833*2ffad162SRick Macklem anon.cr_groups = NULL; 1834*2ffad162SRick Macklem } 18358fae3551SRodney W. Grimes } 183696968c22SPawel Jakub Dawidek } 183796968c22SPawel Jakub Dawidek 183896968c22SPawel Jakub Dawidek /* 183996968c22SPawel Jakub Dawidek * Get the export list from all specified files 184096968c22SPawel Jakub Dawidek */ 184119c46d8cSEdward Tomasz Napierala static void 18420f0869bcSRick Macklem get_exportlist(int passno) 184396968c22SPawel Jakub Dawidek { 184496968c22SPawel Jakub Dawidek struct export_args export; 184596968c22SPawel Jakub Dawidek struct iovec *iov; 18463e08dc74SRick Macklem struct statfs *mntbufp; 184796968c22SPawel Jakub Dawidek char errmsg[255]; 1848e0bcf086SEitan Adler int num, i; 184996968c22SPawel Jakub Dawidek int iovlen; 1850bcc1d071SRick Macklem struct nfsex_args eargs; 18510f0869bcSRick Macklem FILE *debug_file; 185296968c22SPawel Jakub Dawidek 18530f0869bcSRick Macklem if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) { 18540f0869bcSRick Macklem fclose(debug_file); 18550f0869bcSRick Macklem logdebug = 1; 18560f0869bcSRick Macklem } else 18570f0869bcSRick Macklem logdebug = 0; 18580f0869bcSRick Macklem LOGDEBUG("passno=%d", passno); 1859bcc1d071SRick Macklem v4root_dirpath[0] = '\0'; 18600f0869bcSRick Macklem free_v4rootexp(); 18610f0869bcSRick Macklem if (passno == 1) { 18620f0869bcSRick Macklem /* 18630f0869bcSRick Macklem * Save the current lists as old ones, so that the new lists 18640f0869bcSRick Macklem * can be compared with the old ones in the 2nd pass. 18650f0869bcSRick Macklem */ 18660f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) { 18670f0869bcSRick Macklem SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]); 18680f0869bcSRick Macklem SLIST_INIT(&exphead[i]); 18690f0869bcSRick Macklem } 18700f0869bcSRick Macklem 18710f0869bcSRick Macklem /* Note that the public fh has not yet been set. */ 18720f0869bcSRick Macklem has_set_publicfh = 0; 18730f0869bcSRick Macklem 18740f0869bcSRick Macklem /* Read the export file(s) and process them */ 18750f0869bcSRick Macklem read_exportfile(passno); 18760f0869bcSRick Macklem } else { 18770f0869bcSRick Macklem /* 18780f0869bcSRick Macklem * Just make the old lists empty. 18790f0869bcSRick Macklem * exphashsize == 0 for the first call, before oldexphead 18800f0869bcSRick Macklem * has been initialized-->loop won't be executed. 18810f0869bcSRick Macklem */ 18820f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 18830f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]); 18840f0869bcSRick Macklem } 18850f0869bcSRick Macklem 188696968c22SPawel Jakub Dawidek bzero(&export, sizeof(export)); 188796968c22SPawel Jakub Dawidek export.ex_flags = MNT_DELEXPORT; 188896968c22SPawel Jakub Dawidek iov = NULL; 188996968c22SPawel Jakub Dawidek iovlen = 0; 189096968c22SPawel Jakub Dawidek bzero(errmsg, sizeof(errmsg)); 189196968c22SPawel Jakub Dawidek 18920f0869bcSRick Macklem if (suspend_nfsd != 0) 18930f0869bcSRick Macklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 189496968c22SPawel Jakub Dawidek /* 18950f0869bcSRick Macklem * Delete the old V4 root dir. 1896bcc1d071SRick Macklem */ 1897bcc1d071SRick Macklem bzero(&eargs, sizeof (eargs)); 1898bcc1d071SRick Macklem eargs.export.ex_flags = MNT_DELEXPORT; 1899cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, (caddr_t)&eargs) < 0 && 1900bcc1d071SRick Macklem errno != ENOENT) 1901bcc1d071SRick Macklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1902bcc1d071SRick Macklem 19030f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 19040f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 19050f0869bcSRick Macklem build_iovec(&iov, &iovlen, "from", NULL, 0); 19060f0869bcSRick Macklem build_iovec(&iov, &iovlen, "update", NULL, 0); 19070f0869bcSRick Macklem build_iovec(&iov, &iovlen, "export", &export, 19080f0869bcSRick Macklem sizeof(export)); 19090f0869bcSRick Macklem build_iovec(&iov, &iovlen, "errmsg", errmsg, 19100f0869bcSRick Macklem sizeof(errmsg)); 19110f0869bcSRick Macklem 1912bcc1d071SRick Macklem /* 19130f0869bcSRick Macklem * For passno == 1, compare the old and new lists updating the kernel 19140f0869bcSRick Macklem * exports for any cases that have changed. 19150f0869bcSRick Macklem * This call is doing the second pass through the lists. 19160f0869bcSRick Macklem * If it fails, fall back on the bulk reload. 19170f0869bcSRick Macklem */ 19180f0869bcSRick Macklem if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) == 19190f0869bcSRick Macklem 0) { 19200f0869bcSRick Macklem LOGDEBUG("compareok"); 19210f0869bcSRick Macklem /* Free up the old lists. */ 19220f0869bcSRick Macklem free_exports(oldexphead); 19230f0869bcSRick Macklem } else { 19240f0869bcSRick Macklem LOGDEBUG("doing passno=0"); 19250f0869bcSRick Macklem /* 19260f0869bcSRick Macklem * Clear flag that notes if a public fh has been exported. 19270f0869bcSRick Macklem * It is set by do_mount() if MNT_EXPUBLIC is set for the entry. 1928bcc1d071SRick Macklem */ 1929bcc1d071SRick Macklem has_publicfh = 0; 1930bcc1d071SRick Macklem 19310f0869bcSRick Macklem /* exphead == NULL if not yet allocated (first call). */ 19320f0869bcSRick Macklem if (exphead != NULL) { 19330f0869bcSRick Macklem /* 19340f0869bcSRick Macklem * First, get rid of the old lists. 19350f0869bcSRick Macklem */ 19360f0869bcSRick Macklem free_exports(exphead); 19370f0869bcSRick Macklem free_exports(oldexphead); 19380f0869bcSRick Macklem } 19390f0869bcSRick Macklem 1940bcc1d071SRick Macklem /* 194196968c22SPawel Jakub Dawidek * And delete exports that are in the kernel for all local 194296968c22SPawel Jakub Dawidek * filesystems. 19430f0869bcSRick Macklem * XXX: Should know how to handle all local exportable 19440f0869bcSRick Macklem * filesystems. 194596968c22SPawel Jakub Dawidek */ 194696968c22SPawel Jakub Dawidek num = getmntinfo(&mntbufp, MNT_NOWAIT); 194796968c22SPawel Jakub Dawidek 194846a6b5c4SRick Macklem /* Allocate hash tables, for first call. */ 194946a6b5c4SRick Macklem if (exphead == NULL) { 195046a6b5c4SRick Macklem /* Target an average linked list length of 10. */ 195146a6b5c4SRick Macklem exphashsize = num / 10; 195246a6b5c4SRick Macklem if (exphashsize < 1) 195346a6b5c4SRick Macklem exphashsize = 1; 195446a6b5c4SRick Macklem else if (exphashsize > 100000) 195546a6b5c4SRick Macklem exphashsize = 100000; 195646a6b5c4SRick Macklem exphead = malloc(exphashsize * sizeof(*exphead)); 19570f0869bcSRick Macklem oldexphead = malloc(exphashsize * sizeof(*oldexphead)); 19580f0869bcSRick Macklem if (exphead == NULL || oldexphead == NULL) 19590f0869bcSRick Macklem errx(1, "Can't malloc hash tables"); 196046a6b5c4SRick Macklem 19610f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) { 196246a6b5c4SRick Macklem SLIST_INIT(&exphead[i]); 19630f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]); 196446a6b5c4SRick Macklem } 196596968c22SPawel Jakub Dawidek } 196696968c22SPawel Jakub Dawidek 19673e08dc74SRick Macklem for (i = 0; i < num; i++) 19683e08dc74SRick Macklem delete_export(iov, iovlen, &mntbufp[i], errmsg); 196996968c22SPawel Jakub Dawidek 19700f0869bcSRick Macklem 19710f0869bcSRick Macklem /* Read the export file(s) and process them */ 19720f0869bcSRick Macklem read_exportfile(0); 19730f0869bcSRick Macklem } 19740f0869bcSRick Macklem 197596968c22SPawel Jakub Dawidek if (iov != NULL) { 197696968c22SPawel Jakub Dawidek /* Free strings allocated by strdup() in getmntopts.c */ 197796968c22SPawel Jakub Dawidek free(iov[0].iov_base); /* fstype */ 197896968c22SPawel Jakub Dawidek free(iov[2].iov_base); /* fspath */ 197996968c22SPawel Jakub Dawidek free(iov[4].iov_base); /* from */ 198096968c22SPawel Jakub Dawidek free(iov[6].iov_base); /* update */ 198196968c22SPawel Jakub Dawidek free(iov[8].iov_base); /* export */ 198296968c22SPawel Jakub Dawidek free(iov[10].iov_base); /* errmsg */ 198396968c22SPawel Jakub Dawidek 198496968c22SPawel Jakub Dawidek /* free iov, allocated by realloc() */ 198596968c22SPawel Jakub Dawidek free(iov); 198696968c22SPawel Jakub Dawidek iovlen = 0; 198796968c22SPawel Jakub Dawidek } 198896968c22SPawel Jakub Dawidek 1989bcc1d071SRick Macklem /* 1990bcc1d071SRick Macklem * If there was no public fh, clear any previous one set. 1991bcc1d071SRick Macklem */ 19920f0869bcSRick Macklem if (has_publicfh == 0) { 19930f0869bcSRick Macklem LOGDEBUG("clear public fh"); 1994bcc1d071SRick Macklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 19950f0869bcSRick Macklem } 1996c548eb5cSRick Macklem 1997c548eb5cSRick Macklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1998c548eb5cSRick Macklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 19990f0869bcSRick Macklem LOGDEBUG("eo get_exportlist"); 200096968c22SPawel Jakub Dawidek } 20018fae3551SRodney W. Grimes 20028fae3551SRodney W. Grimes /* 20031a9a992fSRick Macklem * Insert an export entry in the appropriate list. 20041a9a992fSRick Macklem */ 20051a9a992fSRick Macklem static void 20061a9a992fSRick Macklem insert_exports(struct exportlist *ep, struct exportlisthead *exhp) 20071a9a992fSRick Macklem { 200846a6b5c4SRick Macklem uint32_t i; 20091a9a992fSRick Macklem 201046a6b5c4SRick Macklem i = EXPHASH(&ep->ex_fs); 20110f0869bcSRick Macklem LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i); 201246a6b5c4SRick Macklem SLIST_INSERT_HEAD(&exhp[i], ep, entries); 20131a9a992fSRick Macklem } 20141a9a992fSRick Macklem 20151a9a992fSRick Macklem /* 20161a9a992fSRick Macklem * Free up the exports lists passed in as arguments. 20171a9a992fSRick Macklem */ 20181a9a992fSRick Macklem static void 20191a9a992fSRick Macklem free_exports(struct exportlisthead *exhp) 20201a9a992fSRick Macklem { 20211a9a992fSRick Macklem struct exportlist *ep, *ep2; 202246a6b5c4SRick Macklem int i; 20231a9a992fSRick Macklem 202446a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++) { 202546a6b5c4SRick Macklem SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) { 202646a6b5c4SRick Macklem SLIST_REMOVE(&exhp[i], ep, exportlist, entries); 20271a9a992fSRick Macklem free_exp(ep); 20281a9a992fSRick Macklem } 202946a6b5c4SRick Macklem SLIST_INIT(&exhp[i]); 203046a6b5c4SRick Macklem } 20311a9a992fSRick Macklem } 20321a9a992fSRick Macklem 20331a9a992fSRick Macklem /* 20343e08dc74SRick Macklem * Read the exports file(s) and call get_exportlist_one() for each line. 20353e08dc74SRick Macklem */ 20363e08dc74SRick Macklem static void 20370f0869bcSRick Macklem read_exportfile(int passno) 20383e08dc74SRick Macklem { 20393e08dc74SRick Macklem int done, i; 20403e08dc74SRick Macklem 20413e08dc74SRick Macklem /* 20423e08dc74SRick Macklem * Read in the exports file and build the list, calling 20433e08dc74SRick Macklem * nmount() as we go along to push the export rules into the kernel. 20443e08dc74SRick Macklem */ 20453e08dc74SRick Macklem done = 0; 20463e08dc74SRick Macklem for (i = 0; exnames[i] != NULL; i++) { 20473e08dc74SRick Macklem if (debug) 20483e08dc74SRick Macklem warnx("reading exports from %s", exnames[i]); 20493e08dc74SRick Macklem if ((exp_file = fopen(exnames[i], "r")) == NULL) { 20503e08dc74SRick Macklem syslog(LOG_WARNING, "can't open %s", exnames[i]); 20513e08dc74SRick Macklem continue; 20523e08dc74SRick Macklem } 20530f0869bcSRick Macklem get_exportlist_one(passno); 20543e08dc74SRick Macklem fclose(exp_file); 20553e08dc74SRick Macklem done++; 20563e08dc74SRick Macklem } 20573e08dc74SRick Macklem if (done == 0) { 20583e08dc74SRick Macklem syslog(LOG_ERR, "can't open any exports file"); 20593e08dc74SRick Macklem exit(2); 20603e08dc74SRick Macklem } 20613e08dc74SRick Macklem } 20623e08dc74SRick Macklem 20633e08dc74SRick Macklem /* 20640f0869bcSRick Macklem * Compare the export lists against the old ones and do nmount() operations 20650f0869bcSRick Macklem * for any cases that have changed. This avoids doing nmount() for entries 20660f0869bcSRick Macklem * that have not changed. 20670f0869bcSRick Macklem * Return 0 upon success, 1 otherwise. 20680f0869bcSRick Macklem */ 20690f0869bcSRick Macklem static int 20700f0869bcSRick Macklem compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg) 20710f0869bcSRick Macklem { 20720f0869bcSRick Macklem struct exportlist *ep, *oep; 20730f0869bcSRick Macklem struct grouplist *grp; 20740f0869bcSRick Macklem struct statfs fs, ofs; 20750f0869bcSRick Macklem int i, ret; 20760f0869bcSRick Macklem 20770f0869bcSRick Macklem /* 20780f0869bcSRick Macklem * Loop through the current list and look for an entry in the old 20790f0869bcSRick Macklem * list. 20800f0869bcSRick Macklem * If found, check to see if it the same. 20810f0869bcSRick Macklem * If it is not the same, delete and re-export. 20820f0869bcSRick Macklem * Then mark it done on the old list. 20830f0869bcSRick Macklem * else (not found) 20840f0869bcSRick Macklem * export it. 20850f0869bcSRick Macklem * Any entries left in the old list after processing must have their 20860f0869bcSRick Macklem * exports deleted. 20870f0869bcSRick Macklem */ 20880f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 20890f0869bcSRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) { 20900f0869bcSRick Macklem LOGDEBUG("foreach ep=%s", ep->ex_fsdir); 20910f0869bcSRick Macklem oep = ex_search(&ep->ex_fs, oldexphead); 20920f0869bcSRick Macklem if (oep != NULL) { 20930f0869bcSRick Macklem /* 20940f0869bcSRick Macklem * Check the mount paths are the same. 20950f0869bcSRick Macklem * If not, return 1 so that the reload of the 20960f0869bcSRick Macklem * exports will be done in bulk, the 20970f0869bcSRick Macklem * passno == 0 way. 20980f0869bcSRick Macklem */ 20990f0869bcSRick Macklem LOGDEBUG("found old exp"); 21000f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) 21010f0869bcSRick Macklem return (1); 21020f0869bcSRick Macklem LOGDEBUG("same fsdir"); 21030f0869bcSRick Macklem /* 21040f0869bcSRick Macklem * Test to see if the entry is the same. 21050f0869bcSRick Macklem * If not the same delete exports and 21060f0869bcSRick Macklem * re-export. 21070f0869bcSRick Macklem */ 21080f0869bcSRick Macklem if (compare_export(ep, oep) != 0) { 21090f0869bcSRick Macklem /* 21100f0869bcSRick Macklem * Clear has_publicfh if if was set 21110f0869bcSRick Macklem * in the old exports, but only if it 21120f0869bcSRick Macklem * has not been set during processing of 21130f0869bcSRick Macklem * the exports for this pass, as 21140f0869bcSRick Macklem * indicated by has_set_publicfh. 21150f0869bcSRick Macklem */ 21160f0869bcSRick Macklem if (has_set_publicfh == 0 && 21170f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0) 21180f0869bcSRick Macklem has_publicfh = 0; 21190f0869bcSRick Macklem 21200f0869bcSRick Macklem /* Delete and re-export. */ 21210f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0) 21220f0869bcSRick Macklem return (1); 21230f0869bcSRick Macklem delete_export(iov, iovlen, &fs, errmsg); 21240f0869bcSRick Macklem ret = do_export_mount(ep, &fs); 21250f0869bcSRick Macklem if (ret != 0) 21260f0869bcSRick Macklem return (ret); 21270f0869bcSRick Macklem } 21280f0869bcSRick Macklem oep->ex_flag |= EX_DONE; 21290f0869bcSRick Macklem LOGDEBUG("exdone"); 21300f0869bcSRick Macklem } else { 21310f0869bcSRick Macklem LOGDEBUG("not found so export"); 21320f0869bcSRick Macklem /* Not found, so do export. */ 21330f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0) 21340f0869bcSRick Macklem return (1); 21350f0869bcSRick Macklem ret = do_export_mount(ep, &fs); 21360f0869bcSRick Macklem if (ret != 0) 21370f0869bcSRick Macklem return (ret); 21380f0869bcSRick Macklem } 21390f0869bcSRick Macklem } 21400f0869bcSRick Macklem 21410f0869bcSRick Macklem /* Delete exports not done. */ 21420f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 21430f0869bcSRick Macklem SLIST_FOREACH(oep, &oldexphead[i], entries) { 21440f0869bcSRick Macklem if ((oep->ex_flag & EX_DONE) == 0) { 21450f0869bcSRick Macklem LOGDEBUG("not done delete=%s", oep->ex_fsdir); 21460f0869bcSRick Macklem if (statfs(oep->ex_fsdir, &ofs) >= 0 && 2147245bfd34SRyan Moeller fsidcmp(&oep->ex_fs, &ofs.f_fsid) == 0) { 21480f0869bcSRick Macklem LOGDEBUG("do delete"); 21490f0869bcSRick Macklem /* 21500f0869bcSRick Macklem * Clear has_publicfh if if was set 21510f0869bcSRick Macklem * in the old exports, but only if it 21520f0869bcSRick Macklem * has not been set during processing of 21530f0869bcSRick Macklem * the exports for this pass, as 21540f0869bcSRick Macklem * indicated by has_set_publicfh. 21550f0869bcSRick Macklem */ 21560f0869bcSRick Macklem if (has_set_publicfh == 0 && 21570f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0) 21580f0869bcSRick Macklem has_publicfh = 0; 21590f0869bcSRick Macklem 21600f0869bcSRick Macklem delete_export(iov, iovlen, &ofs, 21610f0869bcSRick Macklem errmsg); 21620f0869bcSRick Macklem } 21630f0869bcSRick Macklem } 21640f0869bcSRick Macklem } 21650f0869bcSRick Macklem 21660f0869bcSRick Macklem /* Do the V4 root exports, as required. */ 21670f0869bcSRick Macklem grp = NULL; 21680f0869bcSRick Macklem if (v4root_ep != NULL) 21690f0869bcSRick Macklem grp = v4root_ep->ex_grphead; 21700f0869bcSRick Macklem v4root_phase = 2; 21710f0869bcSRick Macklem while (v4root_ep != NULL && grp != NULL) { 21720f0869bcSRick Macklem LOGDEBUG("v4root expath=%s", v4root_dirpath); 21730f0869bcSRick Macklem ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon, 21740f0869bcSRick Macklem v4root_dirpath, strlen(v4root_dirpath), &fs, 21750f0869bcSRick Macklem grp->gr_numsecflavors, grp->gr_secflavors); 21760f0869bcSRick Macklem if (ret != 0) { 21770f0869bcSRick Macklem v4root_phase = 0; 21780f0869bcSRick Macklem return (ret); 21790f0869bcSRick Macklem } 21800f0869bcSRick Macklem grp = grp->gr_next; 21810f0869bcSRick Macklem } 21820f0869bcSRick Macklem v4root_phase = 0; 21830f0869bcSRick Macklem free_v4rootexp(); 21840f0869bcSRick Macklem return (0); 21850f0869bcSRick Macklem } 21860f0869bcSRick Macklem 21870f0869bcSRick Macklem /* 21880f0869bcSRick Macklem * Compare old and current exportlist entries for the fsid and return 0 21890f0869bcSRick Macklem * if they are the same, 1 otherwise. 21900f0869bcSRick Macklem */ 21910f0869bcSRick Macklem static int 21920f0869bcSRick Macklem compare_export(struct exportlist *ep, struct exportlist *oep) 21930f0869bcSRick Macklem { 21940f0869bcSRick Macklem struct grouplist *grp, *ogrp; 21950f0869bcSRick Macklem 21960f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) 21970f0869bcSRick Macklem return (1); 21980f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET)) 21990f0869bcSRick Macklem return (1); 22000f0869bcSRick Macklem if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) || 22010f0869bcSRick Macklem (ep->ex_defdir == NULL && oep->ex_defdir != NULL)) 22020f0869bcSRick Macklem return (1); 22030f0869bcSRick Macklem if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) != 22040f0869bcSRick Macklem (oep->ex_defdir->dp_flag & DP_DEFSET)) 22050f0869bcSRick Macklem return (1); 22060f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors != 22070f0869bcSRick Macklem oep->ex_defnumsecflavors || ep->ex_defexflags != 22080f0869bcSRick Macklem oep->ex_defexflags || compare_cred(&ep->ex_defanon, 22090f0869bcSRick Macklem &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors, 22100f0869bcSRick Macklem oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0)) 22110f0869bcSRick Macklem return (1); 22120f0869bcSRick Macklem 22130f0869bcSRick Macklem /* Now, check all the groups. */ 22140f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) 22150f0869bcSRick Macklem ogrp->gr_flag = 0; 22160f0869bcSRick Macklem for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) { 22170f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = 22180f0869bcSRick Macklem ogrp->gr_next) 22190f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0 && 22200f0869bcSRick Macklem grp->gr_numsecflavors == ogrp->gr_numsecflavors && 22210f0869bcSRick Macklem grp->gr_exflags == ogrp->gr_exflags && 22220f0869bcSRick Macklem compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 && 22230f0869bcSRick Macklem compare_secflavor(grp->gr_secflavors, 22240f0869bcSRick Macklem ogrp->gr_secflavors, grp->gr_numsecflavors) == 0) 22250f0869bcSRick Macklem break; 22260f0869bcSRick Macklem if (ogrp != NULL) 22270f0869bcSRick Macklem ogrp->gr_flag |= GR_FND; 22280f0869bcSRick Macklem else 22290f0869bcSRick Macklem return (1); 22300f0869bcSRick Macklem } 22310f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) 22320f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0) 22330f0869bcSRick Macklem return (1); 22340f0869bcSRick Macklem return (0); 22350f0869bcSRick Macklem } 22360f0869bcSRick Macklem 22370f0869bcSRick Macklem /* 22380f0869bcSRick Macklem * This algorithm compares two arrays of "n" items. It returns 0 if they are 22390f0869bcSRick Macklem * the "same" and 1 otherwise. Although suboptimal, it is always safe to 22400f0869bcSRick Macklem * return 1, which makes compare_nmount_export() reload the exports entry. 22410f0869bcSRick Macklem * "same" refers to having the same set of values in the two arrays. 22420f0869bcSRick Macklem * The arrays are in no particular order and duplicates (multiple entries 22430f0869bcSRick Macklem * in an array with the same value) is allowed. 22440f0869bcSRick Macklem * The algorithm is inefficient, but the common case of indentical arrays is 22450f0869bcSRick Macklem * handled first and "n" is normally fairly small. 22460f0869bcSRick Macklem * Since the two functions need the same algorithm but for arrays of 22470f0869bcSRick Macklem * different types (gid_t vs int), this is done as a macro. 22480f0869bcSRick Macklem */ 22490f0869bcSRick Macklem #define COMPARE_ARRAYS(a1, a2, n) \ 22500f0869bcSRick Macklem do { \ 22510f0869bcSRick Macklem int fnd, fndarray[(n)], i, j; \ 22520f0869bcSRick Macklem /* Handle common case of identical arrays. */ \ 22530f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 22540f0869bcSRick Macklem if ((a1)[i] != (a2)[i]) \ 22550f0869bcSRick Macklem break; \ 22560f0869bcSRick Macklem if (i == (n)) \ 22570f0869bcSRick Macklem return (0); \ 22580f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 22590f0869bcSRick Macklem fndarray[i] = 0; \ 22600f0869bcSRick Macklem for (i = 0; i < (n); i++) { \ 22610f0869bcSRick Macklem fnd = 0; \ 22620f0869bcSRick Macklem for (j = 0; j < (n); j++) { \ 22630f0869bcSRick Macklem if ((a1)[i] == (a2)[j]) { \ 22640f0869bcSRick Macklem fndarray[j] = 1; \ 22650f0869bcSRick Macklem fnd = 1; \ 22660f0869bcSRick Macklem } \ 22670f0869bcSRick Macklem } \ 22680f0869bcSRick Macklem if (fnd == 0) \ 22690f0869bcSRick Macklem return (1); \ 22700f0869bcSRick Macklem } \ 22710f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 22720f0869bcSRick Macklem if (fndarray[i] == 0) \ 22730f0869bcSRick Macklem return (1); \ 22740f0869bcSRick Macklem return (0); \ 22750f0869bcSRick Macklem } while (0) 22760f0869bcSRick Macklem 22770f0869bcSRick Macklem /* 2278cc5efddeSRick Macklem * Compare two struct expcred's. Return 0 if the same and 1 otherwise. 22790f0869bcSRick Macklem */ 22800f0869bcSRick Macklem static int 2281cc5efddeSRick Macklem compare_cred(struct expcred *cr0, struct expcred *cr1) 22820f0869bcSRick Macklem { 22830f0869bcSRick Macklem 22840f0869bcSRick Macklem if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) 22850f0869bcSRick Macklem return (1); 22860f0869bcSRick Macklem 22870f0869bcSRick Macklem COMPARE_ARRAYS(cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups); 22880f0869bcSRick Macklem } 22890f0869bcSRick Macklem 22900f0869bcSRick Macklem /* 22910f0869bcSRick Macklem * Compare two lists of security flavors. Return 0 if the same and 1 otherwise. 22920f0869bcSRick Macklem */ 22930f0869bcSRick Macklem static int 22940f0869bcSRick Macklem compare_secflavor(int *sec1, int *sec2, int nsec) 22950f0869bcSRick Macklem { 22960f0869bcSRick Macklem 22970f0869bcSRick Macklem COMPARE_ARRAYS(sec1, sec2, nsec); 22980f0869bcSRick Macklem } 22990f0869bcSRick Macklem 23000f0869bcSRick Macklem /* 23013e08dc74SRick Macklem * Delete an exports entry. 23023e08dc74SRick Macklem */ 23033e08dc74SRick Macklem static void 23043e08dc74SRick Macklem delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) 23053e08dc74SRick Macklem { 23063e08dc74SRick Macklem struct xvfsconf vfc; 23073e08dc74SRick Macklem 23083e08dc74SRick Macklem if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 23093e08dc74SRick Macklem syslog(LOG_ERR, "getvfsbyname() failed for %s", 23103e08dc74SRick Macklem fsp->f_fstypename); 23113e08dc74SRick Macklem return; 23123e08dc74SRick Macklem } 23133e08dc74SRick Macklem 23143e08dc74SRick Macklem /* 23153e08dc74SRick Macklem * We do not need to delete "export" flag from 23163e08dc74SRick Macklem * filesystems that do not have it set. 23173e08dc74SRick Macklem */ 23183e08dc74SRick Macklem if (!(fsp->f_flags & MNT_EXPORTED)) 23193e08dc74SRick Macklem return; 23203e08dc74SRick Macklem /* 23213e08dc74SRick Macklem * Do not delete export for network filesystem by 23223e08dc74SRick Macklem * passing "export" arg to nmount(). 23233e08dc74SRick Macklem * It only makes sense to do this for local filesystems. 23243e08dc74SRick Macklem */ 23253e08dc74SRick Macklem if (vfc.vfc_flags & VFCF_NETWORK) 23263e08dc74SRick Macklem return; 23273e08dc74SRick Macklem 23283e08dc74SRick Macklem iov[1].iov_base = fsp->f_fstypename; 23293e08dc74SRick Macklem iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 23303e08dc74SRick Macklem iov[3].iov_base = fsp->f_mntonname; 23313e08dc74SRick Macklem iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 23323e08dc74SRick Macklem iov[5].iov_base = fsp->f_mntfromname; 23333e08dc74SRick Macklem iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 23343e08dc74SRick Macklem errmsg[0] = '\0'; 23353e08dc74SRick Macklem 23363e08dc74SRick Macklem /* 23373e08dc74SRick Macklem * EXDEV is returned when path exists but is not a 23383e08dc74SRick Macklem * mount point. May happens if raced with unmount. 23393e08dc74SRick Macklem */ 23403e08dc74SRick Macklem if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT && 23413e08dc74SRick Macklem errno != ENOTSUP && errno != EXDEV) { 23423e08dc74SRick Macklem syslog(LOG_ERR, 23433e08dc74SRick Macklem "can't delete exports for %s: %m %s", 23443e08dc74SRick Macklem fsp->f_mntonname, errmsg); 23453e08dc74SRick Macklem } 23463e08dc74SRick Macklem } 23473e08dc74SRick Macklem 23483e08dc74SRick Macklem /* 23498fae3551SRodney W. Grimes * Allocate an export list element 23508fae3551SRodney W. Grimes */ 235119c46d8cSEdward Tomasz Napierala static struct exportlist * 2352a7a7d96cSPhilippe Charnier get_exp(void) 23538fae3551SRodney W. Grimes { 23548fae3551SRodney W. Grimes struct exportlist *ep; 23558fae3551SRodney W. Grimes 235653750151SXin LI ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 23578fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) 23588fae3551SRodney W. Grimes out_of_mem(); 23598fae3551SRodney W. Grimes return (ep); 23608fae3551SRodney W. Grimes } 23618fae3551SRodney W. Grimes 23628fae3551SRodney W. Grimes /* 23638fae3551SRodney W. Grimes * Allocate a group list element 23648fae3551SRodney W. Grimes */ 236519c46d8cSEdward Tomasz Napierala static struct grouplist * 2366a7a7d96cSPhilippe Charnier get_grp(void) 23678fae3551SRodney W. Grimes { 23688fae3551SRodney W. Grimes struct grouplist *gp; 23698fae3551SRodney W. Grimes 237053750151SXin LI gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 23718fae3551SRodney W. Grimes if (gp == (struct grouplist *)NULL) 23728fae3551SRodney W. Grimes out_of_mem(); 23738fae3551SRodney W. Grimes return (gp); 23748fae3551SRodney W. Grimes } 23758fae3551SRodney W. Grimes 23768fae3551SRodney W. Grimes /* 23778fae3551SRodney W. Grimes * Clean up upon an error in get_exportlist(). 23788fae3551SRodney W. Grimes */ 237919c46d8cSEdward Tomasz Napierala static void 2380354fce28SConrad Meyer getexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason) 23818fae3551SRodney W. Grimes { 23828fae3551SRodney W. Grimes struct grouplist *tgrp; 23838fae3551SRodney W. Grimes 2384354fce28SConrad Meyer if (!(opt_flags & OP_QUIET)) { 2385354fce28SConrad Meyer if (reason != NULL) 2386354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s': %s", line, 2387354fce28SConrad Meyer reason); 2388354fce28SConrad Meyer else 2389354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s'", line); 2390354fce28SConrad Meyer } 23918fae3551SRodney W. Grimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 23928fae3551SRodney W. Grimes free_exp(ep); 23938fae3551SRodney W. Grimes while (grp) { 23948fae3551SRodney W. Grimes tgrp = grp; 23958fae3551SRodney W. Grimes grp = grp->gr_next; 23968fae3551SRodney W. Grimes free_grp(tgrp); 23978fae3551SRodney W. Grimes } 23988fae3551SRodney W. Grimes } 23998fae3551SRodney W. Grimes 24008fae3551SRodney W. Grimes /* 24018fae3551SRodney W. Grimes * Search the export list for a matching fs. 24028fae3551SRodney W. Grimes */ 240319c46d8cSEdward Tomasz Napierala static struct exportlist * 24041a9a992fSRick Macklem ex_search(fsid_t *fsid, struct exportlisthead *exhp) 24058fae3551SRodney W. Grimes { 24068fae3551SRodney W. Grimes struct exportlist *ep; 240746a6b5c4SRick Macklem uint32_t i; 24088fae3551SRodney W. Grimes 240946a6b5c4SRick Macklem i = EXPHASH(fsid); 241046a6b5c4SRick Macklem SLIST_FOREACH(ep, &exhp[i], entries) { 2411245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, fsid) == 0) 24128fae3551SRodney W. Grimes return (ep); 24138fae3551SRodney W. Grimes } 2414c9ac0f71SEmmanuel Vadot 24158fae3551SRodney W. Grimes return (ep); 24168fae3551SRodney W. Grimes } 24178fae3551SRodney W. Grimes 24188fae3551SRodney W. Grimes /* 24198fae3551SRodney W. Grimes * Add a directory path to the list. 24208fae3551SRodney W. Grimes */ 242119c46d8cSEdward Tomasz Napierala static char * 2422a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len) 24238fae3551SRodney W. Grimes { 24248fae3551SRodney W. Grimes struct dirlist *dp; 24258fae3551SRodney W. Grimes 242689b859e3SEmmanuel Vadot dp = malloc(sizeof (struct dirlist)); 242774853402SPhilippe Charnier if (dp == (struct dirlist *)NULL) 242874853402SPhilippe Charnier out_of_mem(); 24298fae3551SRodney W. Grimes dp->dp_left = *dpp; 24308fae3551SRodney W. Grimes dp->dp_right = (struct dirlist *)NULL; 24318fae3551SRodney W. Grimes dp->dp_flag = 0; 24328fae3551SRodney W. Grimes dp->dp_hosts = (struct hostlist *)NULL; 2433380a3fcdSEmmanuel Vadot dp->dp_dirp = strndup(cp, len); 2434380a3fcdSEmmanuel Vadot if (dp->dp_dirp == NULL) 2435380a3fcdSEmmanuel Vadot out_of_mem(); 24368fae3551SRodney W. Grimes *dpp = dp; 24378fae3551SRodney W. Grimes return (dp->dp_dirp); 24388fae3551SRodney W. Grimes } 24398fae3551SRodney W. Grimes 24408fae3551SRodney W. Grimes /* 24418fae3551SRodney W. Grimes * Hang the dir list element off the dirpath binary tree as required 24428fae3551SRodney W. Grimes * and update the entry for host. 24438fae3551SRodney W. Grimes */ 244419c46d8cSEdward Tomasz Napierala static void 2445a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 2446cc5efddeSRick Macklem int flags, struct expcred *anoncrp, uint64_t exflags) 24478fae3551SRodney W. Grimes { 24488fae3551SRodney W. Grimes struct hostlist *hp; 24498fae3551SRodney W. Grimes struct dirlist *dp2; 24508fae3551SRodney W. Grimes 2451a62dc406SDoug Rabson if (flags & OP_ALLDIRS) { 24528fae3551SRodney W. Grimes if (ep->ex_defdir) 24538fae3551SRodney W. Grimes free((caddr_t)dp); 24548fae3551SRodney W. Grimes else 24558fae3551SRodney W. Grimes ep->ex_defdir = dp; 2456a62dc406SDoug Rabson if (grp == (struct grouplist *)NULL) { 24570f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET; 24588fae3551SRodney W. Grimes ep->ex_defdir->dp_flag |= DP_DEFSET; 2459c3f86a25SRick Macklem /* Save the default security flavors list. */ 2460c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2461c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2462c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2463c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 2464cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp); 24650f0869bcSRick Macklem ep->ex_defexflags = exflags; 2466a62dc406SDoug Rabson } else while (grp) { 24678fae3551SRodney W. Grimes hp = get_ht(); 24688fae3551SRodney W. Grimes hp->ht_grp = grp; 24698fae3551SRodney W. Grimes hp->ht_next = ep->ex_defdir->dp_hosts; 24708fae3551SRodney W. Grimes ep->ex_defdir->dp_hosts = hp; 2471c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 2472c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2473c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2474c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2475c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 24768fae3551SRodney W. Grimes grp = grp->gr_next; 24778fae3551SRodney W. Grimes } 24788fae3551SRodney W. Grimes } else { 24798fae3551SRodney W. Grimes 24808fae3551SRodney W. Grimes /* 248174853402SPhilippe Charnier * Loop through the directories adding them to the tree. 24828fae3551SRodney W. Grimes */ 24838fae3551SRodney W. Grimes while (dp) { 24848fae3551SRodney W. Grimes dp2 = dp->dp_left; 24850f0869bcSRick Macklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp, 24860f0869bcSRick Macklem exflags); 24878fae3551SRodney W. Grimes dp = dp2; 24888fae3551SRodney W. Grimes } 24898fae3551SRodney W. Grimes } 24908fae3551SRodney W. Grimes } 24918fae3551SRodney W. Grimes 24928fae3551SRodney W. Grimes /* 24938fae3551SRodney W. Grimes * Traverse the binary tree either updating a node that is already there 24948fae3551SRodney W. Grimes * for the new directory or adding the new node. 24958fae3551SRodney W. Grimes */ 249619c46d8cSEdward Tomasz Napierala static void 2497a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2498cc5efddeSRick Macklem int flags, struct exportlist *ep, struct expcred *anoncrp, 2499cc5efddeSRick Macklem uint64_t exflags) 25008fae3551SRodney W. Grimes { 25018fae3551SRodney W. Grimes struct dirlist *dp; 25028fae3551SRodney W. Grimes struct hostlist *hp; 25038fae3551SRodney W. Grimes int cmp; 25048fae3551SRodney W. Grimes 25058fae3551SRodney W. Grimes dp = *dpp; 25068fae3551SRodney W. Grimes if (dp) { 25078fae3551SRodney W. Grimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 25088fae3551SRodney W. Grimes if (cmp > 0) { 25090f0869bcSRick Macklem add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp, 25100f0869bcSRick Macklem exflags); 25118fae3551SRodney W. Grimes return; 25128fae3551SRodney W. Grimes } else if (cmp < 0) { 25130f0869bcSRick Macklem add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp, 25140f0869bcSRick Macklem exflags); 25158fae3551SRodney W. Grimes return; 25168fae3551SRodney W. Grimes } else 25178fae3551SRodney W. Grimes free((caddr_t)newdp); 25188fae3551SRodney W. Grimes } else { 25198fae3551SRodney W. Grimes dp = newdp; 25208fae3551SRodney W. Grimes dp->dp_left = (struct dirlist *)NULL; 25218fae3551SRodney W. Grimes *dpp = dp; 25228fae3551SRodney W. Grimes } 25238fae3551SRodney W. Grimes if (grp) { 25248fae3551SRodney W. Grimes 25258fae3551SRodney W. Grimes /* 25268fae3551SRodney W. Grimes * Hang all of the host(s) off of the directory point. 25278fae3551SRodney W. Grimes */ 25288fae3551SRodney W. Grimes do { 25298fae3551SRodney W. Grimes hp = get_ht(); 25308fae3551SRodney W. Grimes hp->ht_grp = grp; 25318fae3551SRodney W. Grimes hp->ht_next = dp->dp_hosts; 25328fae3551SRodney W. Grimes dp->dp_hosts = hp; 2533c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 2534c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2535c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2536c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2537c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 25388fae3551SRodney W. Grimes grp = grp->gr_next; 25398fae3551SRodney W. Grimes } while (grp); 2540a62dc406SDoug Rabson } else { 25410f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET; 25428fae3551SRodney W. Grimes dp->dp_flag |= DP_DEFSET; 2543c3f86a25SRick Macklem /* Save the default security flavors list. */ 2544c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2545c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2546c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2547c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 2548cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp); 25490f0869bcSRick Macklem ep->ex_defexflags = exflags; 2550a62dc406SDoug Rabson } 25518fae3551SRodney W. Grimes } 25528fae3551SRodney W. Grimes 25538fae3551SRodney W. Grimes /* 25548fae3551SRodney W. Grimes * Search for a dirpath on the export point. 25558fae3551SRodney W. Grimes */ 255619c46d8cSEdward Tomasz Napierala static struct dirlist * 2557a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp) 25588fae3551SRodney W. Grimes { 25598fae3551SRodney W. Grimes int cmp; 25608fae3551SRodney W. Grimes 25618fae3551SRodney W. Grimes if (dp) { 25628360efbdSAlfred Perlstein cmp = strcmp(dp->dp_dirp, dirp); 25638fae3551SRodney W. Grimes if (cmp > 0) 25648360efbdSAlfred Perlstein return (dirp_search(dp->dp_left, dirp)); 25658fae3551SRodney W. Grimes else if (cmp < 0) 25668360efbdSAlfred Perlstein return (dirp_search(dp->dp_right, dirp)); 25678fae3551SRodney W. Grimes else 25688fae3551SRodney W. Grimes return (dp); 25698fae3551SRodney W. Grimes } 25708fae3551SRodney W. Grimes return (dp); 25718fae3551SRodney W. Grimes } 25728fae3551SRodney W. Grimes 25738fae3551SRodney W. Grimes /* 25748fae3551SRodney W. Grimes * Scan for a host match in a directory tree. 25758fae3551SRodney W. Grimes */ 257619c46d8cSEdward Tomasz Napierala static int 2577a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2578c3f86a25SRick Macklem int *hostsetp, int *numsecflavors, int **secflavorsp) 25798fae3551SRodney W. Grimes { 25808fae3551SRodney W. Grimes struct hostlist *hp; 25818fae3551SRodney W. Grimes struct grouplist *grp; 25828360efbdSAlfred Perlstein struct addrinfo *ai; 25838fae3551SRodney W. Grimes 25848fae3551SRodney W. Grimes if (dp) { 25858fae3551SRodney W. Grimes if (dp->dp_flag & DP_DEFSET) 2586a62dc406SDoug Rabson *defsetp = dp->dp_flag; 25878fae3551SRodney W. Grimes hp = dp->dp_hosts; 25888fae3551SRodney W. Grimes while (hp) { 25898fae3551SRodney W. Grimes grp = hp->ht_grp; 25908fae3551SRodney W. Grimes switch (grp->gr_type) { 25918fae3551SRodney W. Grimes case GT_HOST: 25928360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 25938360efbdSAlfred Perlstein for (; ai; ai = ai->ai_next) { 259460caaee2SIan Dowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 25958360efbdSAlfred Perlstein *hostsetp = 25968360efbdSAlfred Perlstein (hp->ht_flag | DP_HOSTSET); 2597c3f86a25SRick Macklem if (numsecflavors != NULL) { 2598c3f86a25SRick Macklem *numsecflavors = 2599c3f86a25SRick Macklem grp->gr_numsecflavors; 2600c3f86a25SRick Macklem *secflavorsp = 2601c3f86a25SRick Macklem grp->gr_secflavors; 2602c3f86a25SRick Macklem } 26038fae3551SRodney W. Grimes return (1); 2604a62dc406SDoug Rabson } 26058fae3551SRodney W. Grimes } 26068fae3551SRodney W. Grimes break; 26078fae3551SRodney W. Grimes case GT_NET: 260860caaee2SIan Dowse if (!sacmp(saddr, (struct sockaddr *) 260960caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_net, 261060caaee2SIan Dowse (struct sockaddr *) 261160caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_mask)) { 2612a62dc406SDoug Rabson *hostsetp = (hp->ht_flag | DP_HOSTSET); 2613c3f86a25SRick Macklem if (numsecflavors != NULL) { 2614c3f86a25SRick Macklem *numsecflavors = 2615c3f86a25SRick Macklem grp->gr_numsecflavors; 2616c3f86a25SRick Macklem *secflavorsp = 2617c3f86a25SRick Macklem grp->gr_secflavors; 2618c3f86a25SRick Macklem } 26198fae3551SRodney W. Grimes return (1); 2620a62dc406SDoug Rabson } 26218fae3551SRodney W. Grimes break; 262260caaee2SIan Dowse } 26238fae3551SRodney W. Grimes hp = hp->ht_next; 26248fae3551SRodney W. Grimes } 26258fae3551SRodney W. Grimes } 26268fae3551SRodney W. Grimes return (0); 26278fae3551SRodney W. Grimes } 26288fae3551SRodney W. Grimes 26298fae3551SRodney W. Grimes /* 26308fae3551SRodney W. Grimes * Scan tree for a host that matches the address. 26318fae3551SRodney W. Grimes */ 263219c46d8cSEdward Tomasz Napierala static int 2633a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr) 26348fae3551SRodney W. Grimes { 2635a62dc406SDoug Rabson int defset, hostset; 26368fae3551SRodney W. Grimes 26378fae3551SRodney W. Grimes if (dp) { 26388fae3551SRodney W. Grimes if (scan_tree(dp->dp_left, saddr)) 26398fae3551SRodney W. Grimes return (1); 2640c3f86a25SRick Macklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 26418fae3551SRodney W. Grimes return (1); 26428fae3551SRodney W. Grimes if (scan_tree(dp->dp_right, saddr)) 26438fae3551SRodney W. Grimes return (1); 26448fae3551SRodney W. Grimes } 26458fae3551SRodney W. Grimes return (0); 26468fae3551SRodney W. Grimes } 26478fae3551SRodney W. Grimes 26488fae3551SRodney W. Grimes /* 26498fae3551SRodney W. Grimes * Traverse the dirlist tree and free it up. 26508fae3551SRodney W. Grimes */ 265119c46d8cSEdward Tomasz Napierala static void 2652a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp) 26538fae3551SRodney W. Grimes { 26548fae3551SRodney W. Grimes 26558fae3551SRodney W. Grimes if (dp) { 26568fae3551SRodney W. Grimes free_dir(dp->dp_left); 26578fae3551SRodney W. Grimes free_dir(dp->dp_right); 26588fae3551SRodney W. Grimes free_host(dp->dp_hosts); 265992e73cccSEmmanuel Vadot free(dp->dp_dirp); 266092e73cccSEmmanuel Vadot free(dp); 26618fae3551SRodney W. Grimes } 26628fae3551SRodney W. Grimes } 26638fae3551SRodney W. Grimes 26648fae3551SRodney W. Grimes /* 2665a9148abdSDoug Rabson * Parse a colon separated list of security flavors 2666a9148abdSDoug Rabson */ 266719c46d8cSEdward Tomasz Napierala static int 2668a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep) 2669a9148abdSDoug Rabson { 2670a9148abdSDoug Rabson char *cp, savedc; 2671a9148abdSDoug Rabson int flavor; 2672a9148abdSDoug Rabson 2673a9148abdSDoug Rabson ep->ex_numsecflavors = 0; 2674a9148abdSDoug Rabson for (;;) { 2675a9148abdSDoug Rabson cp = strchr(seclist, ':'); 2676a9148abdSDoug Rabson if (cp) { 2677a9148abdSDoug Rabson savedc = *cp; 2678a9148abdSDoug Rabson *cp = '\0'; 2679a9148abdSDoug Rabson } 2680a9148abdSDoug Rabson 2681a9148abdSDoug Rabson if (!strcmp(seclist, "sys")) 2682a9148abdSDoug Rabson flavor = AUTH_SYS; 2683a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5")) 2684a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5; 2685a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5i")) 2686a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5I; 2687a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5p")) 2688a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5P; 2689a9148abdSDoug Rabson else { 2690a9148abdSDoug Rabson if (cp) 2691a9148abdSDoug Rabson *cp = savedc; 2692a9148abdSDoug Rabson syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2693a9148abdSDoug Rabson return (1); 2694a9148abdSDoug Rabson } 2695a9148abdSDoug Rabson if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2696a9148abdSDoug Rabson if (cp) 2697a9148abdSDoug Rabson *cp = savedc; 2698a9148abdSDoug Rabson syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2699a9148abdSDoug Rabson return (1); 2700a9148abdSDoug Rabson } 2701a9148abdSDoug Rabson ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2702a9148abdSDoug Rabson ep->ex_numsecflavors++; 2703a9148abdSDoug Rabson if (cp) { 2704a9148abdSDoug Rabson *cp = savedc; 2705a9148abdSDoug Rabson seclist = cp + 1; 2706a9148abdSDoug Rabson } else { 2707a9148abdSDoug Rabson break; 2708a9148abdSDoug Rabson } 2709a9148abdSDoug Rabson } 2710a9148abdSDoug Rabson return (0); 2711a9148abdSDoug Rabson } 2712a9148abdSDoug Rabson 2713a9148abdSDoug Rabson /* 27148fae3551SRodney W. Grimes * Parse the option string and update fields. 27158fae3551SRodney W. Grimes * Option arguments may either be -<option>=<value> or 27168fae3551SRodney W. Grimes * -<option> <value> 27178fae3551SRodney W. Grimes */ 271819c46d8cSEdward Tomasz Napierala static int 2719a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2720cc5efddeSRick Macklem int *has_hostp, uint64_t *exflagsp, struct expcred *cr) 27218fae3551SRodney W. Grimes { 27228fae3551SRodney W. Grimes char *cpoptarg, *cpoptend; 27238fae3551SRodney W. Grimes char *cp, *endcp, *cpopt, savedc, savedc2; 27248fae3551SRodney W. Grimes int allflag, usedarg; 27258fae3551SRodney W. Grimes 2726cb479b11SAlfred Perlstein savedc2 = '\0'; 27278fae3551SRodney W. Grimes cpopt = *cpp; 27288fae3551SRodney W. Grimes cpopt++; 27298fae3551SRodney W. Grimes cp = *endcpp; 27308fae3551SRodney W. Grimes savedc = *cp; 27318fae3551SRodney W. Grimes *cp = '\0'; 27328fae3551SRodney W. Grimes while (cpopt && *cpopt) { 27338fae3551SRodney W. Grimes allflag = 1; 27348fae3551SRodney W. Grimes usedarg = -2; 273574853402SPhilippe Charnier if ((cpoptend = strchr(cpopt, ','))) { 27368fae3551SRodney W. Grimes *cpoptend++ = '\0'; 273774853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 27388fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 27398fae3551SRodney W. Grimes } else { 274074853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 27418fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 27428fae3551SRodney W. Grimes else { 27438fae3551SRodney W. Grimes *cp = savedc; 27448fae3551SRodney W. Grimes nextfield(&cp, &endcp); 27458fae3551SRodney W. Grimes **endcpp = '\0'; 27468fae3551SRodney W. Grimes if (endcp > cp && *cp != '-') { 27478fae3551SRodney W. Grimes cpoptarg = cp; 27488fae3551SRodney W. Grimes savedc2 = *endcp; 27498fae3551SRodney W. Grimes *endcp = '\0'; 27508fae3551SRodney W. Grimes usedarg = 0; 27518fae3551SRodney W. Grimes } 27528fae3551SRodney W. Grimes } 27538fae3551SRodney W. Grimes } 27548fae3551SRodney W. Grimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 27558fae3551SRodney W. Grimes *exflagsp |= MNT_EXRDONLY; 27568fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 27578fae3551SRodney W. Grimes !(allflag = strcmp(cpopt, "mapall")) || 27588fae3551SRodney W. Grimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 27598fae3551SRodney W. Grimes usedarg++; 27608fae3551SRodney W. Grimes parsecred(cpoptarg, cr); 27618fae3551SRodney W. Grimes if (allflag == 0) { 27628fae3551SRodney W. Grimes *exflagsp |= MNT_EXPORTANON; 27638fae3551SRodney W. Grimes opt_flags |= OP_MAPALL; 27648fae3551SRodney W. Grimes } else 27658fae3551SRodney W. Grimes opt_flags |= OP_MAPROOT; 27668fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 27678fae3551SRodney W. Grimes !strcmp(cpopt, "m"))) { 27688fae3551SRodney W. Grimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 276974853402SPhilippe Charnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 27708fae3551SRodney W. Grimes return (1); 27718fae3551SRodney W. Grimes } 27728fae3551SRodney W. Grimes usedarg++; 27738fae3551SRodney W. Grimes opt_flags |= OP_MASK; 27748fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 27758fae3551SRodney W. Grimes !strcmp(cpopt, "n"))) { 27768360efbdSAlfred Perlstein if (strchr(cpoptarg, '/') != NULL) { 27778360efbdSAlfred Perlstein if (debug) 27788360efbdSAlfred Perlstein fprintf(stderr, "setting OP_MASKLEN\n"); 27798360efbdSAlfred Perlstein opt_flags |= OP_MASKLEN; 27808360efbdSAlfred Perlstein } 27818fae3551SRodney W. Grimes if (grp->gr_type != GT_NULL) { 278274853402SPhilippe Charnier syslog(LOG_ERR, "network/host conflict"); 27838fae3551SRodney W. Grimes return (1); 27848fae3551SRodney W. Grimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 278574853402SPhilippe Charnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 27868fae3551SRodney W. Grimes return (1); 27878fae3551SRodney W. Grimes } 27888fae3551SRodney W. Grimes grp->gr_type = GT_NET; 27898fae3551SRodney W. Grimes *has_hostp = 1; 27908fae3551SRodney W. Grimes usedarg++; 27918fae3551SRodney W. Grimes opt_flags |= OP_NET; 27928fae3551SRodney W. Grimes } else if (!strcmp(cpopt, "alldirs")) { 27938fae3551SRodney W. Grimes opt_flags |= OP_ALLDIRS; 2794cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "public")) { 2795cb3923e0SDoug Rabson *exflagsp |= MNT_EXPUBLIC; 2796cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "webnfs")) { 2797cb3923e0SDoug Rabson *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2798cb3923e0SDoug Rabson opt_flags |= OP_MAPALL; 2799cb3923e0SDoug Rabson } else if (cpoptarg && !strcmp(cpopt, "index")) { 2800cb3923e0SDoug Rabson ep->ex_indexfile = strdup(cpoptarg); 2801288fa14aSJoerg Wunsch } else if (!strcmp(cpopt, "quiet")) { 2802288fa14aSJoerg Wunsch opt_flags |= OP_QUIET; 2803dcdc127bSSergey Kandaurov } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2804a9148abdSDoug Rabson if (parsesec(cpoptarg, ep)) 2805a9148abdSDoug Rabson return (1); 2806a9148abdSDoug Rabson opt_flags |= OP_SEC; 2807a9148abdSDoug Rabson usedarg++; 2808813837baSRick Macklem } else if (!strcmp(cpopt, "tls")) { 2809813837baSRick Macklem *exflagsp |= MNT_EXTLS; 2810813837baSRick Macklem } else if (!strcmp(cpopt, "tlscert")) { 2811813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT); 2812813837baSRick Macklem } else if (!strcmp(cpopt, "tlscertuser")) { 2813813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT | 2814813837baSRick Macklem MNT_EXTLSCERTUSER); 28158fae3551SRodney W. Grimes } else { 281674853402SPhilippe Charnier syslog(LOG_ERR, "bad opt %s", cpopt); 28178fae3551SRodney W. Grimes return (1); 28188fae3551SRodney W. Grimes } 28198fae3551SRodney W. Grimes if (usedarg >= 0) { 28208fae3551SRodney W. Grimes *endcp = savedc2; 28218fae3551SRodney W. Grimes **endcpp = savedc; 28228fae3551SRodney W. Grimes if (usedarg > 0) { 28238fae3551SRodney W. Grimes *cpp = cp; 28248fae3551SRodney W. Grimes *endcpp = endcp; 28258fae3551SRodney W. Grimes } 28268fae3551SRodney W. Grimes return (0); 28278fae3551SRodney W. Grimes } 28288fae3551SRodney W. Grimes cpopt = cpoptend; 28298fae3551SRodney W. Grimes } 28308fae3551SRodney W. Grimes **endcpp = savedc; 28318fae3551SRodney W. Grimes return (0); 28328fae3551SRodney W. Grimes } 28338fae3551SRodney W. Grimes 28348fae3551SRodney W. Grimes /* 28358fae3551SRodney W. Grimes * Translate a character string to the corresponding list of network 28368fae3551SRodney W. Grimes * addresses for a hostname. 28378fae3551SRodney W. Grimes */ 283819c46d8cSEdward Tomasz Napierala static int 2839a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 28408fae3551SRodney W. Grimes { 28418b5a6d67SBill Paul struct grouplist *checkgrp; 284201709abfSIan Dowse struct addrinfo *ai, *tai, hints; 28438360efbdSAlfred Perlstein int ecode; 28448360efbdSAlfred Perlstein char host[NI_MAXHOST]; 28458fae3551SRodney W. Grimes 28468360efbdSAlfred Perlstein if (grp->gr_type != GT_NULL) { 28478360efbdSAlfred Perlstein syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 28488fae3551SRodney W. Grimes return (1); 28498fae3551SRodney W. Grimes } 28508360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 28518360efbdSAlfred Perlstein hints.ai_flags = AI_CANONNAME; 28528360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 28538360efbdSAlfred Perlstein ecode = getaddrinfo(cp, NULL, &hints, &ai); 28548360efbdSAlfred Perlstein if (ecode != 0) { 285501709abfSIan Dowse syslog(LOG_ERR,"can't get address info for host %s", cp); 28568360efbdSAlfred Perlstein return 1; 28578fae3551SRodney W. Grimes } 28588360efbdSAlfred Perlstein grp->gr_ptr.gt_addrinfo = ai; 28598360efbdSAlfred Perlstein while (ai != NULL) { 28608360efbdSAlfred Perlstein if (ai->ai_canonname == NULL) { 28618360efbdSAlfred Perlstein if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 28624f101318SHajimu UMEMOTO sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 28638360efbdSAlfred Perlstein strlcpy(host, "?", sizeof(host)); 28648360efbdSAlfred Perlstein ai->ai_canonname = strdup(host); 28658360efbdSAlfred Perlstein ai->ai_flags |= AI_CANONNAME; 28666d359f31SIan Dowse } 28678fae3551SRodney W. Grimes if (debug) 286801709abfSIan Dowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 286901709abfSIan Dowse /* 287001709abfSIan Dowse * Sanity check: make sure we don't already have an entry 287101709abfSIan Dowse * for this host in the grouplist. 287201709abfSIan Dowse */ 287301709abfSIan Dowse for (checkgrp = tgrp; checkgrp != NULL; 287401709abfSIan Dowse checkgrp = checkgrp->gr_next) { 287501709abfSIan Dowse if (checkgrp->gr_type != GT_HOST) 287601709abfSIan Dowse continue; 287701709abfSIan Dowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 287801709abfSIan Dowse tai = tai->ai_next) { 287960caaee2SIan Dowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 288001709abfSIan Dowse continue; 288101709abfSIan Dowse if (debug) 288201709abfSIan Dowse fprintf(stderr, 288301709abfSIan Dowse "ignoring duplicate host %s\n", 288401709abfSIan Dowse ai->ai_canonname); 288501709abfSIan Dowse grp->gr_type = GT_IGNORE; 288601709abfSIan Dowse return (0); 288701709abfSIan Dowse } 288801709abfSIan Dowse } 28898360efbdSAlfred Perlstein ai = ai->ai_next; 28908360efbdSAlfred Perlstein } 289101709abfSIan Dowse grp->gr_type = GT_HOST; 28928fae3551SRodney W. Grimes return (0); 28938fae3551SRodney W. Grimes } 28948fae3551SRodney W. Grimes 28958fae3551SRodney W. Grimes /* 28968fae3551SRodney W. Grimes * Free up an exports list component 28978fae3551SRodney W. Grimes */ 289819c46d8cSEdward Tomasz Napierala static void 2899a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep) 29008fae3551SRodney W. Grimes { 2901711d44eeSRick Macklem struct grouplist *grp, *tgrp; 29028fae3551SRodney W. Grimes 29038fae3551SRodney W. Grimes if (ep->ex_defdir) { 29048fae3551SRodney W. Grimes free_host(ep->ex_defdir->dp_hosts); 29058fae3551SRodney W. Grimes free((caddr_t)ep->ex_defdir); 29068fae3551SRodney W. Grimes } 29078fae3551SRodney W. Grimes if (ep->ex_fsdir) 29088fae3551SRodney W. Grimes free(ep->ex_fsdir); 2909cb3923e0SDoug Rabson if (ep->ex_indexfile) 2910cb3923e0SDoug Rabson free(ep->ex_indexfile); 29118fae3551SRodney W. Grimes free_dir(ep->ex_dirl); 2912711d44eeSRick Macklem grp = ep->ex_grphead; 2913711d44eeSRick Macklem while (grp) { 2914711d44eeSRick Macklem tgrp = grp; 2915711d44eeSRick Macklem grp = grp->gr_next; 2916711d44eeSRick Macklem free_grp(tgrp); 2917711d44eeSRick Macklem } 2918*2ffad162SRick Macklem if (ep->ex_defanon.cr_groups != ep->ex_defanon.cr_smallgrps) 2919*2ffad162SRick Macklem free(ep->ex_defanon.cr_groups); 29208fae3551SRodney W. Grimes free((caddr_t)ep); 29218fae3551SRodney W. Grimes } 29228fae3551SRodney W. Grimes 29238fae3551SRodney W. Grimes /* 29240f0869bcSRick Macklem * Free up the v4root exports. 29250f0869bcSRick Macklem */ 29260f0869bcSRick Macklem static void 29270f0869bcSRick Macklem free_v4rootexp(void) 29280f0869bcSRick Macklem { 29290f0869bcSRick Macklem 29300f0869bcSRick Macklem if (v4root_ep != NULL) { 29310f0869bcSRick Macklem free_exp(v4root_ep); 29320f0869bcSRick Macklem v4root_ep = NULL; 29330f0869bcSRick Macklem } 29340f0869bcSRick Macklem } 29350f0869bcSRick Macklem 29360f0869bcSRick Macklem /* 29378fae3551SRodney W. Grimes * Free hosts. 29388fae3551SRodney W. Grimes */ 293919c46d8cSEdward Tomasz Napierala static void 2940a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp) 29418fae3551SRodney W. Grimes { 29428fae3551SRodney W. Grimes struct hostlist *hp2; 29438fae3551SRodney W. Grimes 29448fae3551SRodney W. Grimes while (hp) { 29458fae3551SRodney W. Grimes hp2 = hp; 29468fae3551SRodney W. Grimes hp = hp->ht_next; 29478fae3551SRodney W. Grimes free((caddr_t)hp2); 29488fae3551SRodney W. Grimes } 29498fae3551SRodney W. Grimes } 29508fae3551SRodney W. Grimes 295119c46d8cSEdward Tomasz Napierala static struct hostlist * 2952a7a7d96cSPhilippe Charnier get_ht(void) 29538fae3551SRodney W. Grimes { 29548fae3551SRodney W. Grimes struct hostlist *hp; 29558fae3551SRodney W. Grimes 29568fae3551SRodney W. Grimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 29578fae3551SRodney W. Grimes if (hp == (struct hostlist *)NULL) 29588fae3551SRodney W. Grimes out_of_mem(); 29598fae3551SRodney W. Grimes hp->ht_next = (struct hostlist *)NULL; 2960a62dc406SDoug Rabson hp->ht_flag = 0; 29618fae3551SRodney W. Grimes return (hp); 29628fae3551SRodney W. Grimes } 29638fae3551SRodney W. Grimes 29648fae3551SRodney W. Grimes /* 29658fae3551SRodney W. Grimes * Out of memory, fatal 29668fae3551SRodney W. Grimes */ 296719c46d8cSEdward Tomasz Napierala static void 2968a7a7d96cSPhilippe Charnier out_of_mem(void) 29698fae3551SRodney W. Grimes { 29708fae3551SRodney W. Grimes 297174853402SPhilippe Charnier syslog(LOG_ERR, "out of memory"); 29728fae3551SRodney W. Grimes exit(2); 29738fae3551SRodney W. Grimes } 29748fae3551SRodney W. Grimes 29758fae3551SRodney W. Grimes /* 29760f0869bcSRick Macklem * Call do_mount() from the struct exportlist, for each case needed. 29770f0869bcSRick Macklem */ 29780f0869bcSRick Macklem static int 29790f0869bcSRick Macklem do_export_mount(struct exportlist *ep, struct statfs *fsp) 29800f0869bcSRick Macklem { 29810f0869bcSRick Macklem struct grouplist *grp, defgrp; 29820f0869bcSRick Macklem int ret; 29830f0869bcSRick Macklem size_t dirlen; 29840f0869bcSRick Macklem 29850f0869bcSRick Macklem LOGDEBUG("do_export_mount=%s", ep->ex_fsdir); 29860f0869bcSRick Macklem dirlen = strlen(ep->ex_fsdir); 29870f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0) { 29880f0869bcSRick Macklem defgrp.gr_type = GT_DEFAULT; 29890f0869bcSRick Macklem defgrp.gr_next = NULL; 29900f0869bcSRick Macklem /* We have an entry for all other hosts/nets. */ 2991cc5efddeSRick Macklem LOGDEBUG("ex_defexflags=0x%jx", (uintmax_t)ep->ex_defexflags); 29920f0869bcSRick Macklem ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, 29930f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors, 29940f0869bcSRick Macklem ep->ex_defsecflavors); 29950f0869bcSRick Macklem if (ret != 0) 29960f0869bcSRick Macklem return (ret); 29970f0869bcSRick Macklem } 29980f0869bcSRick Macklem 29990f0869bcSRick Macklem /* Do a mount for each group. */ 30000f0869bcSRick Macklem grp = ep->ex_grphead; 30010f0869bcSRick Macklem while (grp != NULL) { 3002cc5efddeSRick Macklem LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%jx", 3003cc5efddeSRick Macklem grp->gr_type, (uintmax_t)grp->gr_exflags); 30040f0869bcSRick Macklem ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, 30050f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors, 30060f0869bcSRick Macklem grp->gr_secflavors); 30070f0869bcSRick Macklem if (ret != 0) 30080f0869bcSRick Macklem return (ret); 30090f0869bcSRick Macklem grp = grp->gr_next; 30100f0869bcSRick Macklem } 30110f0869bcSRick Macklem return (0); 30120f0869bcSRick Macklem } 30130f0869bcSRick Macklem 30140f0869bcSRick Macklem /* 30156a09faf2SCraig Rodrigues * Do the nmount() syscall with the update flag to push the export info into 30168fae3551SRodney W. Grimes * the kernel. 30178fae3551SRodney W. Grimes */ 301819c46d8cSEdward Tomasz Napierala static int 3019cc5efddeSRick Macklem do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags, 3020cc5efddeSRick Macklem struct expcred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, 30210f0869bcSRick Macklem int numsecflavors, int *secflavors) 30228fae3551SRodney W. Grimes { 3023f93caef2SIan Dowse struct statfs fsb1; 30248360efbdSAlfred Perlstein struct addrinfo *ai; 302579b86807SEdward Tomasz Napierala struct export_args *eap; 30266a09faf2SCraig Rodrigues char errmsg[255]; 30276a09faf2SCraig Rodrigues char *cp; 30288fae3551SRodney W. Grimes int done; 30296a09faf2SCraig Rodrigues char savedc; 30306a09faf2SCraig Rodrigues struct iovec *iov; 3031a9148abdSDoug Rabson int i, iovlen; 30326a09faf2SCraig Rodrigues int ret; 3033bcc1d071SRick Macklem struct nfsex_args nfsea; 3034bcc1d071SRick Macklem 3035bcc1d071SRick Macklem eap = &nfsea.export; 30368fae3551SRodney W. Grimes 30376a09faf2SCraig Rodrigues cp = NULL; 30386a09faf2SCraig Rodrigues savedc = '\0'; 30396a09faf2SCraig Rodrigues iov = NULL; 30406a09faf2SCraig Rodrigues iovlen = 0; 30416a09faf2SCraig Rodrigues ret = 0; 304260caaee2SIan Dowse 3043bcc1d071SRick Macklem bzero(eap, sizeof (struct export_args)); 30446a09faf2SCraig Rodrigues bzero(errmsg, sizeof(errmsg)); 3045bcc1d071SRick Macklem eap->ex_flags = exflags; 3046cc5efddeSRick Macklem eap->ex_uid = anoncrp->cr_uid; 3047cc5efddeSRick Macklem eap->ex_ngroups = anoncrp->cr_ngroups; 3048cc5efddeSRick Macklem if (eap->ex_ngroups > 0) { 3049cc5efddeSRick Macklem eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t)); 3050cc5efddeSRick Macklem memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups * 3051cc5efddeSRick Macklem sizeof(gid_t)); 3052cc5efddeSRick Macklem } 3053cc5efddeSRick Macklem LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags); 3054bcc1d071SRick Macklem eap->ex_indexfile = ep->ex_indexfile; 30556d359f31SIan Dowse if (grp->gr_type == GT_HOST) 30568360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 30576d359f31SIan Dowse else 30586d359f31SIan Dowse ai = NULL; 30590f0869bcSRick Macklem eap->ex_numsecflavors = numsecflavors; 30600f0869bcSRick Macklem LOGDEBUG("do_mount numsec=%d", numsecflavors); 3061bcc1d071SRick Macklem for (i = 0; i < eap->ex_numsecflavors; i++) 30620f0869bcSRick Macklem eap->ex_secflavors[i] = secflavors[i]; 3063bcc1d071SRick Macklem if (eap->ex_numsecflavors == 0) { 3064bcc1d071SRick Macklem eap->ex_numsecflavors = 1; 3065bcc1d071SRick Macklem eap->ex_secflavors[0] = AUTH_SYS; 3066a9148abdSDoug Rabson } 30678fae3551SRodney W. Grimes done = FALSE; 30686a09faf2SCraig Rodrigues 3069bcc1d071SRick Macklem if (v4root_phase == 0) { 30706a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", NULL, 0); 30716a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", NULL, 0); 30726a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "from", NULL, 0); 30736a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "update", NULL, 0); 3074bcc1d071SRick Macklem build_iovec(&iov, &iovlen, "export", eap, 3075bcc1d071SRick Macklem sizeof (struct export_args)); 30766a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 3077bcc1d071SRick Macklem } 30786a09faf2SCraig Rodrigues 30798fae3551SRodney W. Grimes while (!done) { 30808fae3551SRodney W. Grimes switch (grp->gr_type) { 30818fae3551SRodney W. Grimes case GT_HOST: 30826d359f31SIan Dowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 30838360efbdSAlfred Perlstein goto skip; 3084bcc1d071SRick Macklem eap->ex_addr = ai->ai_addr; 3085bcc1d071SRick Macklem eap->ex_addrlen = ai->ai_addrlen; 3086bcc1d071SRick Macklem eap->ex_masklen = 0; 30878fae3551SRodney W. Grimes break; 30888fae3551SRodney W. Grimes case GT_NET: 308960caaee2SIan Dowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 30908360efbdSAlfred Perlstein have_v6 == 0) 30918360efbdSAlfred Perlstein goto skip; 3092bcc1d071SRick Macklem eap->ex_addr = 309360caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 3094bcc1d071SRick Macklem eap->ex_addrlen = 30956a09faf2SCraig Rodrigues ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 3096bcc1d071SRick Macklem eap->ex_mask = 309760caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 3098bcc1d071SRick Macklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 30998fae3551SRodney W. Grimes break; 31006d359f31SIan Dowse case GT_DEFAULT: 3101bcc1d071SRick Macklem eap->ex_addr = NULL; 3102bcc1d071SRick Macklem eap->ex_addrlen = 0; 3103bcc1d071SRick Macklem eap->ex_mask = NULL; 3104bcc1d071SRick Macklem eap->ex_masklen = 0; 31056d359f31SIan Dowse break; 31068b5a6d67SBill Paul case GT_IGNORE: 31076a09faf2SCraig Rodrigues ret = 0; 31086a09faf2SCraig Rodrigues goto error_exit; 31098b5a6d67SBill Paul break; 31108fae3551SRodney W. Grimes default: 311174853402SPhilippe Charnier syslog(LOG_ERR, "bad grouptype"); 31128fae3551SRodney W. Grimes if (cp) 31138fae3551SRodney W. Grimes *cp = savedc; 31146a09faf2SCraig Rodrigues ret = 1; 31156a09faf2SCraig Rodrigues goto error_exit; 311680c7cc1cSPedro F. Giffuni } 31178fae3551SRodney W. Grimes 31188fae3551SRodney W. Grimes /* 3119bcc1d071SRick Macklem * For V4:, use the nfssvc() syscall, instead of mount(). 3120bcc1d071SRick Macklem */ 3121bcc1d071SRick Macklem if (v4root_phase == 2) { 3122bcc1d071SRick Macklem nfsea.fspec = v4root_dirpath; 3123cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, 3124cc5efddeSRick Macklem (caddr_t)&nfsea) < 0) { 3125bcc1d071SRick Macklem syslog(LOG_ERR, "Exporting V4: failed"); 3126cc5efddeSRick Macklem ret = 2; 3127cc5efddeSRick Macklem goto error_exit; 3128bcc1d071SRick Macklem } 3129bcc1d071SRick Macklem } else { 3130bcc1d071SRick Macklem /* 31318fae3551SRodney W. Grimes * XXX: 3132bcc1d071SRick Macklem * Maybe I should just use the fsb->f_mntonname path 3133bcc1d071SRick Macklem * instead of looping back up the dirp to the mount 3134bcc1d071SRick Macklem * point?? 31358fae3551SRodney W. Grimes * Also, needs to know how to export all types of local 313687564113SPeter Wemm * exportable filesystems and not just "ufs". 31378fae3551SRodney W. Grimes */ 31386a09faf2SCraig Rodrigues iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 31396a09faf2SCraig Rodrigues iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 31406a09faf2SCraig Rodrigues iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 31416a09faf2SCraig Rodrigues iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 31426a09faf2SCraig Rodrigues iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 31436a09faf2SCraig Rodrigues iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 31444a185fa6SBryan Drewery errmsg[0] = '\0'; 31456a09faf2SCraig Rodrigues 314655dd1327SCraig Rodrigues while (nmount(iov, iovlen, fsb->f_flags) < 0) { 31478fae3551SRodney W. Grimes if (cp) 31488fae3551SRodney W. Grimes *cp-- = savedc; 31498fae3551SRodney W. Grimes else 31508fae3551SRodney W. Grimes cp = dirp + dirplen - 1; 31516a09faf2SCraig Rodrigues if (opt_flags & OP_QUIET) { 31526a09faf2SCraig Rodrigues ret = 1; 31536a09faf2SCraig Rodrigues goto error_exit; 31546a09faf2SCraig Rodrigues } 31558fae3551SRodney W. Grimes if (errno == EPERM) { 315601709abfSIan Dowse if (debug) 315777909162SXin LI warnx("can't change attributes for %s: %s", 315877909162SXin LI dirp, errmsg); 31598fae3551SRodney W. Grimes syslog(LOG_ERR, 316077909162SXin LI "can't change attributes for %s: %s", 316177909162SXin LI dirp, errmsg); 31626a09faf2SCraig Rodrigues ret = 1; 31636a09faf2SCraig Rodrigues goto error_exit; 31648fae3551SRodney W. Grimes } 31658fae3551SRodney W. Grimes if (opt_flags & OP_ALLDIRS) { 3166288fa14aSJoerg Wunsch if (errno == EINVAL) 3167288fa14aSJoerg Wunsch syslog(LOG_ERR, 3168288fa14aSJoerg Wunsch "-alldirs requested but %s is not a filesystem mountpoint", 3169288fa14aSJoerg Wunsch dirp); 3170288fa14aSJoerg Wunsch else 3171288fa14aSJoerg Wunsch syslog(LOG_ERR, 3172288fa14aSJoerg Wunsch "could not remount %s: %m", 31733980ac4fSGarrett Wollman dirp); 31746a09faf2SCraig Rodrigues ret = 1; 31756a09faf2SCraig Rodrigues goto error_exit; 31768fae3551SRodney W. Grimes } 31778fae3551SRodney W. Grimes /* back up over the last component */ 3178d90b3641SBrooks Davis while (cp > dirp && *cp == '/') 31798fae3551SRodney W. Grimes cp--; 3180d90b3641SBrooks Davis while (cp > dirp && *(cp - 1) != '/') 31818fae3551SRodney W. Grimes cp--; 31828fae3551SRodney W. Grimes if (cp == dirp) { 31838fae3551SRodney W. Grimes if (debug) 318474853402SPhilippe Charnier warnx("mnt unsucc"); 3185bcc1d071SRick Macklem syslog(LOG_ERR, "can't export %s %s", 3186bcc1d071SRick Macklem dirp, errmsg); 31876a09faf2SCraig Rodrigues ret = 1; 31886a09faf2SCraig Rodrigues goto error_exit; 31898fae3551SRodney W. Grimes } 31908fae3551SRodney W. Grimes savedc = *cp; 31918fae3551SRodney W. Grimes *cp = '\0'; 3192bcc1d071SRick Macklem /* 3193bcc1d071SRick Macklem * Check that we're still on the same 3194bcc1d071SRick Macklem * filesystem. 3195bcc1d071SRick Macklem */ 3196bcc1d071SRick Macklem if (statfs(dirp, &fsb1) != 0 || 3197245bfd34SRyan Moeller fsidcmp(&fsb1.f_fsid, &fsb->f_fsid) != 0) { 3198f93caef2SIan Dowse *cp = savedc; 3199bcc1d071SRick Macklem syslog(LOG_ERR, 3200bcc1d071SRick Macklem "can't export %s %s", dirp, 320137518a88SCraig Rodrigues errmsg); 32026a09faf2SCraig Rodrigues ret = 1; 32036a09faf2SCraig Rodrigues goto error_exit; 3204f93caef2SIan Dowse } 32058fae3551SRodney W. Grimes } 3206bcc1d071SRick Macklem } 3207bcc1d071SRick Macklem 3208bcc1d071SRick Macklem /* 3209bcc1d071SRick Macklem * For the experimental server: 3210bcc1d071SRick Macklem * If this is the public directory, get the file handle 3211bcc1d071SRick Macklem * and load it into the kernel via the nfssvc() syscall. 3212bcc1d071SRick Macklem */ 321379b86807SEdward Tomasz Napierala if ((exflags & MNT_EXPUBLIC) != 0) { 3214bcc1d071SRick Macklem fhandle_t fh; 3215bcc1d071SRick Macklem char *public_name; 3216bcc1d071SRick Macklem 3217bcc1d071SRick Macklem if (eap->ex_indexfile != NULL) 3218bcc1d071SRick Macklem public_name = eap->ex_indexfile; 3219bcc1d071SRick Macklem else 3220bcc1d071SRick Macklem public_name = dirp; 3221bcc1d071SRick Macklem if (getfh(public_name, &fh) < 0) 3222bcc1d071SRick Macklem syslog(LOG_ERR, 3223bcc1d071SRick Macklem "Can't get public fh for %s", public_name); 3224bcc1d071SRick Macklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 3225bcc1d071SRick Macklem syslog(LOG_ERR, 3226bcc1d071SRick Macklem "Can't set public fh for %s", public_name); 32270f0869bcSRick Macklem else { 3228bcc1d071SRick Macklem has_publicfh = 1; 32290f0869bcSRick Macklem has_set_publicfh = 1; 32300f0869bcSRick Macklem ep->ex_flag |= EX_PUBLICFH; 32310f0869bcSRick Macklem } 3232bcc1d071SRick Macklem } 32338360efbdSAlfred Perlstein skip: 32346d359f31SIan Dowse if (ai != NULL) 32358360efbdSAlfred Perlstein ai = ai->ai_next; 32368360efbdSAlfred Perlstein if (ai == NULL) 32378fae3551SRodney W. Grimes done = TRUE; 32388fae3551SRodney W. Grimes } 32398fae3551SRodney W. Grimes if (cp) 32408fae3551SRodney W. Grimes *cp = savedc; 32416a09faf2SCraig Rodrigues error_exit: 3242cc5efddeSRick Macklem free(eap->ex_groups); 32436a09faf2SCraig Rodrigues /* free strings allocated by strdup() in getmntopts.c */ 32446a09faf2SCraig Rodrigues if (iov != NULL) { 32456a09faf2SCraig Rodrigues free(iov[0].iov_base); /* fstype */ 32466a09faf2SCraig Rodrigues free(iov[2].iov_base); /* fspath */ 32476a09faf2SCraig Rodrigues free(iov[4].iov_base); /* from */ 32486a09faf2SCraig Rodrigues free(iov[6].iov_base); /* update */ 32496a09faf2SCraig Rodrigues free(iov[8].iov_base); /* export */ 32506a09faf2SCraig Rodrigues free(iov[10].iov_base); /* errmsg */ 32516a09faf2SCraig Rodrigues 32526a09faf2SCraig Rodrigues /* free iov, allocated by realloc() */ 32536a09faf2SCraig Rodrigues free(iov); 32546a09faf2SCraig Rodrigues } 32556a09faf2SCraig Rodrigues return (ret); 32568fae3551SRodney W. Grimes } 32578fae3551SRodney W. Grimes 32588fae3551SRodney W. Grimes /* 32598fae3551SRodney W. Grimes * Translate a net address. 326060caaee2SIan Dowse * 326160caaee2SIan Dowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 32628fae3551SRodney W. Grimes */ 326319c46d8cSEdward Tomasz Napierala static int 3264a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg) 32658fae3551SRodney W. Grimes { 3266931c04f1SIan Dowse struct netent *np = NULL; 32678360efbdSAlfred Perlstein char *name, *p, *prefp; 326860caaee2SIan Dowse struct sockaddr_in sin; 3269931c04f1SIan Dowse struct sockaddr *sa = NULL; 32708360efbdSAlfred Perlstein struct addrinfo hints, *ai = NULL; 32718360efbdSAlfred Perlstein char netname[NI_MAXHOST]; 32728360efbdSAlfred Perlstein long preflen; 32738fae3551SRodney W. Grimes 327401709abfSIan Dowse p = prefp = NULL; 32758360efbdSAlfred Perlstein if ((opt_flags & OP_MASKLEN) && !maskflg) { 32768360efbdSAlfred Perlstein p = strchr(cp, '/'); 32778360efbdSAlfred Perlstein *p = '\0'; 32788360efbdSAlfred Perlstein prefp = p + 1; 32798360efbdSAlfred Perlstein } 32808360efbdSAlfred Perlstein 3281931c04f1SIan Dowse /* 3282931c04f1SIan Dowse * Check for a numeric address first. We wish to avoid 3283931c04f1SIan Dowse * possible DNS lookups in getnetbyname(). 3284931c04f1SIan Dowse */ 3285931c04f1SIan Dowse if (isxdigit(*cp) || *cp == ':') { 32868360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 328760caaee2SIan Dowse /* Ensure the mask and the network have the same family. */ 328860caaee2SIan Dowse if (maskflg && (opt_flags & OP_NET)) 328960caaee2SIan Dowse hints.ai_family = net->nt_net.ss_family; 329060caaee2SIan Dowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 329160caaee2SIan Dowse hints.ai_family = net->nt_mask.ss_family; 329260caaee2SIan Dowse else 32938360efbdSAlfred Perlstein hints.ai_family = AF_UNSPEC; 32948360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 3295931c04f1SIan Dowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 3296931c04f1SIan Dowse sa = ai->ai_addr; 3297931c04f1SIan Dowse if (sa != NULL && ai->ai_family == AF_INET) { 32988fae3551SRodney W. Grimes /* 329960caaee2SIan Dowse * The address in `cp' is really a network address, so 330060caaee2SIan Dowse * use inet_network() to re-interpret this correctly. 330160caaee2SIan Dowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 33028fae3551SRodney W. Grimes */ 330360caaee2SIan Dowse bzero(&sin, sizeof sin); 33048360efbdSAlfred Perlstein sin.sin_family = AF_INET; 33058360efbdSAlfred Perlstein sin.sin_len = sizeof sin; 33068360efbdSAlfred Perlstein sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 33078360efbdSAlfred Perlstein if (debug) 330860caaee2SIan Dowse fprintf(stderr, "get_net: v4 addr %s\n", 330960caaee2SIan Dowse inet_ntoa(sin.sin_addr)); 33108360efbdSAlfred Perlstein sa = (struct sockaddr *)&sin; 3311931c04f1SIan Dowse } 3312931c04f1SIan Dowse } 3313931c04f1SIan Dowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 3314931c04f1SIan Dowse bzero(&sin, sizeof sin); 3315931c04f1SIan Dowse sin.sin_family = AF_INET; 3316931c04f1SIan Dowse sin.sin_len = sizeof sin; 3317931c04f1SIan Dowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 3318931c04f1SIan Dowse sa = (struct sockaddr *)&sin; 3319931c04f1SIan Dowse } 3320931c04f1SIan Dowse if (sa == NULL) 33218360efbdSAlfred Perlstein goto fail; 33228360efbdSAlfred Perlstein 332360caaee2SIan Dowse if (maskflg) { 332460caaee2SIan Dowse /* The specified sockaddr is a mask. */ 332560caaee2SIan Dowse if (checkmask(sa) != 0) 33268360efbdSAlfred Perlstein goto fail; 332760caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 332860caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 332960caaee2SIan Dowse } else { 333060caaee2SIan Dowse /* The specified sockaddr is a network address. */ 333160caaee2SIan Dowse bcopy(sa, &net->nt_net, sa->sa_len); 33320f4b7baaSPaul Traina 333360caaee2SIan Dowse /* Get a network name for the export list. */ 333460caaee2SIan Dowse if (np) { 333560caaee2SIan Dowse name = np->n_name; 333660caaee2SIan Dowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 33374f101318SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) { 333860caaee2SIan Dowse name = netname; 333960caaee2SIan Dowse } else { 334060caaee2SIan Dowse goto fail; 334160caaee2SIan Dowse } 334260caaee2SIan Dowse if ((net->nt_name = strdup(name)) == NULL) 334360caaee2SIan Dowse out_of_mem(); 334460caaee2SIan Dowse 334560caaee2SIan Dowse /* 334660caaee2SIan Dowse * Extract a mask from either a "/<masklen>" suffix, or 334760caaee2SIan Dowse * from the class of an IPv4 address. 334860caaee2SIan Dowse */ 33498360efbdSAlfred Perlstein if (opt_flags & OP_MASKLEN) { 33508360efbdSAlfred Perlstein preflen = strtol(prefp, NULL, 10); 335160caaee2SIan Dowse if (preflen < 0L || preflen == LONG_MAX) 33528360efbdSAlfred Perlstein goto fail; 335360caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 335460caaee2SIan Dowse if (makemask(&net->nt_mask, (int)preflen) != 0) 335560caaee2SIan Dowse goto fail; 335660caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 33578360efbdSAlfred Perlstein *p = '/'; 335860caaee2SIan Dowse } else if (sa->sa_family == AF_INET && 335960caaee2SIan Dowse (opt_flags & OP_MASK) == 0) { 336060caaee2SIan Dowse in_addr_t addr; 33618360efbdSAlfred Perlstein 336260caaee2SIan Dowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 336360caaee2SIan Dowse if (IN_CLASSA(addr)) 336460caaee2SIan Dowse preflen = 8; 336560caaee2SIan Dowse else if (IN_CLASSB(addr)) 336660caaee2SIan Dowse preflen = 16; 336760caaee2SIan Dowse else if (IN_CLASSC(addr)) 336860caaee2SIan Dowse preflen = 24; 336960caaee2SIan Dowse else if (IN_CLASSD(addr)) 337060caaee2SIan Dowse preflen = 28; 33718360efbdSAlfred Perlstein else 337260caaee2SIan Dowse preflen = 32; /* XXX */ 337360caaee2SIan Dowse 337460caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 337560caaee2SIan Dowse makemask(&net->nt_mask, (int)preflen); 337660caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 337760caaee2SIan Dowse } 33788360efbdSAlfred Perlstein } 33798360efbdSAlfred Perlstein 33808360efbdSAlfred Perlstein if (ai) 33818360efbdSAlfred Perlstein freeaddrinfo(ai); 33828360efbdSAlfred Perlstein return 0; 33838360efbdSAlfred Perlstein 33848360efbdSAlfred Perlstein fail: 33858360efbdSAlfred Perlstein if (ai) 33868360efbdSAlfred Perlstein freeaddrinfo(ai); 33878360efbdSAlfred Perlstein return 1; 33888fae3551SRodney W. Grimes } 33898fae3551SRodney W. Grimes 33908fae3551SRodney W. Grimes /* 33918fae3551SRodney W. Grimes * Parse out the next white space separated field 33928fae3551SRodney W. Grimes */ 339319c46d8cSEdward Tomasz Napierala static void 3394a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp) 33958fae3551SRodney W. Grimes { 33968fae3551SRodney W. Grimes char *p; 3397eb1f7f43SAlexander Motin char quot = 0; 33988fae3551SRodney W. Grimes 33998fae3551SRodney W. Grimes p = *cp; 34008fae3551SRodney W. Grimes while (*p == ' ' || *p == '\t') 34018fae3551SRodney W. Grimes p++; 3402eb1f7f43SAlexander Motin *cp = p; 3403eb1f7f43SAlexander Motin while (*p != '\0') { 3404eb1f7f43SAlexander Motin if (quot) { 3405eb1f7f43SAlexander Motin if (*p == quot) 3406eb1f7f43SAlexander Motin quot = 0; 3407eb1f7f43SAlexander Motin } else { 3408eb1f7f43SAlexander Motin if (*p == '\\' && *(p + 1) != '\0') 34098fae3551SRodney W. Grimes p++; 3410eb1f7f43SAlexander Motin else if (*p == '\'' || *p == '"') 3411eb1f7f43SAlexander Motin quot = *p; 3412eb1f7f43SAlexander Motin else if (*p == ' ' || *p == '\t') 3413eb1f7f43SAlexander Motin break; 34148fae3551SRodney W. Grimes } 3415eb1f7f43SAlexander Motin p++; 3416eb1f7f43SAlexander Motin }; 3417eb1f7f43SAlexander Motin *endcp = p; 34188fae3551SRodney W. Grimes } 34198fae3551SRodney W. Grimes 34208fae3551SRodney W. Grimes /* 34218fae3551SRodney W. Grimes * Get an exports file line. Skip over blank lines and handle line 34228fae3551SRodney W. Grimes * continuations. 34238fae3551SRodney W. Grimes */ 342419c46d8cSEdward Tomasz Napierala static int 3425a7a7d96cSPhilippe Charnier get_line(void) 34268fae3551SRodney W. Grimes { 34278fae3551SRodney W. Grimes char *p, *cp; 342891ca1a91SIan Dowse size_t len; 34298fae3551SRodney W. Grimes int totlen, cont_line; 34308fae3551SRodney W. Grimes 34318fae3551SRodney W. Grimes /* 34328fae3551SRodney W. Grimes * Loop around ignoring blank lines and getting all continuation lines. 34338fae3551SRodney W. Grimes */ 34348fae3551SRodney W. Grimes p = line; 34358fae3551SRodney W. Grimes totlen = 0; 34368fae3551SRodney W. Grimes do { 343791ca1a91SIan Dowse if ((p = fgetln(exp_file, &len)) == NULL) 34388fae3551SRodney W. Grimes return (0); 34398fae3551SRodney W. Grimes cp = p + len - 1; 34408fae3551SRodney W. Grimes cont_line = 0; 34418fae3551SRodney W. Grimes while (cp >= p && 34428fae3551SRodney W. Grimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 34438fae3551SRodney W. Grimes if (*cp == '\\') 34448fae3551SRodney W. Grimes cont_line = 1; 34458fae3551SRodney W. Grimes cp--; 34468fae3551SRodney W. Grimes len--; 34478fae3551SRodney W. Grimes } 3448376f8390SDima Dorfman if (cont_line) { 3449376f8390SDima Dorfman *++cp = ' '; 3450376f8390SDima Dorfman len++; 3451376f8390SDima Dorfman } 345291ca1a91SIan Dowse if (linesize < len + totlen + 1) { 345391ca1a91SIan Dowse linesize = len + totlen + 1; 345491ca1a91SIan Dowse line = realloc(line, linesize); 345591ca1a91SIan Dowse if (line == NULL) 345691ca1a91SIan Dowse out_of_mem(); 345791ca1a91SIan Dowse } 345891ca1a91SIan Dowse memcpy(line + totlen, p, len); 34598fae3551SRodney W. Grimes totlen += len; 346091ca1a91SIan Dowse line[totlen] = '\0'; 34618fae3551SRodney W. Grimes } while (totlen == 0 || cont_line); 34628fae3551SRodney W. Grimes return (1); 34638fae3551SRodney W. Grimes } 34648fae3551SRodney W. Grimes 34658fae3551SRodney W. Grimes /* 34668fae3551SRodney W. Grimes * Parse a description of a credential. 34678fae3551SRodney W. Grimes */ 346819c46d8cSEdward Tomasz Napierala static void 3469cc5efddeSRick Macklem parsecred(char *namelist, struct expcred *cr) 34708fae3551SRodney W. Grimes { 34718fae3551SRodney W. Grimes char *name; 3472*2ffad162SRick Macklem int inpos; 34738fae3551SRodney W. Grimes char *names; 34748fae3551SRodney W. Grimes struct passwd *pw; 34758fae3551SRodney W. Grimes struct group *gr; 3476*2ffad162SRick Macklem gid_t groups[NGROUPS_MAX + 1]; 3477*2ffad162SRick Macklem int ngroups; 34788fae3551SRodney W. Grimes 34798fae3551SRodney W. Grimes /* 348074853402SPhilippe Charnier * Set up the unprivileged user. 34818fae3551SRodney W. Grimes */ 3482*2ffad162SRick Macklem cr->cr_groups = cr->cr_smallgrps; 34833e2d36ffSRick Macklem cr->cr_uid = UID_NOBODY; 34843e2d36ffSRick Macklem cr->cr_groups[0] = GID_NOGROUP; 34858fae3551SRodney W. Grimes cr->cr_ngroups = 1; 34868fae3551SRodney W. Grimes /* 34878fae3551SRodney W. Grimes * Get the user's password table entry. 34888fae3551SRodney W. Grimes */ 3489eb1f7f43SAlexander Motin names = namelist; 3490eb1f7f43SAlexander Motin name = strsep_quote(&names, ":"); 3491b875c2e9SJosh Paetzel /* Bug? name could be NULL here */ 34928fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') 34938fae3551SRodney W. Grimes pw = getpwuid(atoi(name)); 34948fae3551SRodney W. Grimes else 34958fae3551SRodney W. Grimes pw = getpwnam(name); 34968fae3551SRodney W. Grimes /* 34978fae3551SRodney W. Grimes * Credentials specified as those of a user. 34988fae3551SRodney W. Grimes */ 34998fae3551SRodney W. Grimes if (names == NULL) { 35008fae3551SRodney W. Grimes if (pw == NULL) { 350174853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 35028fae3551SRodney W. Grimes return; 35038fae3551SRodney W. Grimes } 35048fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 3505*2ffad162SRick Macklem ngroups = NGROUPS_MAX + 1; 3506*2ffad162SRick Macklem if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { 350774853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 3508*2ffad162SRick Macklem ngroups = NGROUPS_MAX + 1; 3509020d6f96SAndriy Gapon } 3510020d6f96SAndriy Gapon 35118fae3551SRodney W. Grimes /* 3512950cc395SStefan Farfeleder * Compress out duplicate. 35138fae3551SRodney W. Grimes */ 3514*2ffad162SRick Macklem if (ngroups > 1 && groups[0] == groups[1]) { 3515*2ffad162SRick Macklem ngroups--; 3516*2ffad162SRick Macklem inpos = 2; 3517*2ffad162SRick Macklem } else 3518*2ffad162SRick Macklem inpos = 1; 3519*2ffad162SRick Macklem if (ngroups > NGROUPS_MAX) 3520*2ffad162SRick Macklem ngroups = NGROUPS_MAX; 3521*2ffad162SRick Macklem if (ngroups > SMALLNGROUPS) 3522*2ffad162SRick Macklem cr->cr_groups = malloc(ngroups * sizeof(gid_t)); 3523*2ffad162SRick Macklem cr->cr_ngroups = ngroups; 3524*2ffad162SRick Macklem cr->cr_groups[0] = groups[0]; 3525*2ffad162SRick Macklem memcpy(&cr->cr_groups[1], &groups[inpos], (ngroups - 1) * 3526*2ffad162SRick Macklem sizeof(gid_t)); 35278fae3551SRodney W. Grimes return; 35288fae3551SRodney W. Grimes } 35298fae3551SRodney W. Grimes /* 35308fae3551SRodney W. Grimes * Explicit credential specified as a colon separated list: 35318fae3551SRodney W. Grimes * uid:gid:gid:... 35328fae3551SRodney W. Grimes */ 35338fae3551SRodney W. Grimes if (pw != NULL) 35348fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 35358fae3551SRodney W. Grimes else if (isdigit(*name) || *name == '-') 35368fae3551SRodney W. Grimes cr->cr_uid = atoi(name); 35378fae3551SRodney W. Grimes else { 353874853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 35398fae3551SRodney W. Grimes return; 35408fae3551SRodney W. Grimes } 35418fae3551SRodney W. Grimes cr->cr_ngroups = 0; 3542cc5efddeSRick Macklem while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { 3543eb1f7f43SAlexander Motin name = strsep_quote(&names, ":"); 35448fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') { 3545*2ffad162SRick Macklem groups[cr->cr_ngroups++] = atoi(name); 35468fae3551SRodney W. Grimes } else { 35478fae3551SRodney W. Grimes if ((gr = getgrnam(name)) == NULL) { 354874853402SPhilippe Charnier syslog(LOG_ERR, "unknown group: %s", name); 35498fae3551SRodney W. Grimes continue; 35508fae3551SRodney W. Grimes } 3551*2ffad162SRick Macklem groups[cr->cr_ngroups++] = gr->gr_gid; 35528fae3551SRodney W. Grimes } 35538fae3551SRodney W. Grimes } 3554cc5efddeSRick Macklem if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) 355574853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 3556*2ffad162SRick Macklem if (cr->cr_ngroups > SMALLNGROUPS) 3557*2ffad162SRick Macklem cr->cr_groups = malloc(cr->cr_ngroups * sizeof(gid_t)); 3558*2ffad162SRick Macklem memcpy(cr->cr_groups, groups, cr->cr_ngroups * sizeof(gid_t)); 35598fae3551SRodney W. Grimes } 35608fae3551SRodney W. Grimes 35610775314bSDoug Rabson #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 35628fae3551SRodney W. Grimes /* 35638fae3551SRodney W. Grimes * Routines that maintain the remote mounttab 35648fae3551SRodney W. Grimes */ 356519c46d8cSEdward Tomasz Napierala static void 3566a7a7d96cSPhilippe Charnier get_mountlist(void) 35678fae3551SRodney W. Grimes { 35681da3e8b0SEmmanuel Vadot struct mountlist *mlp; 356987564113SPeter Wemm char *host, *dirp, *cp; 35708fae3551SRodney W. Grimes char str[STRSIZ]; 35718fae3551SRodney W. Grimes FILE *mlfile; 35728fae3551SRodney W. Grimes 35738fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 357439539916SBill Fumerola if (errno == ENOENT) 357539539916SBill Fumerola return; 357639539916SBill Fumerola else { 357774853402SPhilippe Charnier syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 35788fae3551SRodney W. Grimes return; 35798fae3551SRodney W. Grimes } 358039539916SBill Fumerola } 35818fae3551SRodney W. Grimes while (fgets(str, STRSIZ, mlfile) != NULL) { 358287564113SPeter Wemm cp = str; 358387564113SPeter Wemm host = strsep(&cp, " \t\n"); 358487564113SPeter Wemm dirp = strsep(&cp, " \t\n"); 358587564113SPeter Wemm if (host == NULL || dirp == NULL) 35868fae3551SRodney W. Grimes continue; 35878fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 358874853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 358974853402SPhilippe Charnier out_of_mem(); 35900775314bSDoug Rabson strncpy(mlp->ml_host, host, MNTNAMLEN); 35910775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 35920775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 35930775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 35941da3e8b0SEmmanuel Vadot 35951da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 35968fae3551SRodney W. Grimes } 35978fae3551SRodney W. Grimes fclose(mlfile); 35988fae3551SRodney W. Grimes } 35998fae3551SRodney W. Grimes 360019c46d8cSEdward Tomasz Napierala static void 360101709abfSIan Dowse del_mlist(char *hostp, char *dirp) 36028fae3551SRodney W. Grimes { 36031da3e8b0SEmmanuel Vadot struct mountlist *mlp, *mlp2; 36048fae3551SRodney W. Grimes FILE *mlfile; 36058fae3551SRodney W. Grimes int fnd = 0; 36068fae3551SRodney W. Grimes 36071da3e8b0SEmmanuel Vadot SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) { 36088fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && 36098fae3551SRodney W. Grimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 36108fae3551SRodney W. Grimes fnd = 1; 36111da3e8b0SEmmanuel Vadot SLIST_REMOVE(&mlhead, mlp, mountlist, next); 36121da3e8b0SEmmanuel Vadot free((caddr_t)mlp); 36138fae3551SRodney W. Grimes } 36148fae3551SRodney W. Grimes } 36158fae3551SRodney W. Grimes if (fnd) { 36168fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 361774853402SPhilippe Charnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 36188fae3551SRodney W. Grimes return; 36198fae3551SRodney W. Grimes } 36201da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 36218fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 36228fae3551SRodney W. Grimes } 36238fae3551SRodney W. Grimes fclose(mlfile); 36248fae3551SRodney W. Grimes } 36258fae3551SRodney W. Grimes } 36268fae3551SRodney W. Grimes 362719c46d8cSEdward Tomasz Napierala static void 3628a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp) 36298fae3551SRodney W. Grimes { 36301da3e8b0SEmmanuel Vadot struct mountlist *mlp; 36318fae3551SRodney W. Grimes FILE *mlfile; 36328fae3551SRodney W. Grimes 36331da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 36348fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 36358fae3551SRodney W. Grimes return; 36368fae3551SRodney W. Grimes } 36371da3e8b0SEmmanuel Vadot 36388fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 363974853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 364074853402SPhilippe Charnier out_of_mem(); 36410775314bSDoug Rabson strncpy(mlp->ml_host, hostp, MNTNAMLEN); 36420775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 36430775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 36440775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 36451da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 36468fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 364774853402SPhilippe Charnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 36488fae3551SRodney W. Grimes return; 36498fae3551SRodney W. Grimes } 36508fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 36518fae3551SRodney W. Grimes fclose(mlfile); 36528fae3551SRodney W. Grimes } 36538fae3551SRodney W. Grimes 36548fae3551SRodney W. Grimes /* 36558fae3551SRodney W. Grimes * Free up a group list. 36568fae3551SRodney W. Grimes */ 365719c46d8cSEdward Tomasz Napierala static void 3658a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp) 36598fae3551SRodney W. Grimes { 36608fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 36618360efbdSAlfred Perlstein if (grp->gr_ptr.gt_addrinfo != NULL) 36628360efbdSAlfred Perlstein freeaddrinfo(grp->gr_ptr.gt_addrinfo); 36638fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 36648fae3551SRodney W. Grimes if (grp->gr_ptr.gt_net.nt_name) 36658fae3551SRodney W. Grimes free(grp->gr_ptr.gt_net.nt_name); 36668fae3551SRodney W. Grimes } 3667*2ffad162SRick Macklem if (grp->gr_anon.cr_groups != grp->gr_anon.cr_smallgrps) 3668*2ffad162SRick Macklem free(grp->gr_anon.cr_groups); 36698fae3551SRodney W. Grimes free((caddr_t)grp); 36708fae3551SRodney W. Grimes } 36718fae3551SRodney W. Grimes 36728fae3551SRodney W. Grimes #ifdef DEBUG 367319c46d8cSEdward Tomasz Napierala static void 36748fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...) 36758fae3551SRodney W. Grimes { 36768fae3551SRodney W. Grimes va_list ap; 36778fae3551SRodney W. Grimes 36788fae3551SRodney W. Grimes va_start(ap, fmt); 36798fae3551SRodney W. Grimes vfprintf(stderr, fmt, ap); 36808fae3551SRodney W. Grimes va_end(ap); 36818fae3551SRodney W. Grimes } 36828fae3551SRodney W. Grimes #endif /* DEBUG */ 36838fae3551SRodney W. Grimes 36848fae3551SRodney W. Grimes /* 36858fae3551SRodney W. Grimes * Check options for consistency. 36868fae3551SRodney W. Grimes */ 368719c46d8cSEdward Tomasz Napierala static int 3688a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp) 36898fae3551SRodney W. Grimes { 36908fae3551SRodney W. Grimes 3691bcc1d071SRick Macklem if (v4root_phase == 0 && dp == NULL) 36928fae3551SRodney W. Grimes return (1); 369391196234SPeter Wemm if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 369491196234SPeter Wemm syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 36958fae3551SRodney W. Grimes return (1); 36968fae3551SRodney W. Grimes } 36978fae3551SRodney W. Grimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 369860caaee2SIan Dowse syslog(LOG_ERR, "-mask requires -network"); 369960caaee2SIan Dowse return (1); 370060caaee2SIan Dowse } 370160caaee2SIan Dowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 370260caaee2SIan Dowse syslog(LOG_ERR, "-network requires mask specification"); 370360caaee2SIan Dowse return (1); 370460caaee2SIan Dowse } 370560caaee2SIan Dowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 370660caaee2SIan Dowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 37078fae3551SRodney W. Grimes return (1); 37088fae3551SRodney W. Grimes } 3709bcc1d071SRick Macklem if (v4root_phase > 0 && 3710bcc1d071SRick Macklem (opt_flags & 3711bcc1d071SRick Macklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3712bcc1d071SRick Macklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3713bcc1d071SRick Macklem return (1); 3714bcc1d071SRick Macklem } 371556cfc5edSRick Macklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 371656cfc5edSRick Macklem syslog(LOG_ERR, "-alldirs has multiple directories"); 371756cfc5edSRick Macklem return (1); 371856cfc5edSRick Macklem } 37198fae3551SRodney W. Grimes return (0); 37208fae3551SRodney W. Grimes } 37218fae3551SRodney W. Grimes 37228fae3551SRodney W. Grimes /* 37238fae3551SRodney W. Grimes * Check an absolute directory path for any symbolic links. Return true 37248fae3551SRodney W. Grimes */ 372519c46d8cSEdward Tomasz Napierala static int 3726a7a7d96cSPhilippe Charnier check_dirpath(char *dirp) 37278fae3551SRodney W. Grimes { 37288fae3551SRodney W. Grimes char *cp; 37298fae3551SRodney W. Grimes int ret = 1; 37308fae3551SRodney W. Grimes struct stat sb; 37318fae3551SRodney W. Grimes 37328fae3551SRodney W. Grimes cp = dirp + 1; 37338fae3551SRodney W. Grimes while (*cp && ret) { 37348fae3551SRodney W. Grimes if (*cp == '/') { 37358fae3551SRodney W. Grimes *cp = '\0'; 3736a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 37378fae3551SRodney W. Grimes ret = 0; 37388fae3551SRodney W. Grimes *cp = '/'; 37398fae3551SRodney W. Grimes } 37408fae3551SRodney W. Grimes cp++; 37418fae3551SRodney W. Grimes } 3742a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 37438fae3551SRodney W. Grimes ret = 0; 37448fae3551SRodney W. Grimes return (ret); 37458fae3551SRodney W. Grimes } 3746a62dc406SDoug Rabson 374760caaee2SIan Dowse /* 374860caaee2SIan Dowse * Make a netmask according to the specified prefix length. The ss_family 374960caaee2SIan Dowse * and other non-address fields must be initialised before calling this. 375060caaee2SIan Dowse */ 375119c46d8cSEdward Tomasz Napierala static int 375260caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen) 37538360efbdSAlfred Perlstein { 375460caaee2SIan Dowse u_char *p; 375560caaee2SIan Dowse int bits, i, len; 37568360efbdSAlfred Perlstein 375760caaee2SIan Dowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 375860caaee2SIan Dowse return (-1); 375989fdc4e1SMike Barcroft if (bitlen > len * CHAR_BIT) 376060caaee2SIan Dowse return (-1); 37618360efbdSAlfred Perlstein 376260caaee2SIan Dowse for (i = 0; i < len; i++) { 3763a175f065SMarcelo Araujo bits = MIN(CHAR_BIT, bitlen); 376458202d89SRuslan Ermilov *p++ = (u_char)~0 << (CHAR_BIT - bits); 376560caaee2SIan Dowse bitlen -= bits; 37668360efbdSAlfred Perlstein } 37678360efbdSAlfred Perlstein return 0; 37688360efbdSAlfred Perlstein } 37698360efbdSAlfred Perlstein 377060caaee2SIan Dowse /* 377160caaee2SIan Dowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 377260caaee2SIan Dowse * is acceptable (i.e. of the form 1...10....0). 377360caaee2SIan Dowse */ 377419c46d8cSEdward Tomasz Napierala static int 377560caaee2SIan Dowse checkmask(struct sockaddr *sa) 37768360efbdSAlfred Perlstein { 377760caaee2SIan Dowse u_char *mask; 377860caaee2SIan Dowse int i, len; 377960caaee2SIan Dowse 378060caaee2SIan Dowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 378160caaee2SIan Dowse return (-1); 378260caaee2SIan Dowse 378360caaee2SIan Dowse for (i = 0; i < len; i++) 378460caaee2SIan Dowse if (mask[i] != 0xff) 378560caaee2SIan Dowse break; 378660caaee2SIan Dowse if (i < len) { 378760caaee2SIan Dowse if (~mask[i] & (u_char)(~mask[i] + 1)) 378860caaee2SIan Dowse return (-1); 378960caaee2SIan Dowse i++; 379060caaee2SIan Dowse } 379160caaee2SIan Dowse for (; i < len; i++) 379260caaee2SIan Dowse if (mask[i] != 0) 379360caaee2SIan Dowse return (-1); 379460caaee2SIan Dowse return (0); 379560caaee2SIan Dowse } 379660caaee2SIan Dowse 379760caaee2SIan Dowse /* 379860caaee2SIan Dowse * Compare two sockaddrs according to a specified mask. Return zero if 379960caaee2SIan Dowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 38003df5ecacSUlrich Spörlein * If samask is NULL, perform a full comparison. 380160caaee2SIan Dowse */ 380219c46d8cSEdward Tomasz Napierala static int 380360caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 380460caaee2SIan Dowse { 380560caaee2SIan Dowse unsigned char *p1, *p2, *mask; 380660caaee2SIan Dowse int len, i; 380760caaee2SIan Dowse 380860caaee2SIan Dowse if (sa1->sa_family != sa2->sa_family || 380960caaee2SIan Dowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 381060caaee2SIan Dowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 381160caaee2SIan Dowse return (1); 381260caaee2SIan Dowse 381360caaee2SIan Dowse switch (sa1->sa_family) { 381460caaee2SIan Dowse case AF_INET6: 381560caaee2SIan Dowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 381660caaee2SIan Dowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 381760caaee2SIan Dowse return (1); 381860caaee2SIan Dowse break; 381960caaee2SIan Dowse } 382060caaee2SIan Dowse 382160caaee2SIan Dowse /* Simple binary comparison if no mask specified. */ 382260caaee2SIan Dowse if (samask == NULL) 382360caaee2SIan Dowse return (memcmp(p1, p2, len)); 382460caaee2SIan Dowse 382560caaee2SIan Dowse /* Set up the mask, and do a mask-based comparison. */ 382660caaee2SIan Dowse if (sa1->sa_family != samask->sa_family || 382760caaee2SIan Dowse (mask = sa_rawaddr(samask, NULL)) == NULL) 382860caaee2SIan Dowse return (1); 382960caaee2SIan Dowse 383060caaee2SIan Dowse for (i = 0; i < len; i++) 383160caaee2SIan Dowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 383260caaee2SIan Dowse return (1); 383360caaee2SIan Dowse return (0); 383460caaee2SIan Dowse } 383560caaee2SIan Dowse 383660caaee2SIan Dowse /* 383760caaee2SIan Dowse * Return a pointer to the part of the sockaddr that contains the 383860caaee2SIan Dowse * raw address, and set *nbytes to its length in bytes. Returns 383960caaee2SIan Dowse * NULL if the address family is unknown. 384060caaee2SIan Dowse */ 384119c46d8cSEdward Tomasz Napierala static void * 384260caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) { 384360caaee2SIan Dowse void *p; 384460caaee2SIan Dowse int len; 38458360efbdSAlfred Perlstein 38468360efbdSAlfred Perlstein switch (sa->sa_family) { 38478360efbdSAlfred Perlstein case AF_INET: 384860caaee2SIan Dowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 384960caaee2SIan Dowse p = &((struct sockaddr_in *)sa)->sin_addr; 38508360efbdSAlfred Perlstein break; 38518360efbdSAlfred Perlstein case AF_INET6: 385260caaee2SIan Dowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 385360caaee2SIan Dowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 38548360efbdSAlfred Perlstein break; 38558360efbdSAlfred Perlstein default: 385660caaee2SIan Dowse p = NULL; 385760caaee2SIan Dowse len = 0; 38588360efbdSAlfred Perlstein } 38598360efbdSAlfred Perlstein 386060caaee2SIan Dowse if (nbytes != NULL) 386160caaee2SIan Dowse *nbytes = len; 386260caaee2SIan Dowse return (p); 38638360efbdSAlfred Perlstein } 38648360efbdSAlfred Perlstein 386519c46d8cSEdward Tomasz Napierala static void 3866a7a7d96cSPhilippe Charnier huphandler(int sig __unused) 386769d65572SIan Dowse { 386819c46d8cSEdward Tomasz Napierala 386969d65572SIan Dowse got_sighup = 1; 387069d65572SIan Dowse } 387169d65572SIan Dowse 387219c46d8cSEdward Tomasz Napierala static void 387319c46d8cSEdward Tomasz Napierala terminate(int sig __unused) 38748360efbdSAlfred Perlstein { 3875a032b226SPawel Jakub Dawidek pidfile_remove(pfh); 38760775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 38770775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 38788360efbdSAlfred Perlstein exit (0); 38798360efbdSAlfred Perlstein } 3880cc5efddeSRick Macklem 3881cc5efddeSRick Macklem static void 3882cc5efddeSRick Macklem cp_cred(struct expcred *outcr, struct expcred *incr) 3883cc5efddeSRick Macklem { 3884cc5efddeSRick Macklem 3885cc5efddeSRick Macklem outcr->cr_uid = incr->cr_uid; 3886cc5efddeSRick Macklem outcr->cr_ngroups = incr->cr_ngroups; 3887*2ffad162SRick Macklem if (outcr->cr_ngroups > SMALLNGROUPS) 3888*2ffad162SRick Macklem outcr->cr_groups = malloc(outcr->cr_ngroups * sizeof(gid_t)); 3889*2ffad162SRick Macklem else 3890*2ffad162SRick Macklem outcr->cr_groups = outcr->cr_smallgrps; 3891cc5efddeSRick Macklem memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups * 3892cc5efddeSRick Macklem sizeof(gid_t)); 3893cc5efddeSRick Macklem } 3894