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. 1182ffad162SRick Macklem * cr_smallgrps can be used for a group list up to SMALLNGROUPS in size. 1192ffad162SRick Macklem * Larger group lists are malloc'd/free'd. 120cc5efddeSRick Macklem */ 1212ffad162SRick Macklem #define SMALLNGROUPS 32 122cc5efddeSRick Macklem struct expcred { 123cc5efddeSRick Macklem uid_t cr_uid; 124cc5efddeSRick Macklem int cr_ngroups; 1252ffad162SRick Macklem gid_t cr_smallgrps[SMALLNGROUPS]; 1262ffad162SRick 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 *); 213*572b77f8SAlexander Motin static int check_path_component(const char *, char **); 214*572b77f8SAlexander Motin static int check_dirpath(char *, char **); 215*572b77f8SAlexander Motin static int check_statfs(const char *, struct statfs *, char **); 21619c46d8cSEdward Tomasz Napierala static int check_options(struct dirlist *); 21719c46d8cSEdward Tomasz Napierala static int checkmask(struct sockaddr *sa); 21819c46d8cSEdward Tomasz Napierala static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, 21919c46d8cSEdward Tomasz Napierala int *, int **); 220b875c2e9SJosh Paetzel static char *strsep_quote(char **stringp, const char *delim); 2218fb6ad5dSRick Macklem static int create_service(struct netconfig *nconf); 2228fb6ad5dSRick Macklem static void complete_service(struct netconfig *nconf, char *port_str); 2238fb6ad5dSRick Macklem static void clearout_service(void); 22419c46d8cSEdward Tomasz Napierala static void del_mlist(char *hostp, char *dirp); 22519c46d8cSEdward Tomasz Napierala static struct dirlist *dirp_search(struct dirlist *, char *); 2260f0869bcSRick Macklem static int do_export_mount(struct exportlist *, struct statfs *); 227cc5efddeSRick Macklem static int do_mount(struct exportlist *, struct grouplist *, uint64_t, 228cc5efddeSRick Macklem struct expcred *, char *, int, struct statfs *, int, int *); 22919c46d8cSEdward Tomasz Napierala static int do_opt(char **, char **, struct exportlist *, 230cc5efddeSRick Macklem struct grouplist *, int *, uint64_t *, struct expcred *); 2311a9a992fSRick Macklem static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); 23219c46d8cSEdward Tomasz Napierala static struct exportlist *get_exp(void); 23319c46d8cSEdward Tomasz Napierala static void free_dir(struct dirlist *); 23419c46d8cSEdward Tomasz Napierala static void free_exp(struct exportlist *); 23519c46d8cSEdward Tomasz Napierala static void free_grp(struct grouplist *); 23619c46d8cSEdward Tomasz Napierala static void free_host(struct hostlist *); 2370f0869bcSRick Macklem static void free_v4rootexp(void); 2380f0869bcSRick Macklem static void get_exportlist_one(int); 2390f0869bcSRick Macklem static void get_exportlist(int); 2401a9a992fSRick Macklem static void insert_exports(struct exportlist *, struct exportlisthead *); 2411a9a992fSRick Macklem static void free_exports(struct exportlisthead *); 2420f0869bcSRick Macklem static void read_exportfile(int); 2430f0869bcSRick Macklem static int compare_nmount_exportlist(struct iovec *, int, char *); 2440f0869bcSRick Macklem static int compare_export(struct exportlist *, struct exportlist *); 245cc5efddeSRick Macklem static int compare_cred(struct expcred *, struct expcred *); 2460f0869bcSRick Macklem static int compare_secflavor(int *, int *, int); 2473e08dc74SRick Macklem static void delete_export(struct iovec *, int, struct statfs *, char *); 24819c46d8cSEdward Tomasz Napierala static int get_host(char *, struct grouplist *, struct grouplist *); 24919c46d8cSEdward Tomasz Napierala static struct hostlist *get_ht(void); 25019c46d8cSEdward Tomasz Napierala static int get_line(void); 25119c46d8cSEdward Tomasz Napierala static void get_mountlist(void); 25219c46d8cSEdward Tomasz Napierala static int get_net(char *, struct netmsk *, int); 253354fce28SConrad Meyer static void getexp_err(struct exportlist *, struct grouplist *, const char *); 25419c46d8cSEdward Tomasz Napierala static struct grouplist *get_grp(void); 25519c46d8cSEdward Tomasz Napierala static void hang_dirp(struct dirlist *, struct grouplist *, 256cc5efddeSRick Macklem struct exportlist *, int, struct expcred *, uint64_t); 25719c46d8cSEdward Tomasz Napierala static void huphandler(int sig); 25819c46d8cSEdward Tomasz Napierala static int makemask(struct sockaddr_storage *ssp, int bitlen); 25919c46d8cSEdward Tomasz Napierala static void mntsrv(struct svc_req *, SVCXPRT *); 26019c46d8cSEdward Tomasz Napierala static void nextfield(char **, char **); 26119c46d8cSEdward Tomasz Napierala static void out_of_mem(void); 262cc5efddeSRick Macklem static void parsecred(char *, struct expcred *); 26319c46d8cSEdward Tomasz Napierala static int parsesec(char *, struct exportlist *); 26419c46d8cSEdward Tomasz Napierala static int put_exlist(struct dirlist *, XDR *, struct dirlist *, 26519c46d8cSEdward Tomasz Napierala int *, int); 26619c46d8cSEdward Tomasz Napierala static void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 26719c46d8cSEdward Tomasz Napierala static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 26860caaee2SIan Dowse struct sockaddr *samask); 26919c46d8cSEdward Tomasz Napierala static int scan_tree(struct dirlist *, struct sockaddr *); 27085429990SWarner Losh static void usage(void); 27119c46d8cSEdward Tomasz Napierala static int xdr_dir(XDR *, char *); 27219c46d8cSEdward Tomasz Napierala static int xdr_explist(XDR *, caddr_t); 27319c46d8cSEdward Tomasz Napierala static int xdr_explist_brief(XDR *, caddr_t); 27419c46d8cSEdward Tomasz Napierala static int xdr_explist_common(XDR *, caddr_t, int); 27519c46d8cSEdward Tomasz Napierala static int xdr_fhs(XDR *, caddr_t); 27619c46d8cSEdward Tomasz Napierala static int xdr_mlist(XDR *, caddr_t); 27719c46d8cSEdward Tomasz Napierala static void terminate(int); 278cc5efddeSRick Macklem static void cp_cred(struct expcred *, struct expcred *); 2798fae3551SRodney W. Grimes 28046a6b5c4SRick Macklem #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) 28146a6b5c4SRick Macklem static struct exportlisthead *exphead = NULL; 2820f0869bcSRick Macklem static struct exportlisthead *oldexphead = NULL; 28346a6b5c4SRick Macklem static int exphashsize = 0; 2841a9a992fSRick Macklem static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); 28519c46d8cSEdward Tomasz Napierala static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 28619c46d8cSEdward Tomasz Napierala static char **exnames; 28719c46d8cSEdward Tomasz Napierala static char **hosts = NULL; 28819c46d8cSEdward Tomasz Napierala static int force_v2 = 0; 28919c46d8cSEdward Tomasz Napierala static int resvport_only = 1; 29019c46d8cSEdward Tomasz Napierala static int nhosts = 0; 29119c46d8cSEdward Tomasz Napierala static int dir_only = 1; 29219c46d8cSEdward Tomasz Napierala static int dolog = 0; 29319c46d8cSEdward Tomasz Napierala static int got_sighup = 0; 29419c46d8cSEdward Tomasz Napierala static int xcreated = 0; 295d11e3645SMatteo Riondato 29619c46d8cSEdward Tomasz Napierala static char *svcport_str = NULL; 2978fb6ad5dSRick Macklem static int mallocd_svcport = 0; 2988fb6ad5dSRick Macklem static int *sock_fd; 2998fb6ad5dSRick Macklem static int sock_fdcnt; 3008fb6ad5dSRick Macklem static int sock_fdpos; 301c548eb5cSRick Macklem static int suspend_nfsd = 0; 3028360efbdSAlfred Perlstein 30319c46d8cSEdward Tomasz Napierala static int opt_flags; 3048360efbdSAlfred Perlstein static int have_v6 = 1; 3058360efbdSAlfred Perlstein 30619c46d8cSEdward Tomasz Napierala static int v4root_phase = 0; 30719c46d8cSEdward Tomasz Napierala static char v4root_dirpath[PATH_MAX + 1]; 3080f0869bcSRick Macklem static struct exportlist *v4root_ep = NULL; 30919c46d8cSEdward Tomasz Napierala static int has_publicfh = 0; 3100f0869bcSRick Macklem static int has_set_publicfh = 0; 311bcc1d071SRick Macklem 31219c46d8cSEdward Tomasz Napierala static struct pidfh *pfh = NULL; 31360caaee2SIan Dowse /* Bits for opt_flags above */ 3148fae3551SRodney W. Grimes #define OP_MAPROOT 0x01 3158fae3551SRodney W. Grimes #define OP_MAPALL 0x02 31691196234SPeter Wemm /* 0x4 free */ 3178fae3551SRodney W. Grimes #define OP_MASK 0x08 3188fae3551SRodney W. Grimes #define OP_NET 0x10 3198fae3551SRodney W. Grimes #define OP_ALLDIRS 0x40 32060caaee2SIan Dowse #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 321288fa14aSJoerg Wunsch #define OP_QUIET 0x100 3228360efbdSAlfred Perlstein #define OP_MASKLEN 0x200 323a9148abdSDoug Rabson #define OP_SEC 0x400 3248fae3551SRodney W. Grimes 3258fae3551SRodney W. Grimes #ifdef DEBUG 32619c46d8cSEdward Tomasz Napierala static int debug = 1; 32719c46d8cSEdward Tomasz Napierala static void SYSLOG(int, const char *, ...) __printflike(2, 3); 3288fae3551SRodney W. Grimes #define syslog SYSLOG 3298fae3551SRodney W. Grimes #else 33019c46d8cSEdward Tomasz Napierala static int debug = 0; 3318fae3551SRodney W. Grimes #endif 3328fae3551SRodney W. Grimes 3338fae3551SRodney W. Grimes /* 3340f0869bcSRick Macklem * The LOGDEBUG() syslog() calls are always compiled into the daemon. 3350f0869bcSRick Macklem * To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty. 3360f0869bcSRick Macklem * To disable the logging, just delete the file at _PATH_MOUNTDDEBUG. 3370f0869bcSRick Macklem */ 3380f0869bcSRick Macklem static int logdebug = 0; 3390f0869bcSRick Macklem #define LOGDEBUG(format, ...) \ 3400f0869bcSRick Macklem (logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0) 3410f0869bcSRick Macklem 3420f0869bcSRick Macklem /* 343b875c2e9SJosh Paetzel * Similar to strsep(), but it allows for quoted strings 344b875c2e9SJosh Paetzel * and escaped characters. 345b875c2e9SJosh Paetzel * 346b875c2e9SJosh Paetzel * It returns the string (or NULL, if *stringp is NULL), 347b875c2e9SJosh Paetzel * which is a de-quoted version of the string if necessary. 348b875c2e9SJosh Paetzel * 349b875c2e9SJosh Paetzel * It modifies *stringp in place. 350b875c2e9SJosh Paetzel */ 351b875c2e9SJosh Paetzel static char * 352b875c2e9SJosh Paetzel strsep_quote(char **stringp, const char *delim) 353b875c2e9SJosh Paetzel { 354b875c2e9SJosh Paetzel char *srcptr, *dstptr, *retval; 355b875c2e9SJosh Paetzel char quot = 0; 356b875c2e9SJosh Paetzel 357b875c2e9SJosh Paetzel if (stringp == NULL || *stringp == NULL) 358b875c2e9SJosh Paetzel return (NULL); 359b875c2e9SJosh Paetzel 360b875c2e9SJosh Paetzel srcptr = dstptr = retval = *stringp; 361b875c2e9SJosh Paetzel 362b875c2e9SJosh Paetzel while (*srcptr) { 363b875c2e9SJosh Paetzel /* 364b875c2e9SJosh Paetzel * We're looking for several edge cases here. 365b875c2e9SJosh Paetzel * First: if we're in quote state (quot != 0), 366b875c2e9SJosh Paetzel * then we ignore the delim characters, but otherwise 367b875c2e9SJosh Paetzel * process as normal, unless it is the quote character. 368b875c2e9SJosh Paetzel * Second: if the current character is a backslash, 369b875c2e9SJosh Paetzel * we take the next character as-is, without checking 370b875c2e9SJosh Paetzel * for delim, quote, or backslash. Exception: if the 371b875c2e9SJosh Paetzel * next character is a NUL, that's the end of the string. 372b875c2e9SJosh Paetzel * Third: if the character is a quote character, we toggle 373b875c2e9SJosh Paetzel * quote state. 374b875c2e9SJosh Paetzel * Otherwise: check the current character for NUL, or 375b875c2e9SJosh Paetzel * being in delim, and end the string if either is true. 376b875c2e9SJosh Paetzel */ 377b875c2e9SJosh Paetzel if (*srcptr == '\\') { 378b875c2e9SJosh Paetzel srcptr++; 379b875c2e9SJosh Paetzel /* 380b875c2e9SJosh Paetzel * The edge case here is if the next character 381b875c2e9SJosh Paetzel * is NUL, we want to stop processing. But if 382b875c2e9SJosh Paetzel * it's not NUL, then we simply want to copy it. 383b875c2e9SJosh Paetzel */ 384b875c2e9SJosh Paetzel if (*srcptr) { 385b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 386b875c2e9SJosh Paetzel } 387b875c2e9SJosh Paetzel continue; 388b875c2e9SJosh Paetzel } 389b875c2e9SJosh Paetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 390b875c2e9SJosh Paetzel quot = *srcptr++; 391b875c2e9SJosh Paetzel continue; 392b875c2e9SJosh Paetzel } 393b875c2e9SJosh Paetzel if (quot && *srcptr == quot) { 394b875c2e9SJosh Paetzel /* End of the quoted part */ 395b875c2e9SJosh Paetzel quot = 0; 396b875c2e9SJosh Paetzel srcptr++; 397b875c2e9SJosh Paetzel continue; 398b875c2e9SJosh Paetzel } 399b875c2e9SJosh Paetzel if (!quot && strchr(delim, *srcptr)) 400b875c2e9SJosh Paetzel break; 401b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 402b875c2e9SJosh Paetzel } 403b875c2e9SJosh Paetzel 404b875c2e9SJosh Paetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 4054ae6e084SAlexander Motin *dstptr = 0; /* Terminate the string */ 406b875c2e9SJosh Paetzel return (retval); 407b875c2e9SJosh Paetzel } 408b875c2e9SJosh Paetzel 409b875c2e9SJosh Paetzel /* 4108fae3551SRodney W. Grimes * Mountd server for NFS mount protocol as described in: 4118fae3551SRodney W. Grimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 4128fae3551SRodney W. Grimes * The optional arguments are the exports file name 4138fae3551SRodney W. Grimes * default: _PATH_EXPORTS 4148fae3551SRodney W. Grimes * and "-n" to allow nonroot mount. 4158fae3551SRodney W. Grimes */ 4168fae3551SRodney W. Grimes int 417a7a7d96cSPhilippe Charnier main(int argc, char **argv) 4188fae3551SRodney W. Grimes { 41969d65572SIan Dowse fd_set readfds; 420d11e3645SMatteo Riondato struct netconfig *nconf; 421d11e3645SMatteo Riondato char *endptr, **hosts_bak; 422d11e3645SMatteo Riondato void *nc_handle; 423a032b226SPawel Jakub Dawidek pid_t otherpid; 424d11e3645SMatteo Riondato in_port_t svcport; 425d11e3645SMatteo Riondato int c, k, s; 426bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE; 4278fb6ad5dSRick Macklem int attempt_cnt, port_len, port_pos, ret; 4288fb6ad5dSRick Macklem char **port_list; 4297674d489SRick Macklem uint64_t curtime, nexttime; 4307674d489SRick Macklem struct timeval tv; 4317674d489SRick Macklem struct timespec tp; 432bde6f938SRick Macklem sigset_t sig_mask, sighup_mask; 433bde6f938SRick Macklem int enable_rpcbind; 4348360efbdSAlfred Perlstein 435bde6f938SRick Macklem enable_rpcbind = 1; 43601709abfSIan Dowse /* Check that another mountd isn't already running. */ 4378b28aef2SPawel Jakub Dawidek pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 438a032b226SPawel Jakub Dawidek if (pfh == NULL) { 439a032b226SPawel Jakub Dawidek if (errno == EEXIST) 440a032b226SPawel Jakub Dawidek errx(1, "mountd already running, pid: %d.", otherpid); 441a032b226SPawel Jakub Dawidek warn("cannot open or create pidfile"); 442a032b226SPawel Jakub Dawidek } 4438360efbdSAlfred Perlstein 4448360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 4458360efbdSAlfred Perlstein if (s < 0) 4468360efbdSAlfred Perlstein have_v6 = 0; 4478360efbdSAlfred Perlstein else 4488360efbdSAlfred Perlstein close(s); 4498fae3551SRodney W. Grimes 450bde6f938SRick Macklem while ((c = getopt(argc, argv, "2deh:lnp:RrS")) != -1) 4518fae3551SRodney W. Grimes switch (c) { 4522a66cfc5SDoug Rabson case '2': 4532a66cfc5SDoug Rabson force_v2 = 1; 4542a66cfc5SDoug Rabson break; 4552179ae1eSRick Macklem case 'e': 4562a85df8cSRick Macklem /* now a no-op, since this is the default */ 457bcc1d071SRick Macklem break; 458a62dc406SDoug Rabson case 'n': 459a62dc406SDoug Rabson resvport_only = 0; 460a62dc406SDoug Rabson break; 461bde6f938SRick Macklem case 'R': 462bde6f938SRick Macklem /* Do not support Mount protocol */ 463bde6f938SRick Macklem enable_rpcbind = 0; 464bde6f938SRick Macklem break; 465a62dc406SDoug Rabson case 'r': 466a62dc406SDoug Rabson dir_only = 0; 467a62dc406SDoug Rabson break; 4686444ef3bSPoul-Henning Kamp case 'd': 4696444ef3bSPoul-Henning Kamp debug = debug ? 0 : 1; 4706444ef3bSPoul-Henning Kamp break; 471f51631d7SGuido van Rooij case 'l': 472c903443aSPeter Wemm dolog = 1; 473f51631d7SGuido van Rooij break; 474c203da27SBruce M Simpson case 'p': 475c203da27SBruce M Simpson endptr = NULL; 476c203da27SBruce M Simpson svcport = (in_port_t)strtoul(optarg, &endptr, 10); 477c203da27SBruce M Simpson if (endptr == NULL || *endptr != '\0' || 478c203da27SBruce M Simpson svcport == 0 || svcport >= IPPORT_MAX) 479c203da27SBruce M Simpson usage(); 480d11e3645SMatteo Riondato svcport_str = strdup(optarg); 481d11e3645SMatteo Riondato break; 482d11e3645SMatteo Riondato case 'h': 483d11e3645SMatteo Riondato ++nhosts; 484d11e3645SMatteo Riondato hosts_bak = hosts; 485d11e3645SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 486d11e3645SMatteo Riondato if (hosts_bak == NULL) { 487d11e3645SMatteo Riondato if (hosts != NULL) { 488d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 489d11e3645SMatteo Riondato free(hosts[k]); 490d11e3645SMatteo Riondato free(hosts); 491d11e3645SMatteo Riondato out_of_mem(); 492d11e3645SMatteo Riondato } 493d11e3645SMatteo Riondato } 494d11e3645SMatteo Riondato hosts = hosts_bak; 495d11e3645SMatteo Riondato hosts[nhosts - 1] = strdup(optarg); 496d11e3645SMatteo Riondato if (hosts[nhosts - 1] == NULL) { 497d11e3645SMatteo Riondato for (k = 0; k < (nhosts - 1); k++) 498d11e3645SMatteo Riondato free(hosts[k]); 499d11e3645SMatteo Riondato free(hosts); 500d11e3645SMatteo Riondato out_of_mem(); 501d11e3645SMatteo Riondato } 502c203da27SBruce M Simpson break; 503c548eb5cSRick Macklem case 'S': 504c548eb5cSRick Macklem suspend_nfsd = 1; 505c548eb5cSRick Macklem break; 5068fae3551SRodney W. Grimes default: 50774853402SPhilippe Charnier usage(); 50880c7cc1cSPedro F. Giffuni } 509bde6f938SRick Macklem if (enable_rpcbind == 0) { 510bde6f938SRick Macklem if (svcport_str != NULL) { 511bde6f938SRick Macklem warnx("-p option not compatible with -R, ignored"); 512bde6f938SRick Macklem free(svcport_str); 513bde6f938SRick Macklem svcport_str = NULL; 514bde6f938SRick Macklem } 515bde6f938SRick Macklem if (nhosts > 0) { 516bde6f938SRick Macklem warnx("-h option not compatible with -R, ignored"); 517bde6f938SRick Macklem for (k = 0; k < nhosts; k++) 518bde6f938SRick Macklem free(hosts[k]); 519bde6f938SRick Macklem free(hosts); 520bde6f938SRick Macklem hosts = NULL; 521bde6f938SRick Macklem nhosts = 0; 522bde6f938SRick Macklem } 523bde6f938SRick Macklem } 524bcc1d071SRick Macklem 525bcc1d071SRick Macklem if (modfind("nfsd") < 0) { 526bcc1d071SRick Macklem /* Not present in kernel, try loading it */ 527bcc1d071SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 528bcc1d071SRick Macklem errx(1, "NFS server is not available"); 529bcc1d071SRick Macklem } 530bcc1d071SRick Macklem 5318fae3551SRodney W. Grimes argc -= optind; 5328fae3551SRodney W. Grimes argv += optind; 53396968c22SPawel Jakub Dawidek if (argc > 0) 53496968c22SPawel Jakub Dawidek exnames = argv; 53596968c22SPawel Jakub Dawidek else 53696968c22SPawel Jakub Dawidek exnames = exnames_default; 5378fae3551SRodney W. Grimes openlog("mountd", LOG_PID, LOG_DAEMON); 5388fae3551SRodney W. Grimes if (debug) 53974853402SPhilippe Charnier warnx("getting export list"); 5400f0869bcSRick Macklem get_exportlist(0); 5418fae3551SRodney W. Grimes if (debug) 54274853402SPhilippe Charnier warnx("getting mount list"); 5438fae3551SRodney W. Grimes get_mountlist(); 5448fae3551SRodney W. Grimes if (debug) 54574853402SPhilippe Charnier warnx("here we go"); 5468fae3551SRodney W. Grimes if (debug == 0) { 5478fae3551SRodney W. Grimes daemon(0, 0); 5488fae3551SRodney W. Grimes signal(SIGINT, SIG_IGN); 5498fae3551SRodney W. Grimes signal(SIGQUIT, SIG_IGN); 5508fae3551SRodney W. Grimes } 55169d65572SIan Dowse signal(SIGHUP, huphandler); 5528360efbdSAlfred Perlstein signal(SIGTERM, terminate); 55309fc9dc6SCraig Rodrigues signal(SIGPIPE, SIG_IGN); 554a032b226SPawel Jakub Dawidek 555a032b226SPawel Jakub Dawidek pidfile_write(pfh); 556a032b226SPawel Jakub Dawidek 557bde6f938SRick Macklem if (enable_rpcbind != 0) { 5580775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 5590775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 560bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 561bcb53b16SMartin Blapp 562c6e5e158SGuido van Rooij if (!resvport_only) { 5635ebee88dSRick Macklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL, 5644a0785aaSPeter Wemm &resvport_only, sizeof(resvport_only)) != 0 && 5654a0785aaSPeter Wemm errno != ENOENT) { 566394da4c1SGuido van Rooij syslog(LOG_ERR, "sysctl: %m"); 567394da4c1SGuido van Rooij exit(1); 568394da4c1SGuido van Rooij } 569c6e5e158SGuido van Rooij } 570c203da27SBruce M Simpson 571d11e3645SMatteo Riondato /* 572d11e3645SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to 573bde6f938SRick Macklem * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added 574bde6f938SRick Macklem * to the list. 575d11e3645SMatteo Riondato */ 576d11e3645SMatteo Riondato if (nhosts == 0) { 577c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *)); 578d11e3645SMatteo Riondato if (hosts == NULL) 579d11e3645SMatteo Riondato out_of_mem(); 580d11e3645SMatteo Riondato hosts[0] = "*"; 581d11e3645SMatteo Riondato nhosts = 1; 582d11e3645SMatteo Riondato } else { 583d11e3645SMatteo Riondato hosts_bak = hosts; 584d11e3645SMatteo Riondato if (have_v6) { 585d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) * 586d11e3645SMatteo Riondato sizeof(char *)); 587d11e3645SMatteo Riondato if (hosts_bak == NULL) { 588d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 589d11e3645SMatteo Riondato free(hosts[k]); 590d11e3645SMatteo Riondato free(hosts); 591d11e3645SMatteo Riondato out_of_mem(); 592c203da27SBruce M Simpson } else 593d11e3645SMatteo Riondato hosts = hosts_bak; 594d11e3645SMatteo Riondato nhosts += 2; 595d11e3645SMatteo Riondato hosts[nhosts - 2] = "::1"; 596d11e3645SMatteo Riondato } else { 597bde6f938SRick Macklem hosts_bak = realloc(hosts, (nhosts + 1) * 598bde6f938SRick Macklem sizeof(char *)); 599d11e3645SMatteo Riondato if (hosts_bak == NULL) { 600d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 601d11e3645SMatteo Riondato free(hosts[k]); 602d11e3645SMatteo Riondato free(hosts); 603d11e3645SMatteo Riondato out_of_mem(); 604d11e3645SMatteo Riondato } else { 605d11e3645SMatteo Riondato nhosts += 1; 606d11e3645SMatteo Riondato hosts = hosts_bak; 6078fae3551SRodney W. Grimes } 608d11e3645SMatteo Riondato } 6098360efbdSAlfred Perlstein 610d11e3645SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1"; 6118360efbdSAlfred Perlstein } 612bde6f938SRick Macklem } 6138360efbdSAlfred Perlstein 6148fb6ad5dSRick Macklem attempt_cnt = 1; 6158fb6ad5dSRick Macklem sock_fdcnt = 0; 6168fb6ad5dSRick Macklem sock_fd = NULL; 6178fb6ad5dSRick Macklem port_list = NULL; 6188fb6ad5dSRick Macklem port_len = 0; 619bde6f938SRick Macklem if (enable_rpcbind != 0) { 620d11e3645SMatteo Riondato nc_handle = setnetconfig(); 621d11e3645SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) { 622d11e3645SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) { 623d11e3645SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 624d11e3645SMatteo Riondato "inet6") == 0) { 625d11e3645SMatteo Riondato /* DO NOTHING */ 6268fb6ad5dSRick Macklem } else { 6278fb6ad5dSRick Macklem ret = create_service(nconf); 6288fb6ad5dSRick Macklem if (ret == 1) 6298fb6ad5dSRick Macklem /* Ignore this call */ 6308fb6ad5dSRick Macklem continue; 6318fb6ad5dSRick Macklem if (ret < 0) { 6328fb6ad5dSRick Macklem /* 633bde6f938SRick Macklem * Failed to bind port, so close 634bde6f938SRick Macklem * off all sockets created and 635bde6f938SRick Macklem * try again if the port# was 636bde6f938SRick Macklem * dynamically assigned via 637bde6f938SRick Macklem * bind(2). 6388fb6ad5dSRick Macklem */ 6398fb6ad5dSRick Macklem clearout_service(); 6408fb6ad5dSRick Macklem if (mallocd_svcport != 0 && 641bde6f938SRick Macklem attempt_cnt < 642bde6f938SRick Macklem GETPORT_MAXTRY) { 6438fb6ad5dSRick Macklem free(svcport_str); 6448fb6ad5dSRick Macklem svcport_str = NULL; 6458fb6ad5dSRick Macklem mallocd_svcport = 0; 6468fb6ad5dSRick Macklem } else { 6478fb6ad5dSRick Macklem errno = EADDRINUSE; 6488fb6ad5dSRick Macklem syslog(LOG_ERR, 649bde6f938SRick Macklem "bindresvport_sa:" 650bde6f938SRick Macklem " %m"); 6518fb6ad5dSRick Macklem exit(1); 6528fb6ad5dSRick Macklem } 6538fb6ad5dSRick Macklem 654bde6f938SRick Macklem /* 655bde6f938SRick Macklem * Start over at the first 656bde6f938SRick Macklem * service. 657bde6f938SRick Macklem */ 6588fb6ad5dSRick Macklem free(sock_fd); 6598fb6ad5dSRick Macklem sock_fdcnt = 0; 6608fb6ad5dSRick Macklem sock_fd = NULL; 6618fb6ad5dSRick Macklem nc_handle = setnetconfig(); 6628fb6ad5dSRick Macklem attempt_cnt++; 6638fb6ad5dSRick Macklem } else if (mallocd_svcport != 0 && 6648fb6ad5dSRick Macklem attempt_cnt == GETPORT_MAXTRY) { 6658fb6ad5dSRick Macklem /* 6668fb6ad5dSRick Macklem * For the last attempt, allow 667bde6f938SRick Macklem * different port #s for each 668bde6f938SRick Macklem * nconf by saving the 669bde6f938SRick Macklem * svcport_str setting it back 670bde6f938SRick Macklem * to NULL. 6718fb6ad5dSRick Macklem */ 6728fb6ad5dSRick Macklem port_list = realloc(port_list, 673bde6f938SRick Macklem (port_len + 1) * 674bde6f938SRick Macklem sizeof(char *)); 6758fb6ad5dSRick Macklem if (port_list == NULL) 6768fb6ad5dSRick Macklem out_of_mem(); 677bde6f938SRick Macklem port_list[port_len++] = 678bde6f938SRick Macklem svcport_str; 6798fb6ad5dSRick Macklem svcport_str = NULL; 6808fb6ad5dSRick Macklem mallocd_svcport = 0; 6818fb6ad5dSRick Macklem } 6828fb6ad5dSRick Macklem } 6838fb6ad5dSRick Macklem } 6848fb6ad5dSRick Macklem } 6858fb6ad5dSRick Macklem 6868fb6ad5dSRick Macklem /* 6878fb6ad5dSRick Macklem * Successfully bound the ports, so call complete_service() to 6888fb6ad5dSRick Macklem * do the rest of the setup on the service(s). 6898fb6ad5dSRick Macklem */ 6908fb6ad5dSRick Macklem sock_fdpos = 0; 6918fb6ad5dSRick Macklem port_pos = 0; 6928fb6ad5dSRick Macklem nc_handle = setnetconfig(); 6938fb6ad5dSRick Macklem while ((nconf = getnetconfig(nc_handle))) { 6948fb6ad5dSRick Macklem if (nconf->nc_flag & NC_VISIBLE) { 6958fb6ad5dSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 6968fb6ad5dSRick Macklem "inet6") == 0) { 6978fb6ad5dSRick Macklem /* DO NOTHING */ 6988fb6ad5dSRick Macklem } else if (port_list != NULL) { 6998fb6ad5dSRick Macklem if (port_pos >= port_len) { 700bde6f938SRick Macklem syslog(LOG_ERR, "too many" 701bde6f938SRick Macklem " port#s"); 7028fb6ad5dSRick Macklem exit(1); 7038fb6ad5dSRick Macklem } 704bde6f938SRick Macklem complete_service(nconf, 705bde6f938SRick Macklem port_list[port_pos++]); 706c203da27SBruce M Simpson } else 7078fb6ad5dSRick Macklem complete_service(nconf, svcport_str); 7088360efbdSAlfred Perlstein } 709d11e3645SMatteo Riondato } 710d11e3645SMatteo Riondato endnetconfig(nc_handle); 7118fb6ad5dSRick Macklem free(sock_fd); 7128fb6ad5dSRick Macklem if (port_list != NULL) { 7138fb6ad5dSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++) 7148fb6ad5dSRick Macklem free(port_list[port_pos]); 7158fb6ad5dSRick Macklem free(port_list); 7168fb6ad5dSRick Macklem } 7178360efbdSAlfred Perlstein 7188360efbdSAlfred Perlstein if (xcreated == 0) { 7198360efbdSAlfred Perlstein syslog(LOG_ERR, "could not create any services"); 7202a66cfc5SDoug Rabson exit(1); 7212a66cfc5SDoug Rabson } 722bde6f938SRick Macklem } 72369d65572SIan Dowse 72469d65572SIan Dowse /* Expand svc_run() here so that we can call get_exportlist(). */ 7257674d489SRick Macklem curtime = nexttime = 0; 7267674d489SRick Macklem sigemptyset(&sighup_mask); 7277674d489SRick Macklem sigaddset(&sighup_mask, SIGHUP); 72869d65572SIan Dowse for (;;) { 7297674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp); 7307674d489SRick Macklem curtime = tp.tv_sec; 7317674d489SRick Macklem curtime = curtime * 1000000 + tp.tv_nsec / 1000; 732bde6f938SRick Macklem sigprocmask(SIG_BLOCK, &sighup_mask, &sig_mask); 7337674d489SRick Macklem if (got_sighup && curtime >= nexttime) { 73469d65572SIan Dowse got_sighup = 0; 7357674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 7367674d489SRick Macklem get_exportlist(1); 7377674d489SRick Macklem clock_gettime(CLOCK_MONOTONIC, &tp); 7387674d489SRick Macklem nexttime = tp.tv_sec; 7397674d489SRick Macklem nexttime = nexttime * 1000000 + tp.tv_nsec / 1000 + 7407674d489SRick Macklem RELOADDELAY; 7417674d489SRick Macklem } else 7427674d489SRick Macklem sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 7437674d489SRick Macklem 7447674d489SRick Macklem /* 7457674d489SRick Macklem * If a reload is pending, poll for received request(s), 7467674d489SRick Macklem * otherwise set a RELOADDELAY timeout, since a SIGHUP 7477674d489SRick Macklem * could be processed between the got_sighup test and 7487674d489SRick Macklem * the select() system call. 7497674d489SRick Macklem */ 7507674d489SRick Macklem tv.tv_sec = 0; 7517674d489SRick Macklem if (got_sighup) 7527674d489SRick Macklem tv.tv_usec = 0; 7537674d489SRick Macklem else 7547674d489SRick Macklem tv.tv_usec = RELOADDELAY; 755bde6f938SRick Macklem if (enable_rpcbind != 0) { 75669d65572SIan Dowse readfds = svc_fdset; 757bde6f938SRick Macklem switch (select(svc_maxfd + 1, &readfds, NULL, NULL, 758bde6f938SRick Macklem &tv)) { 75969d65572SIan Dowse case -1: 7607674d489SRick Macklem if (errno == EINTR) { 7617674d489SRick Macklem /* Allow a reload now. */ 7627674d489SRick Macklem nexttime = 0; 76369d65572SIan Dowse continue; 7647674d489SRick Macklem } 76569d65572SIan Dowse syslog(LOG_ERR, "mountd died: select: %m"); 76674853402SPhilippe Charnier exit(1); 76769d65572SIan Dowse case 0: 7687674d489SRick Macklem /* Allow a reload now. */ 7697674d489SRick Macklem nexttime = 0; 77069d65572SIan Dowse continue; 77169d65572SIan Dowse default: 77269d65572SIan Dowse svc_getreqset(&readfds); 77369d65572SIan Dowse } 774bde6f938SRick Macklem } else { 775bde6f938SRick Macklem /* Simply wait for a signal. */ 776bde6f938SRick Macklem sigsuspend(&sig_mask); 777bde6f938SRick Macklem } 77869d65572SIan Dowse } 77974853402SPhilippe Charnier } 78074853402SPhilippe Charnier 781d11e3645SMatteo Riondato /* 782d11e3645SMatteo Riondato * This routine creates and binds sockets on the appropriate 7838fb6ad5dSRick Macklem * addresses. It gets called one time for each transport. 784afc55510SGordon Bergling * It returns 0 upon success, 1 for ignore the call and -1 to indicate 7858fb6ad5dSRick Macklem * bind failed with EADDRINUSE. 7868fb6ad5dSRick Macklem * Any file descriptors that have been created are stored in sock_fd and 7878fb6ad5dSRick Macklem * the total count of them is maintained in sock_fdcnt. 788d11e3645SMatteo Riondato */ 7898fb6ad5dSRick Macklem static int 790d11e3645SMatteo Riondato create_service(struct netconfig *nconf) 791d11e3645SMatteo Riondato { 792d11e3645SMatteo Riondato struct addrinfo hints, *res = NULL; 793d11e3645SMatteo Riondato struct sockaddr_in *sin; 794d11e3645SMatteo Riondato struct sockaddr_in6 *sin6; 795d11e3645SMatteo Riondato struct __rpc_sockinfo si; 796d11e3645SMatteo Riondato int aicode; 797d11e3645SMatteo Riondato int fd; 798d11e3645SMatteo Riondato int nhostsbak; 799d11e3645SMatteo Riondato int one = 1; 800d11e3645SMatteo Riondato int r; 801d11e3645SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 8028fb6ad5dSRick Macklem int mallocd_res; 803d11e3645SMatteo Riondato 804d11e3645SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) && 805d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) && 806d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD)) 8078fb6ad5dSRick Macklem return (1); /* not my type */ 808d11e3645SMatteo Riondato 809d11e3645SMatteo Riondato /* 810d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 811d11e3645SMatteo Riondato */ 812d11e3645SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) { 813d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s", 814d11e3645SMatteo Riondato nconf->nc_netid); 8158fb6ad5dSRick Macklem return (1); 816d11e3645SMatteo Riondato } 817d11e3645SMatteo Riondato 818d11e3645SMatteo Riondato /* Get mountd's address on this transport */ 819d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 820d11e3645SMatteo Riondato hints.ai_family = si.si_af; 821d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 822d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 823d11e3645SMatteo Riondato 824d11e3645SMatteo Riondato /* 825d11e3645SMatteo Riondato * Bind to specific IPs if asked to 826d11e3645SMatteo Riondato */ 827d11e3645SMatteo Riondato nhostsbak = nhosts; 828d11e3645SMatteo Riondato while (nhostsbak > 0) { 829d11e3645SMatteo Riondato --nhostsbak; 8308fb6ad5dSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 8318fb6ad5dSRick Macklem if (sock_fd == NULL) 8328fb6ad5dSRick Macklem out_of_mem(); 8338fb6ad5dSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 8348fb6ad5dSRick Macklem mallocd_res = 0; 8358fb6ad5dSRick Macklem 8369745de4cSRyan Stone hints.ai_flags = AI_PASSIVE; 8379745de4cSRyan Stone 838d11e3645SMatteo Riondato /* 839d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 840d11e3645SMatteo Riondato */ 841d11e3645SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) { 842d11e3645SMatteo Riondato int non_fatal = 0; 843a5752d55SKevin Lo if (errno == EAFNOSUPPORT && 844d11e3645SMatteo Riondato nconf->nc_semantics != NC_TPI_CLTS) 845d11e3645SMatteo Riondato non_fatal = 1; 846d11e3645SMatteo Riondato 847d11e3645SMatteo Riondato syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 848d11e3645SMatteo Riondato "cannot create socket for %s", nconf->nc_netid); 8498fb6ad5dSRick Macklem if (non_fatal != 0) 8508fb6ad5dSRick Macklem continue; 8518fb6ad5dSRick Macklem exit(1); 852d11e3645SMatteo Riondato } 853d11e3645SMatteo Riondato 854d11e3645SMatteo Riondato switch (hints.ai_family) { 855d11e3645SMatteo Riondato case AF_INET: 856d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 857d11e3645SMatteo Riondato host_addr) == 1) { 8588fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 859d11e3645SMatteo Riondato } else { 860d11e3645SMatteo Riondato /* 861d11e3645SMatteo Riondato * Skip if we have an AF_INET6 address. 862d11e3645SMatteo Riondato */ 863d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 864d11e3645SMatteo Riondato host_addr) == 1) { 865d11e3645SMatteo Riondato close(fd); 866d11e3645SMatteo Riondato continue; 867d11e3645SMatteo Riondato } 868d11e3645SMatteo Riondato } 869d11e3645SMatteo Riondato break; 870d11e3645SMatteo Riondato case AF_INET6: 871d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 872d11e3645SMatteo Riondato host_addr) == 1) { 8738fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 874d11e3645SMatteo Riondato } else { 875d11e3645SMatteo Riondato /* 876d11e3645SMatteo Riondato * Skip if we have an AF_INET address. 877d11e3645SMatteo Riondato */ 878d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 879d11e3645SMatteo Riondato host_addr) == 1) { 880d11e3645SMatteo Riondato close(fd); 881d11e3645SMatteo Riondato continue; 882d11e3645SMatteo Riondato } 883d11e3645SMatteo Riondato } 884d11e3645SMatteo Riondato 885d11e3645SMatteo Riondato /* 886d11e3645SMatteo Riondato * We're doing host-based access checks here, so don't 887d11e3645SMatteo Riondato * allow v4-in-v6 to confuse things. The kernel will 888d11e3645SMatteo Riondato * disable it by default on NFS sockets too. 889d11e3645SMatteo Riondato */ 890d11e3645SMatteo Riondato if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 891d11e3645SMatteo Riondato sizeof one) < 0) { 892d11e3645SMatteo Riondato syslog(LOG_ERR, 893d11e3645SMatteo Riondato "can't disable v4-in-v6 on IPv6 socket"); 894d11e3645SMatteo Riondato exit(1); 895d11e3645SMatteo Riondato } 896d11e3645SMatteo Riondato break; 897d11e3645SMatteo Riondato default: 898d11e3645SMatteo Riondato break; 899d11e3645SMatteo Riondato } 900d11e3645SMatteo Riondato 901d11e3645SMatteo Riondato /* 902d11e3645SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY 903d11e3645SMatteo Riondato */ 904d11e3645SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) { 905d11e3645SMatteo Riondato if (svcport_str == NULL) { 906d11e3645SMatteo Riondato res = malloc(sizeof(struct addrinfo)); 907d11e3645SMatteo Riondato if (res == NULL) 908d11e3645SMatteo Riondato out_of_mem(); 9098fb6ad5dSRick Macklem mallocd_res = 1; 910d11e3645SMatteo Riondato res->ai_flags = hints.ai_flags; 911d11e3645SMatteo Riondato res->ai_family = hints.ai_family; 912d11e3645SMatteo Riondato res->ai_protocol = hints.ai_protocol; 913d11e3645SMatteo Riondato switch (res->ai_family) { 914d11e3645SMatteo Riondato case AF_INET: 915d11e3645SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in)); 916d11e3645SMatteo Riondato if (sin == NULL) 917d11e3645SMatteo Riondato out_of_mem(); 918d11e3645SMatteo Riondato sin->sin_family = AF_INET; 919d11e3645SMatteo Riondato sin->sin_port = htons(0); 920d11e3645SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY); 921d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin; 922d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 9238fb6ad5dSRick Macklem sizeof(struct sockaddr_in); 924d11e3645SMatteo Riondato break; 925d11e3645SMatteo Riondato case AF_INET6: 926d11e3645SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6)); 92789ca9145SSimon L. B. Nielsen if (sin6 == NULL) 928d11e3645SMatteo Riondato out_of_mem(); 929d11e3645SMatteo Riondato sin6->sin6_family = AF_INET6; 930d11e3645SMatteo Riondato sin6->sin6_port = htons(0); 931d11e3645SMatteo Riondato sin6->sin6_addr = in6addr_any; 932d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6; 933d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 9348fb6ad5dSRick Macklem sizeof(struct sockaddr_in6); 935d11e3645SMatteo Riondato break; 936d11e3645SMatteo Riondato default: 9378fb6ad5dSRick Macklem syslog(LOG_ERR, "bad addr fam %d", 9388fb6ad5dSRick Macklem res->ai_family); 9398fb6ad5dSRick Macklem exit(1); 940d11e3645SMatteo Riondato } 941d11e3645SMatteo Riondato } else { 942d11e3645SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str, 943d11e3645SMatteo Riondato &hints, &res)) != 0) { 944d11e3645SMatteo Riondato syslog(LOG_ERR, 945d11e3645SMatteo Riondato "cannot get local address for %s: %s", 946d11e3645SMatteo Riondato nconf->nc_netid, 947d11e3645SMatteo Riondato gai_strerror(aicode)); 9488fb6ad5dSRick Macklem close(fd); 949d11e3645SMatteo Riondato continue; 950d11e3645SMatteo Riondato } 951d11e3645SMatteo Riondato } 952d11e3645SMatteo Riondato } else { 953d11e3645SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 954d11e3645SMatteo Riondato &hints, &res)) != 0) { 955d11e3645SMatteo Riondato syslog(LOG_ERR, 956d11e3645SMatteo Riondato "cannot get local address for %s: %s", 957d11e3645SMatteo Riondato nconf->nc_netid, gai_strerror(aicode)); 9588fb6ad5dSRick Macklem close(fd); 959d11e3645SMatteo Riondato continue; 960d11e3645SMatteo Riondato } 961d11e3645SMatteo Riondato } 962d11e3645SMatteo Riondato 9638fb6ad5dSRick Macklem /* Store the fd. */ 9648fb6ad5dSRick Macklem sock_fd[sock_fdcnt - 1] = fd; 9658fb6ad5dSRick Macklem 9668fb6ad5dSRick Macklem /* Now, attempt the bind. */ 967d11e3645SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr); 968d11e3645SMatteo Riondato if (r != 0) { 9698fb6ad5dSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 9708fb6ad5dSRick Macklem if (mallocd_res != 0) { 9718fb6ad5dSRick Macklem free(res->ai_addr); 9728fb6ad5dSRick Macklem free(res); 9738fb6ad5dSRick Macklem } else 9748fb6ad5dSRick Macklem freeaddrinfo(res); 9758fb6ad5dSRick Macklem return (-1); 9768fb6ad5dSRick Macklem } 977d11e3645SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m"); 978d11e3645SMatteo Riondato exit(1); 979d11e3645SMatteo Riondato } 980d11e3645SMatteo Riondato 9818fb6ad5dSRick Macklem if (svcport_str == NULL) { 9828fb6ad5dSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 9838fb6ad5dSRick Macklem if (svcport_str == NULL) 9848fb6ad5dSRick Macklem out_of_mem(); 9858fb6ad5dSRick Macklem mallocd_svcport = 1; 9868fb6ad5dSRick Macklem 9878fb6ad5dSRick Macklem if (getnameinfo(res->ai_addr, 9888fb6ad5dSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 9898fb6ad5dSRick Macklem svcport_str, NI_MAXSERV * sizeof(char), 9908fb6ad5dSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV)) 9918fb6ad5dSRick Macklem errx(1, "Cannot get port number"); 9928fb6ad5dSRick Macklem } 9938fb6ad5dSRick Macklem if (mallocd_res != 0) { 9948fb6ad5dSRick Macklem free(res->ai_addr); 9958fb6ad5dSRick Macklem free(res); 9968fb6ad5dSRick Macklem } else 9978fb6ad5dSRick Macklem freeaddrinfo(res); 9988fb6ad5dSRick Macklem res = NULL; 9998fb6ad5dSRick Macklem } 10008fb6ad5dSRick Macklem return (0); 10018fb6ad5dSRick Macklem } 10028fb6ad5dSRick Macklem 10038fb6ad5dSRick Macklem /* 10048fb6ad5dSRick Macklem * Called after all the create_service() calls have succeeded, to complete 10058fb6ad5dSRick Macklem * the setup and registration. 10068fb6ad5dSRick Macklem */ 10078fb6ad5dSRick Macklem static void 10088fb6ad5dSRick Macklem complete_service(struct netconfig *nconf, char *port_str) 10098fb6ad5dSRick Macklem { 10108fb6ad5dSRick Macklem struct addrinfo hints, *res = NULL; 10118fb6ad5dSRick Macklem struct __rpc_sockinfo si; 10128fb6ad5dSRick Macklem struct netbuf servaddr; 10138fb6ad5dSRick Macklem SVCXPRT *transp = NULL; 10148fb6ad5dSRick Macklem int aicode, fd, nhostsbak; 10158fb6ad5dSRick Macklem int registered = 0; 10168fb6ad5dSRick Macklem 10178fb6ad5dSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 10188fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) && 10198fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 10208fb6ad5dSRick Macklem return; /* not my type */ 10218fb6ad5dSRick Macklem 10228fb6ad5dSRick Macklem /* 10238fb6ad5dSRick Macklem * XXX - using RPC library internal functions. 10248fb6ad5dSRick Macklem */ 10258fb6ad5dSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 10268fb6ad5dSRick Macklem syslog(LOG_ERR, "cannot get information for %s", 10278fb6ad5dSRick Macklem nconf->nc_netid); 10288fb6ad5dSRick Macklem return; 10298fb6ad5dSRick Macklem } 10308fb6ad5dSRick Macklem 10318fb6ad5dSRick Macklem nhostsbak = nhosts; 10328fb6ad5dSRick Macklem while (nhostsbak > 0) { 10338fb6ad5dSRick Macklem --nhostsbak; 10348fb6ad5dSRick Macklem if (sock_fdpos >= sock_fdcnt) { 10358fb6ad5dSRick Macklem /* Should never happen. */ 10368fb6ad5dSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's"); 10378fb6ad5dSRick Macklem return; 10388fb6ad5dSRick Macklem } 10398fb6ad5dSRick Macklem fd = sock_fd[sock_fdpos++]; 10408fb6ad5dSRick Macklem if (fd < 0) 10418fb6ad5dSRick Macklem continue; 10428fb6ad5dSRick Macklem 104393840fdeSSean Eric Fagan /* 104493840fdeSSean Eric Fagan * Using -1 tells listen(2) to use 104593840fdeSSean Eric Fagan * kern.ipc.soacceptqueue for the backlog. 104693840fdeSSean Eric Fagan */ 1047d11e3645SMatteo Riondato if (nconf->nc_semantics != NC_TPI_CLTS) 104893840fdeSSean Eric Fagan listen(fd, -1); 1049d11e3645SMatteo Riondato 1050d11e3645SMatteo Riondato if (nconf->nc_semantics == NC_TPI_CLTS ) 1051d11e3645SMatteo Riondato transp = svc_dg_create(fd, 0, 0); 1052d11e3645SMatteo Riondato else 1053d11e3645SMatteo Riondato transp = svc_vc_create(fd, RPC_MAXDATASIZE, 1054d11e3645SMatteo Riondato RPC_MAXDATASIZE); 1055d11e3645SMatteo Riondato 1056d11e3645SMatteo Riondato if (transp != (SVCXPRT *) NULL) { 10570775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 1058d11e3645SMatteo Riondato NULL)) 1059d11e3645SMatteo Riondato syslog(LOG_ERR, 10600775314bSDoug Rabson "can't register %s MOUNTVERS service", 1061d11e3645SMatteo Riondato nconf->nc_netid); 1062d11e3645SMatteo Riondato if (!force_v2) { 10630775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 1064d11e3645SMatteo Riondato mntsrv, NULL)) 1065d11e3645SMatteo Riondato syslog(LOG_ERR, 10660775314bSDoug Rabson "can't register %s MOUNTVERS3 service", 1067d11e3645SMatteo Riondato nconf->nc_netid); 1068d11e3645SMatteo Riondato } 1069d11e3645SMatteo Riondato } else 1070d11e3645SMatteo Riondato syslog(LOG_WARNING, "can't create %s services", 1071d11e3645SMatteo Riondato nconf->nc_netid); 1072d11e3645SMatteo Riondato 1073d11e3645SMatteo Riondato if (registered == 0) { 1074d11e3645SMatteo Riondato registered = 1; 1075d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 1076d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE; 1077d11e3645SMatteo Riondato hints.ai_family = si.si_af; 1078d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 1079d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 1080d11e3645SMatteo Riondato 10818fb6ad5dSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 1082d11e3645SMatteo Riondato &res)) != 0) { 1083d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s", 1084d11e3645SMatteo Riondato gai_strerror(aicode)); 1085d11e3645SMatteo Riondato exit(1); 1086d11e3645SMatteo Riondato } 1087d11e3645SMatteo Riondato 1088d11e3645SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen); 1089d11e3645SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 1090d11e3645SMatteo Riondato servaddr.len = res->ai_addrlen; 1091d11e3645SMatteo Riondato 10920775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 10930775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 1094d11e3645SMatteo Riondato 1095d11e3645SMatteo Riondato xcreated++; 1096d11e3645SMatteo Riondato freeaddrinfo(res); 1097d11e3645SMatteo Riondato } 1098d11e3645SMatteo Riondato } /* end while */ 1099d11e3645SMatteo Riondato } 1100d11e3645SMatteo Riondato 11018fb6ad5dSRick Macklem /* 11028fb6ad5dSRick Macklem * Clear out sockets after a failure to bind one of them, so that the 11038fb6ad5dSRick Macklem * cycle of socket creation/binding can start anew. 11048fb6ad5dSRick Macklem */ 11058fb6ad5dSRick Macklem static void 11068fb6ad5dSRick Macklem clearout_service(void) 11078fb6ad5dSRick Macklem { 11088fb6ad5dSRick Macklem int i; 11098fb6ad5dSRick Macklem 11108fb6ad5dSRick Macklem for (i = 0; i < sock_fdcnt; i++) { 11118fb6ad5dSRick Macklem if (sock_fd[i] >= 0) { 11128fb6ad5dSRick Macklem shutdown(sock_fd[i], SHUT_RDWR); 11138fb6ad5dSRick Macklem close(sock_fd[i]); 11148fb6ad5dSRick Macklem } 11158fb6ad5dSRick Macklem } 11168fb6ad5dSRick Macklem } 11178fb6ad5dSRick Macklem 111874853402SPhilippe Charnier static void 1119a7a7d96cSPhilippe Charnier usage(void) 112074853402SPhilippe Charnier { 112174853402SPhilippe Charnier fprintf(stderr, 11222179ae1eSRick Macklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 1123c548eb5cSRick Macklem "[-S] [-h <bindip>] [export_file ...]\n"); 11248fae3551SRodney W. Grimes exit(1); 11258fae3551SRodney W. Grimes } 11268fae3551SRodney W. Grimes 11278fae3551SRodney W. Grimes /* 11288fae3551SRodney W. Grimes * The mount rpc service 11298fae3551SRodney W. Grimes */ 11308fae3551SRodney W. Grimes void 1131a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 11328fae3551SRodney W. Grimes { 11338fae3551SRodney W. Grimes struct exportlist *ep; 11348fae3551SRodney W. Grimes struct dirlist *dp; 1135a62dc406SDoug Rabson struct fhreturn fhr; 11368fae3551SRodney W. Grimes struct stat stb; 11378fae3551SRodney W. Grimes struct statfs fsb; 11388360efbdSAlfred Perlstein char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 11398360efbdSAlfred Perlstein int lookup_failed = 1; 11408360efbdSAlfred Perlstein struct sockaddr *saddr; 1141a62dc406SDoug Rabson u_short sport; 11420775314bSDoug Rabson char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 1143e9b21d43SBrooks Davis int defset, hostset; 1144e9b21d43SBrooks Davis long bad = 0; 1145a62dc406SDoug Rabson sigset_t sighup_mask; 1146c3f86a25SRick Macklem int numsecflavors, *secflavorsp; 11478fae3551SRodney W. Grimes 1148a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1149a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 11508360efbdSAlfred Perlstein saddr = svc_getrpccaller(transp)->buf; 11518360efbdSAlfred Perlstein switch (saddr->sa_family) { 11528360efbdSAlfred Perlstein case AF_INET6: 115301709abfSIan Dowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 11548360efbdSAlfred Perlstein break; 11558360efbdSAlfred Perlstein case AF_INET: 115601709abfSIan Dowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 11578360efbdSAlfred Perlstein break; 11588360efbdSAlfred Perlstein default: 11598360efbdSAlfred Perlstein syslog(LOG_ERR, "request from unknown address family"); 11608360efbdSAlfred Perlstein return; 11618360efbdSAlfred Perlstein } 116254ff4a6aSSean Eric Fagan switch (rqstp->rq_proc) { 116354ff4a6aSSean Eric Fagan case MOUNTPROC_MNT: 116454ff4a6aSSean Eric Fagan case MOUNTPROC_UMNT: 116554ff4a6aSSean Eric Fagan case MOUNTPROC_UMNTALL: 116654ff4a6aSSean Eric Fagan lookup_failed = getnameinfo(saddr, saddr->sa_len, host, 116754ff4a6aSSean Eric Fagan sizeof host, NULL, 0, 0); 116854ff4a6aSSean Eric Fagan } 11698360efbdSAlfred Perlstein getnameinfo(saddr, saddr->sa_len, numerichost, 11708360efbdSAlfred Perlstein sizeof numerichost, NULL, 0, NI_NUMERICHOST); 11718fae3551SRodney W. Grimes switch (rqstp->rq_proc) { 11728fae3551SRodney W. Grimes case NULLPROC: 1173389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 117474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 11758fae3551SRodney W. Grimes return; 11760775314bSDoug Rabson case MOUNTPROC_MNT: 1177a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1178f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1179f51631d7SGuido van Rooij "mount request from %s from unprivileged port", 11808360efbdSAlfred Perlstein numerichost); 11818fae3551SRodney W. Grimes svcerr_weakauth(transp); 11828fae3551SRodney W. Grimes return; 11838fae3551SRodney W. Grimes } 1184389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1185f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable mount request from %s", 11868360efbdSAlfred Perlstein numerichost); 11878fae3551SRodney W. Grimes svcerr_decode(transp); 11888fae3551SRodney W. Grimes return; 11898fae3551SRodney W. Grimes } 11908fae3551SRodney W. Grimes 11918fae3551SRodney W. Grimes /* 11928fae3551SRodney W. Grimes * Get the real pathname and make sure it is a directory 1193a62dc406SDoug Rabson * or a regular file if the -r option was specified 1194a62dc406SDoug Rabson * and it exists. 11958fae3551SRodney W. Grimes */ 1196cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL || 11978fae3551SRodney W. Grimes stat(dirpath, &stb) < 0 || 11988fae3551SRodney W. Grimes statfs(dirpath, &fsb) < 0) { 11998fae3551SRodney W. Grimes chdir("/"); /* Just in case realpath doesn't */ 1200f51631d7SGuido van Rooij syslog(LOG_NOTICE, 120174853402SPhilippe Charnier "mount request from %s for non existent path %s", 12028360efbdSAlfred Perlstein numerichost, dirpath); 12038fae3551SRodney W. Grimes if (debug) 120474853402SPhilippe Charnier warnx("stat failed on %s", dirpath); 1205e90cdb54SGuido van Rooij bad = ENOENT; /* We will send error reply later */ 12068fae3551SRodney W. Grimes } 1207b235f015SRavi Pokala if (!bad && 1208b235f015SRavi Pokala !S_ISDIR(stb.st_mode) && 1209b235f015SRavi Pokala (dir_only || !S_ISREG(stb.st_mode))) { 1210b235f015SRavi Pokala syslog(LOG_NOTICE, 1211b235f015SRavi Pokala "mount request from %s for non-directory path %s", 1212b235f015SRavi Pokala numerichost, dirpath); 1213b235f015SRavi Pokala if (debug) 1214b235f015SRavi Pokala warnx("mounting non-directory %s", dirpath); 1215b235f015SRavi Pokala bad = ENOTDIR; /* We will send error reply later */ 1216b235f015SRavi Pokala } 12178fae3551SRodney W. Grimes 12188fae3551SRodney W. Grimes /* Check in the exports list */ 1219a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1220b235f015SRavi Pokala if (bad) 1221b235f015SRavi Pokala ep = NULL; 1222b235f015SRavi Pokala else 122346a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead); 1224a62dc406SDoug Rabson hostset = defset = 0; 1225c3f86a25SRick Macklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1226c3f86a25SRick Macklem &numsecflavors, &secflavorsp) || 12278fae3551SRodney W. Grimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1228c3f86a25SRick Macklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1229c3f86a25SRick Macklem &secflavorsp)) || 12308fae3551SRodney W. Grimes (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 12318fae3551SRodney W. Grimes scan_tree(ep->ex_dirl, saddr) == 0))) { 1232e90cdb54SGuido van Rooij if (bad) { 1233389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 1234e90cdb54SGuido van Rooij (caddr_t)&bad)) 123574853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1236e90cdb54SGuido van Rooij sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1237e90cdb54SGuido van Rooij return; 1238e90cdb54SGuido van Rooij } 1239c3f86a25SRick Macklem if (hostset & DP_HOSTSET) { 1240a62dc406SDoug Rabson fhr.fhr_flag = hostset; 1241c3f86a25SRick Macklem fhr.fhr_numsecflavors = numsecflavors; 1242c3f86a25SRick Macklem fhr.fhr_secflavors = secflavorsp; 1243c3f86a25SRick Macklem } else { 1244a62dc406SDoug Rabson fhr.fhr_flag = defset; 1245c3f86a25SRick Macklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1246c3f86a25SRick Macklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1247c3f86a25SRick Macklem } 1248a62dc406SDoug Rabson fhr.fhr_vers = rqstp->rq_vers; 12498fae3551SRodney W. Grimes /* Get the file handle */ 125087564113SPeter Wemm memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 1251a62dc406SDoug Rabson if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 12528fae3551SRodney W. Grimes bad = errno; 125374853402SPhilippe Charnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1254389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 12558fae3551SRodney W. Grimes (caddr_t)&bad)) 125674853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1257a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12588fae3551SRodney W. Grimes return; 12598fae3551SRodney W. Grimes } 1260389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1261389b8446SPeter Wemm (caddr_t)&fhr)) 126274853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 12638360efbdSAlfred Perlstein if (!lookup_failed) 12648360efbdSAlfred Perlstein add_mlist(host, dirpath); 12658fae3551SRodney W. Grimes else 12668360efbdSAlfred Perlstein add_mlist(numerichost, dirpath); 12678fae3551SRodney W. Grimes if (debug) 126874853402SPhilippe Charnier warnx("mount successful"); 1269c903443aSPeter Wemm if (dolog) 1270f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1271f51631d7SGuido van Rooij "mount request succeeded from %s for %s", 12728360efbdSAlfred Perlstein numerichost, dirpath); 1273f51631d7SGuido van Rooij } else { 1274b235f015SRavi Pokala if (!bad) 12758fae3551SRodney W. Grimes bad = EACCES; 1276f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1277f51631d7SGuido van Rooij "mount request denied from %s for %s", 12788360efbdSAlfred Perlstein numerichost, dirpath); 1279f51631d7SGuido van Rooij } 1280e90cdb54SGuido van Rooij 1281389b8446SPeter Wemm if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1282389b8446SPeter Wemm (caddr_t)&bad)) 128374853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1284a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12858fae3551SRodney W. Grimes return; 12860775314bSDoug Rabson case MOUNTPROC_DUMP: 1287389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 128874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1289c903443aSPeter Wemm else if (dolog) 1290f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1291f51631d7SGuido van Rooij "dump request succeeded from %s", 12928360efbdSAlfred Perlstein numerichost); 12938fae3551SRodney W. Grimes return; 12940775314bSDoug Rabson case MOUNTPROC_UMNT: 1295a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1296f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1297f51631d7SGuido van Rooij "umount request from %s from unprivileged port", 12988360efbdSAlfred Perlstein numerichost); 12998fae3551SRodney W. Grimes svcerr_weakauth(transp); 13008fae3551SRodney W. Grimes return; 13018fae3551SRodney W. Grimes } 1302389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1303f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable umount request from %s", 13048360efbdSAlfred Perlstein numerichost); 13058fae3551SRodney W. Grimes svcerr_decode(transp); 13068fae3551SRodney W. Grimes return; 13078fae3551SRodney W. Grimes } 1308cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL) { 1309cb479b11SAlfred Perlstein syslog(LOG_NOTICE, "umount request from %s " 1310cb479b11SAlfred Perlstein "for non existent path %s", 13118360efbdSAlfred Perlstein numerichost, dirpath); 1312cb479b11SAlfred Perlstein } 1313389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 131474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 13158360efbdSAlfred Perlstein if (!lookup_failed) 131601709abfSIan Dowse del_mlist(host, dirpath); 131701709abfSIan Dowse del_mlist(numerichost, dirpath); 1318c903443aSPeter Wemm if (dolog) 1319f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1320f51631d7SGuido van Rooij "umount request succeeded from %s for %s", 13218360efbdSAlfred Perlstein numerichost, dirpath); 13228fae3551SRodney W. Grimes return; 13230775314bSDoug Rabson case MOUNTPROC_UMNTALL: 1324a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1325f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1326f51631d7SGuido van Rooij "umountall request from %s from unprivileged port", 13278360efbdSAlfred Perlstein numerichost); 13288fae3551SRodney W. Grimes svcerr_weakauth(transp); 13298fae3551SRodney W. Grimes return; 13308fae3551SRodney W. Grimes } 1331389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 133274853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 13338360efbdSAlfred Perlstein if (!lookup_failed) 133401709abfSIan Dowse del_mlist(host, NULL); 133501709abfSIan Dowse del_mlist(numerichost, NULL); 1336c903443aSPeter Wemm if (dolog) 1337f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1338f51631d7SGuido van Rooij "umountall request succeeded from %s", 13398360efbdSAlfred Perlstein numerichost); 13408fae3551SRodney W. Grimes return; 13410775314bSDoug Rabson case MOUNTPROC_EXPORT: 1342389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1343389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1344389b8446SPeter Wemm (caddr_t)NULL)) 134574853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1346c903443aSPeter Wemm if (dolog) 1347f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1348f51631d7SGuido van Rooij "export request succeeded from %s", 13498360efbdSAlfred Perlstein numerichost); 13508fae3551SRodney W. Grimes return; 13518fae3551SRodney W. Grimes default: 13528fae3551SRodney W. Grimes svcerr_noproc(transp); 13538fae3551SRodney W. Grimes return; 13548fae3551SRodney W. Grimes } 13558fae3551SRodney W. Grimes } 13568fae3551SRodney W. Grimes 13578fae3551SRodney W. Grimes /* 13588fae3551SRodney W. Grimes * Xdr conversion for a dirpath string 13598fae3551SRodney W. Grimes */ 136019c46d8cSEdward Tomasz Napierala static int 1361a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp) 13628fae3551SRodney W. Grimes { 13630775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 13648fae3551SRodney W. Grimes } 13658fae3551SRodney W. Grimes 13668fae3551SRodney W. Grimes /* 1367a62dc406SDoug Rabson * Xdr routine to generate file handle reply 13688fae3551SRodney W. Grimes */ 136919c46d8cSEdward Tomasz Napierala static int 1370a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp) 13718fae3551SRodney W. Grimes { 13723d438ad6SDavid E. O'Brien struct fhreturn *fhrp = (struct fhreturn *)cp; 1373a62dc406SDoug Rabson u_long ok = 0, len, auth; 1374a9148abdSDoug Rabson int i; 13758fae3551SRodney W. Grimes 13768fae3551SRodney W. Grimes if (!xdr_long(xdrsp, &ok)) 13778fae3551SRodney W. Grimes return (0); 1378a62dc406SDoug Rabson switch (fhrp->fhr_vers) { 1379a62dc406SDoug Rabson case 1: 1380a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 1381a62dc406SDoug Rabson case 3: 1382a62dc406SDoug Rabson len = NFSX_V3FH; 1383a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1384a62dc406SDoug Rabson return (0); 1385a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 1386a62dc406SDoug Rabson return (0); 1387a9148abdSDoug Rabson if (fhrp->fhr_numsecflavors) { 1388a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1389a9148abdSDoug Rabson return (0); 1390a9148abdSDoug Rabson for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1391a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1392a9148abdSDoug Rabson return (0); 1393a9148abdSDoug Rabson return (1); 1394a9148abdSDoug Rabson } else { 1395a9148abdSDoug Rabson auth = AUTH_SYS; 1396a62dc406SDoug Rabson len = 1; 1397a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1398a62dc406SDoug Rabson return (0); 1399a62dc406SDoug Rabson return (xdr_long(xdrsp, &auth)); 1400a9148abdSDoug Rabson } 140180c7cc1cSPedro F. Giffuni } 1402a62dc406SDoug Rabson return (0); 14038fae3551SRodney W. Grimes } 14048fae3551SRodney W. Grimes 140519c46d8cSEdward Tomasz Napierala static int 1406a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused) 14078fae3551SRodney W. Grimes { 14088fae3551SRodney W. Grimes struct mountlist *mlp; 14098fae3551SRodney W. Grimes int true = 1; 14108fae3551SRodney W. Grimes int false = 0; 14118fae3551SRodney W. Grimes char *strp; 14128fae3551SRodney W. Grimes 14131da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 14148fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 14158fae3551SRodney W. Grimes return (0); 14168fae3551SRodney W. Grimes strp = &mlp->ml_host[0]; 14170775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 14188fae3551SRodney W. Grimes return (0); 14198fae3551SRodney W. Grimes strp = &mlp->ml_dirp[0]; 14200775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 14218fae3551SRodney W. Grimes return (0); 14228fae3551SRodney W. Grimes } 14238fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 14248fae3551SRodney W. Grimes return (0); 14258fae3551SRodney W. Grimes return (1); 14268fae3551SRodney W. Grimes } 14278fae3551SRodney W. Grimes 14288fae3551SRodney W. Grimes /* 14298fae3551SRodney W. Grimes * Xdr conversion for export list 14308fae3551SRodney W. Grimes */ 143119c46d8cSEdward Tomasz Napierala static int 1432a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 14338fae3551SRodney W. Grimes { 14348fae3551SRodney W. Grimes struct exportlist *ep; 14358fae3551SRodney W. Grimes int false = 0; 1436a62dc406SDoug Rabson int putdef; 1437a62dc406SDoug Rabson sigset_t sighup_mask; 143846a6b5c4SRick Macklem int i; 14398fae3551SRodney W. Grimes 1440a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1441a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 1442a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1443c9ac0f71SEmmanuel Vadot 144446a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++) 144546a6b5c4SRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) { 14468fae3551SRodney W. Grimes putdef = 0; 144791acb349SAlfred Perlstein if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 144891acb349SAlfred Perlstein &putdef, brief)) 14498fae3551SRodney W. Grimes goto errout; 14508fae3551SRodney W. Grimes if (ep->ex_defdir && putdef == 0 && 145146a6b5c4SRick Macklem put_exlist(ep->ex_defdir, xdrsp, NULL, 145291acb349SAlfred Perlstein &putdef, brief)) 14538fae3551SRodney W. Grimes goto errout; 14548fae3551SRodney W. Grimes } 1455a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 14568fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 14578fae3551SRodney W. Grimes return (0); 14588fae3551SRodney W. Grimes return (1); 14598fae3551SRodney W. Grimes errout: 1460a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 14618fae3551SRodney W. Grimes return (0); 14628fae3551SRodney W. Grimes } 14638fae3551SRodney W. Grimes 14648fae3551SRodney W. Grimes /* 14658fae3551SRodney W. Grimes * Called from xdr_explist() to traverse the tree and export the 14668fae3551SRodney W. Grimes * directory paths. 14678fae3551SRodney W. Grimes */ 146819c46d8cSEdward Tomasz Napierala static int 1469a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1470a7a7d96cSPhilippe Charnier int brief) 14718fae3551SRodney W. Grimes { 14728fae3551SRodney W. Grimes struct grouplist *grp; 14738fae3551SRodney W. Grimes struct hostlist *hp; 14748fae3551SRodney W. Grimes int true = 1; 14758fae3551SRodney W. Grimes int false = 0; 14768fae3551SRodney W. Grimes int gotalldir = 0; 14778fae3551SRodney W. Grimes char *strp; 14788fae3551SRodney W. Grimes 14798fae3551SRodney W. Grimes if (dp) { 148091acb349SAlfred Perlstein if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 14818fae3551SRodney W. Grimes return (1); 14828fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 14838fae3551SRodney W. Grimes return (1); 14848fae3551SRodney W. Grimes strp = dp->dp_dirp; 14850775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 14868fae3551SRodney W. Grimes return (1); 14878fae3551SRodney W. Grimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 14888fae3551SRodney W. Grimes gotalldir = 1; 14898fae3551SRodney W. Grimes *putdefp = 1; 14908fae3551SRodney W. Grimes } 149191acb349SAlfred Perlstein if (brief) { 149291acb349SAlfred Perlstein if (!xdr_bool(xdrsp, &true)) 149391acb349SAlfred Perlstein return (1); 149491acb349SAlfred Perlstein strp = "(...)"; 14950775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 149691acb349SAlfred Perlstein return (1); 149791acb349SAlfred Perlstein } else if ((dp->dp_flag & DP_DEFSET) == 0 && 14988fae3551SRodney W. Grimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 14998fae3551SRodney W. Grimes hp = dp->dp_hosts; 15008fae3551SRodney W. Grimes while (hp) { 15018fae3551SRodney W. Grimes grp = hp->ht_grp; 15028fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 15038fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 15048fae3551SRodney W. Grimes return (1); 15058360efbdSAlfred Perlstein strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 15068fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 15070775314bSDoug Rabson MNTNAMLEN)) 15088fae3551SRodney W. Grimes return (1); 15098fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 15108fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 15118fae3551SRodney W. Grimes return (1); 15128fae3551SRodney W. Grimes strp = grp->gr_ptr.gt_net.nt_name; 15138fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 15140775314bSDoug Rabson MNTNAMLEN)) 15158fae3551SRodney W. Grimes return (1); 15168fae3551SRodney W. Grimes } 15178fae3551SRodney W. Grimes hp = hp->ht_next; 15188fae3551SRodney W. Grimes if (gotalldir && hp == (struct hostlist *)NULL) { 15198fae3551SRodney W. Grimes hp = adp->dp_hosts; 15208fae3551SRodney W. Grimes gotalldir = 0; 15218fae3551SRodney W. Grimes } 15228fae3551SRodney W. Grimes } 15238fae3551SRodney W. Grimes } 15248fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 15258fae3551SRodney W. Grimes return (1); 152691acb349SAlfred Perlstein if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 15278fae3551SRodney W. Grimes return (1); 15288fae3551SRodney W. Grimes } 15298fae3551SRodney W. Grimes return (0); 15308fae3551SRodney W. Grimes } 15318fae3551SRodney W. Grimes 153219c46d8cSEdward Tomasz Napierala static int 1533a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp) 153491acb349SAlfred Perlstein { 153591acb349SAlfred Perlstein 153691acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 0); 153791acb349SAlfred Perlstein } 153891acb349SAlfred Perlstein 153919c46d8cSEdward Tomasz Napierala static int 1540a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp) 154191acb349SAlfred Perlstein { 154291acb349SAlfred Perlstein 154391acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 1); 154491acb349SAlfred Perlstein } 154591acb349SAlfred Perlstein 154619c46d8cSEdward Tomasz Napierala static char *line; 154719c46d8cSEdward Tomasz Napierala static size_t linesize; 154819c46d8cSEdward Tomasz Napierala static FILE *exp_file; 15498fae3551SRodney W. Grimes 15508fae3551SRodney W. Grimes /* 155196968c22SPawel Jakub Dawidek * Get the export list from one, currently open file 15528fae3551SRodney W. Grimes */ 155396968c22SPawel Jakub Dawidek static void 15540f0869bcSRick Macklem get_exportlist_one(int passno) 15558fae3551SRodney W. Grimes { 1556c9ac0f71SEmmanuel Vadot struct exportlist *ep; 15570f0869bcSRick Macklem struct grouplist *grp, *tgrp, *savgrp; 15588fae3551SRodney W. Grimes struct dirlist *dirhead; 155996968c22SPawel Jakub Dawidek struct statfs fsb; 1560cc5efddeSRick Macklem struct expcred anon; 15618fae3551SRodney W. Grimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1562*572b77f8SAlexander Motin char *err_msg = NULL; 1563cc5efddeSRick Macklem int len, has_host, got_nondir, dirplen, netgrp; 1564cc5efddeSRick Macklem uint64_t exflags; 15658fae3551SRodney W. Grimes 1566bcc1d071SRick Macklem v4root_phase = 0; 15672ffad162SRick Macklem anon.cr_groups = NULL; 15688fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 15698fae3551SRodney W. Grimes while (get_line()) { 15708fae3551SRodney W. Grimes if (debug) 157174853402SPhilippe Charnier warnx("got line %s", line); 15728fae3551SRodney W. Grimes cp = line; 15738fae3551SRodney W. Grimes nextfield(&cp, &endcp); 15748fae3551SRodney W. Grimes if (*cp == '#') 15758fae3551SRodney W. Grimes goto nextline; 15768fae3551SRodney W. Grimes 15778fae3551SRodney W. Grimes /* 15788fae3551SRodney W. Grimes * Set defaults. 15798fae3551SRodney W. Grimes */ 15808fae3551SRodney W. Grimes has_host = FALSE; 15812ffad162SRick Macklem anon.cr_groups = anon.cr_smallgrps; 15823e2d36ffSRick Macklem anon.cr_uid = UID_NOBODY; 1583cc5efddeSRick Macklem anon.cr_ngroups = 1; 15843e2d36ffSRick Macklem anon.cr_groups[0] = GID_NOGROUP; 15858fae3551SRodney W. Grimes exflags = MNT_EXPORTED; 15868fae3551SRodney W. Grimes got_nondir = 0; 15878fae3551SRodney W. Grimes opt_flags = 0; 15888fae3551SRodney W. Grimes ep = (struct exportlist *)NULL; 1589bcc1d071SRick Macklem dirp = NULL; 1590bcc1d071SRick Macklem 1591bcc1d071SRick Macklem /* 1592bcc1d071SRick Macklem * Handle the V4 root dir. 1593bcc1d071SRick Macklem */ 1594bcc1d071SRick Macklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1595bcc1d071SRick Macklem /* 1596bcc1d071SRick Macklem * V4: just indicates that it is the v4 root point, 1597bcc1d071SRick Macklem * so skip over that and set v4root_phase. 1598bcc1d071SRick Macklem */ 1599bcc1d071SRick Macklem if (v4root_phase > 0) { 1600bcc1d071SRick Macklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1601bcc1d071SRick Macklem goto nextline; 1602bcc1d071SRick Macklem } 1603bcc1d071SRick Macklem v4root_phase = 1; 1604bcc1d071SRick Macklem cp += 3; 1605bcc1d071SRick Macklem nextfield(&cp, &endcp); 1606bcc1d071SRick Macklem } 16078fae3551SRodney W. Grimes 16088fae3551SRodney W. Grimes /* 16098fae3551SRodney W. Grimes * Create new exports list entry 16108fae3551SRodney W. Grimes */ 16118fae3551SRodney W. Grimes len = endcp-cp; 16128fae3551SRodney W. Grimes tgrp = grp = get_grp(); 16138fae3551SRodney W. Grimes while (len > 0) { 16140775314bSDoug Rabson if (len > MNTNAMLEN) { 1615354fce28SConrad Meyer getexp_err(ep, tgrp, "mountpoint too long"); 16168fae3551SRodney W. Grimes goto nextline; 16178fae3551SRodney W. Grimes } 16188fae3551SRodney W. Grimes if (*cp == '-') { 16198fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1620354fce28SConrad Meyer getexp_err(ep, tgrp, 1621354fce28SConrad Meyer "flag before export path definition"); 16228fae3551SRodney W. Grimes goto nextline; 16238fae3551SRodney W. Grimes } 16248fae3551SRodney W. Grimes if (debug) 162574853402SPhilippe Charnier warnx("doing opt %s", cp); 16268fae3551SRodney W. Grimes got_nondir = 1; 16278fae3551SRodney W. Grimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 16288fae3551SRodney W. Grimes &exflags, &anon)) { 1629354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 16308fae3551SRodney W. Grimes goto nextline; 16318fae3551SRodney W. Grimes } 16328fae3551SRodney W. Grimes } else if (*cp == '/') { 16338fae3551SRodney W. Grimes savedc = *endcp; 16348fae3551SRodney W. Grimes *endcp = '\0'; 1635bcc1d071SRick Macklem if (v4root_phase > 1) { 1636bcc1d071SRick Macklem if (dirp != NULL) { 1637354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1638bcc1d071SRick Macklem goto nextline; 1639bcc1d071SRick Macklem } 1640bcc1d071SRick Macklem } 1641*572b77f8SAlexander Motin if (check_dirpath(cp, &err_msg) && 1642*572b77f8SAlexander Motin check_statfs(cp, &fsb, &err_msg)) { 16439896584aSRick Macklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 16449896584aSRick Macklem syslog(LOG_ERR, "Warning: exporting of " 16459896584aSRick Macklem "automounted fs %s not supported", cp); 16468fae3551SRodney W. Grimes if (got_nondir) { 1647354fce28SConrad Meyer getexp_err(ep, tgrp, "dirs must be first"); 16488fae3551SRodney W. Grimes goto nextline; 16498fae3551SRodney W. Grimes } 1650bcc1d071SRick Macklem if (v4root_phase == 1) { 1651bcc1d071SRick Macklem if (dirp != NULL) { 1652354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1653bcc1d071SRick Macklem goto nextline; 1654bcc1d071SRick Macklem } 1655bcc1d071SRick Macklem if (strlen(v4root_dirpath) == 0) { 1656bcc1d071SRick Macklem strlcpy(v4root_dirpath, cp, 1657bcc1d071SRick Macklem sizeof (v4root_dirpath)); 1658bcc1d071SRick Macklem } else if (strcmp(v4root_dirpath, cp) 1659bcc1d071SRick Macklem != 0) { 1660bcc1d071SRick Macklem syslog(LOG_ERR, 1661bcc1d071SRick Macklem "different V4 dirpath %s", cp); 1662354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 1663bcc1d071SRick Macklem goto nextline; 1664bcc1d071SRick Macklem } 1665bcc1d071SRick Macklem dirp = cp; 1666bcc1d071SRick Macklem v4root_phase = 2; 1667bcc1d071SRick Macklem got_nondir = 1; 1668bcc1d071SRick Macklem ep = get_exp(); 1669bcc1d071SRick Macklem } else { 16708fae3551SRodney W. Grimes if (ep) { 1671245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, &fsb.f_fsid) 1672245bfd34SRyan Moeller != 0) { 1673354fce28SConrad Meyer getexp_err(ep, tgrp, 1674354fce28SConrad Meyer "fsid mismatch"); 16758fae3551SRodney W. Grimes goto nextline; 16768fae3551SRodney W. Grimes } 16778fae3551SRodney W. Grimes } else { 16788fae3551SRodney W. Grimes /* 16798fae3551SRodney W. Grimes * See if this directory is already 16808fae3551SRodney W. Grimes * in the list. 16818fae3551SRodney W. Grimes */ 168246a6b5c4SRick Macklem ep = ex_search(&fsb.f_fsid, exphead); 16838fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 16848fae3551SRodney W. Grimes ep = get_exp(); 16858fae3551SRodney W. Grimes ep->ex_fs = fsb.f_fsid; 1686380a3fcdSEmmanuel Vadot ep->ex_fsdir = strdup(fsb.f_mntonname); 1687380a3fcdSEmmanuel Vadot if (ep->ex_fsdir == NULL) 16888fae3551SRodney W. Grimes out_of_mem(); 16898fae3551SRodney W. Grimes if (debug) 1690bcc1d071SRick Macklem warnx( 1691bcc1d071SRick Macklem "making new ep fs=0x%x,0x%x", 16928fae3551SRodney W. Grimes fsb.f_fsid.val[0], 16938fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 16948fae3551SRodney W. Grimes } else if (debug) 169574853402SPhilippe Charnier warnx("found ep fs=0x%x,0x%x", 16968fae3551SRodney W. Grimes fsb.f_fsid.val[0], 16978fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 16988fae3551SRodney W. Grimes } 16998fae3551SRodney W. Grimes 17008fae3551SRodney W. Grimes /* 17018fae3551SRodney W. Grimes * Add dirpath to export mount point. 17028fae3551SRodney W. Grimes */ 17038fae3551SRodney W. Grimes dirp = add_expdir(&dirhead, cp, len); 17048fae3551SRodney W. Grimes dirplen = len; 1705bcc1d071SRick Macklem } 17068fae3551SRodney W. Grimes } else { 1707*572b77f8SAlexander Motin if (err_msg != NULL) { 1708*572b77f8SAlexander Motin getexp_err(ep, tgrp, err_msg); 1709*572b77f8SAlexander Motin free(err_msg); 1710*572b77f8SAlexander Motin err_msg = NULL; 1711*572b77f8SAlexander Motin } else { 1712354fce28SConrad Meyer getexp_err(ep, tgrp, 1713*572b77f8SAlexander Motin "symbolic link in export path or " 1714*572b77f8SAlexander Motin "statfs failed"); 1715*572b77f8SAlexander Motin } 17168fae3551SRodney W. Grimes goto nextline; 17178fae3551SRodney W. Grimes } 17188fae3551SRodney W. Grimes *endcp = savedc; 17198fae3551SRodney W. Grimes } else { 17208fae3551SRodney W. Grimes savedc = *endcp; 17218fae3551SRodney W. Grimes *endcp = '\0'; 17228fae3551SRodney W. Grimes got_nondir = 1; 17238fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1724354fce28SConrad Meyer getexp_err(ep, tgrp, 1725354fce28SConrad Meyer "host(s) before export path definition"); 17268fae3551SRodney W. Grimes goto nextline; 17278fae3551SRodney W. Grimes } 17288fae3551SRodney W. Grimes 17298fae3551SRodney W. Grimes /* 17308fae3551SRodney W. Grimes * Get the host or netgroup. 17318fae3551SRodney W. Grimes */ 17328fae3551SRodney W. Grimes setnetgrent(cp); 17338fae3551SRodney W. Grimes netgrp = getnetgrent(&hst, &usr, &dom); 17348fae3551SRodney W. Grimes do { 17358fae3551SRodney W. Grimes if (has_host) { 17368fae3551SRodney W. Grimes grp->gr_next = get_grp(); 17378fae3551SRodney W. Grimes grp = grp->gr_next; 17388fae3551SRodney W. Grimes } 17398fae3551SRodney W. Grimes if (netgrp) { 17409d70a156SJoerg Wunsch if (hst == 0) { 174174853402SPhilippe Charnier syslog(LOG_ERR, 174274853402SPhilippe Charnier "null hostname in netgroup %s, skipping", cp); 174301d48801SJoerg Wunsch grp->gr_type = GT_IGNORE; 17449d70a156SJoerg Wunsch } else if (get_host(hst, grp, tgrp)) { 174574853402SPhilippe Charnier syslog(LOG_ERR, 174674853402SPhilippe Charnier "bad host %s in netgroup %s, skipping", hst, cp); 1747a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 17488fae3551SRodney W. Grimes } 17498b5a6d67SBill Paul } else if (get_host(cp, grp, tgrp)) { 175074853402SPhilippe Charnier syslog(LOG_ERR, "bad host %s, skipping", cp); 1751a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 17528fae3551SRodney W. Grimes } 17538fae3551SRodney W. Grimes has_host = TRUE; 17548fae3551SRodney W. Grimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 17558fae3551SRodney W. Grimes endnetgrent(); 17568fae3551SRodney W. Grimes *endcp = savedc; 17578fae3551SRodney W. Grimes } 17588fae3551SRodney W. Grimes cp = endcp; 17598fae3551SRodney W. Grimes nextfield(&cp, &endcp); 17608fae3551SRodney W. Grimes len = endcp - cp; 17618fae3551SRodney W. Grimes } 17628fae3551SRodney W. Grimes if (check_options(dirhead)) { 1763354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 17648fae3551SRodney W. Grimes goto nextline; 17658fae3551SRodney W. Grimes } 17668fae3551SRodney W. Grimes if (!has_host) { 17676d359f31SIan Dowse grp->gr_type = GT_DEFAULT; 17688fae3551SRodney W. Grimes if (debug) 176974853402SPhilippe Charnier warnx("adding a default entry"); 17708fae3551SRodney W. Grimes 17718fae3551SRodney W. Grimes /* 17728fae3551SRodney W. Grimes * Don't allow a network export coincide with a list of 17738fae3551SRodney W. Grimes * host(s) on the same line. 17748fae3551SRodney W. Grimes */ 17758fae3551SRodney W. Grimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1776354fce28SConrad Meyer getexp_err(ep, tgrp, "network/host conflict"); 17778fae3551SRodney W. Grimes goto nextline; 1778a968cfd8SJonathan Lemon 1779a968cfd8SJonathan Lemon /* 1780a968cfd8SJonathan Lemon * If an export list was specified on this line, make sure 1781a968cfd8SJonathan Lemon * that we have at least one valid entry, otherwise skip it. 1782a968cfd8SJonathan Lemon */ 1783a968cfd8SJonathan Lemon } else { 1784a968cfd8SJonathan Lemon grp = tgrp; 1785a968cfd8SJonathan Lemon while (grp && grp->gr_type == GT_IGNORE) 1786a968cfd8SJonathan Lemon grp = grp->gr_next; 1787a968cfd8SJonathan Lemon if (! grp) { 1788354fce28SConrad Meyer getexp_err(ep, tgrp, "no valid entries"); 1789a968cfd8SJonathan Lemon goto nextline; 1790a968cfd8SJonathan Lemon } 17918fae3551SRodney W. Grimes } 17928fae3551SRodney W. Grimes 1793bcc1d071SRick Macklem if (v4root_phase == 1) { 1794354fce28SConrad Meyer getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); 1795bcc1d071SRick Macklem goto nextline; 1796bcc1d071SRick Macklem } 1797bcc1d071SRick Macklem 17988fae3551SRodney W. Grimes /* 17998fae3551SRodney W. Grimes * Loop through hosts, pushing the exports into the kernel. 18008fae3551SRodney W. Grimes * After loop, tgrp points to the start of the list and 18018fae3551SRodney W. Grimes * grp points to the last entry in the list. 18020f0869bcSRick Macklem * Do not do the do_mount() for passno == 1, since the 18030f0869bcSRick Macklem * second pass will do it, as required. 18048fae3551SRodney W. Grimes */ 18058fae3551SRodney W. Grimes grp = tgrp; 18068fae3551SRodney W. Grimes do { 18070f0869bcSRick Macklem grp->gr_exflags = exflags; 1808cc5efddeSRick Macklem cp_cred(&grp->gr_anon, &anon); 18090f0869bcSRick Macklem if (v4root_phase == 2 && passno == 0) 18100f0869bcSRick Macklem LOGDEBUG("do_mount v4root"); 18110f0869bcSRick Macklem if (passno == 0 && do_mount(ep, grp, exflags, &anon, 18120f0869bcSRick Macklem dirp, dirplen, &fsb, ep->ex_numsecflavors, 18130f0869bcSRick Macklem ep->ex_secflavors)) { 1814354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 18158fae3551SRodney W. Grimes goto nextline; 18168fae3551SRodney W. Grimes } 18178fae3551SRodney W. Grimes } while (grp->gr_next && (grp = grp->gr_next)); 18188fae3551SRodney W. Grimes 18198fae3551SRodney W. Grimes /* 1820bcc1d071SRick Macklem * For V4: don't enter in mount lists. 1821bcc1d071SRick Macklem */ 182273f4ccbdSRick Macklem if (v4root_phase > 0 && v4root_phase <= 2) { 182373f4ccbdSRick Macklem /* 1824c2ec1113SRick Macklem * These structures are used for the reload, 18250f0869bcSRick Macklem * so save them for that case. Otherwise, just 182673f4ccbdSRick Macklem * free them up now. 182773f4ccbdSRick Macklem */ 18280f0869bcSRick Macklem if (passno == 1 && ep != NULL) { 18290f0869bcSRick Macklem savgrp = tgrp; 18300f0869bcSRick Macklem while (tgrp != NULL) { 18310f0869bcSRick Macklem /* 18320f0869bcSRick Macklem * Save the security flavors and exflags 18330f0869bcSRick Macklem * for this host set in the groups. 18340f0869bcSRick Macklem */ 18350f0869bcSRick Macklem tgrp->gr_numsecflavors = 18360f0869bcSRick Macklem ep->ex_numsecflavors; 18370f0869bcSRick Macklem if (ep->ex_numsecflavors > 0) 18380f0869bcSRick Macklem memcpy(tgrp->gr_secflavors, 18390f0869bcSRick Macklem ep->ex_secflavors, 18400f0869bcSRick Macklem sizeof(ep->ex_secflavors)); 18410f0869bcSRick Macklem tgrp = tgrp->gr_next; 18420f0869bcSRick Macklem } 18430f0869bcSRick Macklem if (v4root_ep == NULL) { 18440f0869bcSRick Macklem v4root_ep = ep; 18450f0869bcSRick Macklem ep = NULL; /* Don't free below. */ 18460f0869bcSRick Macklem } 18470f0869bcSRick Macklem grp->gr_next = v4root_ep->ex_grphead; 18480f0869bcSRick Macklem v4root_ep->ex_grphead = savgrp; 18490f0869bcSRick Macklem } 185073f4ccbdSRick Macklem if (ep != NULL) 185173f4ccbdSRick Macklem free_exp(ep); 185273f4ccbdSRick Macklem while (tgrp != NULL) { 185373f4ccbdSRick Macklem grp = tgrp; 185473f4ccbdSRick Macklem tgrp = tgrp->gr_next; 185573f4ccbdSRick Macklem free_grp(grp); 185673f4ccbdSRick Macklem } 1857bcc1d071SRick Macklem goto nextline; 185873f4ccbdSRick Macklem } 1859bcc1d071SRick Macklem 1860bcc1d071SRick Macklem /* 18618fae3551SRodney W. Grimes * Success. Update the data structures. 18628fae3551SRodney W. Grimes */ 18638fae3551SRodney W. Grimes if (has_host) { 18640f0869bcSRick Macklem hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags); 1865711d44eeSRick Macklem grp->gr_next = ep->ex_grphead; 1866711d44eeSRick Macklem ep->ex_grphead = tgrp; 18678fae3551SRodney W. Grimes } else { 18688fae3551SRodney W. Grimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 18690f0869bcSRick Macklem opt_flags, &anon, exflags); 18708fae3551SRodney W. Grimes free_grp(grp); 18718fae3551SRodney W. Grimes } 18728fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 18738fae3551SRodney W. Grimes if ((ep->ex_flag & EX_LINKED) == 0) { 187446a6b5c4SRick Macklem insert_exports(ep, exphead); 18758fae3551SRodney W. Grimes 18768fae3551SRodney W. Grimes ep->ex_flag |= EX_LINKED; 18778fae3551SRodney W. Grimes } 18788fae3551SRodney W. Grimes nextline: 1879bcc1d071SRick Macklem v4root_phase = 0; 18808fae3551SRodney W. Grimes if (dirhead) { 18818fae3551SRodney W. Grimes free_dir(dirhead); 18828fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 18838fae3551SRodney W. Grimes } 18842ffad162SRick Macklem if (anon.cr_groups != anon.cr_smallgrps) { 18852ffad162SRick Macklem free(anon.cr_groups); 18862ffad162SRick Macklem anon.cr_groups = NULL; 18872ffad162SRick Macklem } 18888fae3551SRodney W. Grimes } 188996968c22SPawel Jakub Dawidek } 189096968c22SPawel Jakub Dawidek 189196968c22SPawel Jakub Dawidek /* 189296968c22SPawel Jakub Dawidek * Get the export list from all specified files 189396968c22SPawel Jakub Dawidek */ 189419c46d8cSEdward Tomasz Napierala static void 18950f0869bcSRick Macklem get_exportlist(int passno) 189696968c22SPawel Jakub Dawidek { 189796968c22SPawel Jakub Dawidek struct export_args export; 189896968c22SPawel Jakub Dawidek struct iovec *iov; 18993e08dc74SRick Macklem struct statfs *mntbufp; 190096968c22SPawel Jakub Dawidek char errmsg[255]; 190109673fc0SRick Macklem int error, i, nfs_maxvers, num; 190296968c22SPawel Jakub Dawidek int iovlen; 1903bcc1d071SRick Macklem struct nfsex_args eargs; 19040f0869bcSRick Macklem FILE *debug_file; 190509673fc0SRick Macklem size_t nfs_maxvers_size; 190696968c22SPawel Jakub Dawidek 19070f0869bcSRick Macklem if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) { 19080f0869bcSRick Macklem fclose(debug_file); 19090f0869bcSRick Macklem logdebug = 1; 19100f0869bcSRick Macklem } else 19110f0869bcSRick Macklem logdebug = 0; 19120f0869bcSRick Macklem LOGDEBUG("passno=%d", passno); 1913bcc1d071SRick Macklem v4root_dirpath[0] = '\0'; 19140f0869bcSRick Macklem free_v4rootexp(); 19150f0869bcSRick Macklem if (passno == 1) { 19160f0869bcSRick Macklem /* 19170f0869bcSRick Macklem * Save the current lists as old ones, so that the new lists 19180f0869bcSRick Macklem * can be compared with the old ones in the 2nd pass. 19190f0869bcSRick Macklem */ 19200f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) { 19210f0869bcSRick Macklem SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]); 19220f0869bcSRick Macklem SLIST_INIT(&exphead[i]); 19230f0869bcSRick Macklem } 19240f0869bcSRick Macklem 19250f0869bcSRick Macklem /* Note that the public fh has not yet been set. */ 19260f0869bcSRick Macklem has_set_publicfh = 0; 19270f0869bcSRick Macklem 19280f0869bcSRick Macklem /* Read the export file(s) and process them */ 19290f0869bcSRick Macklem read_exportfile(passno); 19300f0869bcSRick Macklem } else { 19310f0869bcSRick Macklem /* 19320f0869bcSRick Macklem * Just make the old lists empty. 19330f0869bcSRick Macklem * exphashsize == 0 for the first call, before oldexphead 19340f0869bcSRick Macklem * has been initialized-->loop won't be executed. 19350f0869bcSRick Macklem */ 19360f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 19370f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]); 19380f0869bcSRick Macklem } 19390f0869bcSRick Macklem 194096968c22SPawel Jakub Dawidek bzero(&export, sizeof(export)); 194196968c22SPawel Jakub Dawidek export.ex_flags = MNT_DELEXPORT; 194296968c22SPawel Jakub Dawidek iov = NULL; 194396968c22SPawel Jakub Dawidek iovlen = 0; 194496968c22SPawel Jakub Dawidek bzero(errmsg, sizeof(errmsg)); 194596968c22SPawel Jakub Dawidek 19460f0869bcSRick Macklem if (suspend_nfsd != 0) 19470f0869bcSRick Macklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 194896968c22SPawel Jakub Dawidek /* 19490f0869bcSRick Macklem * Delete the old V4 root dir. 1950bcc1d071SRick Macklem */ 1951bcc1d071SRick Macklem bzero(&eargs, sizeof (eargs)); 1952bcc1d071SRick Macklem eargs.export.ex_flags = MNT_DELEXPORT; 1953cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, (caddr_t)&eargs) < 0 && 1954bcc1d071SRick Macklem errno != ENOENT) 1955bcc1d071SRick Macklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1956bcc1d071SRick Macklem 19570f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 19580f0869bcSRick Macklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 19590f0869bcSRick Macklem build_iovec(&iov, &iovlen, "from", NULL, 0); 19600f0869bcSRick Macklem build_iovec(&iov, &iovlen, "update", NULL, 0); 19610f0869bcSRick Macklem build_iovec(&iov, &iovlen, "export", &export, 19620f0869bcSRick Macklem sizeof(export)); 19630f0869bcSRick Macklem build_iovec(&iov, &iovlen, "errmsg", errmsg, 19640f0869bcSRick Macklem sizeof(errmsg)); 19650f0869bcSRick Macklem 1966bcc1d071SRick Macklem /* 19670f0869bcSRick Macklem * For passno == 1, compare the old and new lists updating the kernel 19680f0869bcSRick Macklem * exports for any cases that have changed. 19690f0869bcSRick Macklem * This call is doing the second pass through the lists. 19700f0869bcSRick Macklem * If it fails, fall back on the bulk reload. 19710f0869bcSRick Macklem */ 19720f0869bcSRick Macklem if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) == 19730f0869bcSRick Macklem 0) { 19740f0869bcSRick Macklem LOGDEBUG("compareok"); 19750f0869bcSRick Macklem /* Free up the old lists. */ 19760f0869bcSRick Macklem free_exports(oldexphead); 19770f0869bcSRick Macklem } else { 19780f0869bcSRick Macklem LOGDEBUG("doing passno=0"); 19790f0869bcSRick Macklem /* 19800f0869bcSRick Macklem * Clear flag that notes if a public fh has been exported. 19810f0869bcSRick Macklem * It is set by do_mount() if MNT_EXPUBLIC is set for the entry. 1982bcc1d071SRick Macklem */ 1983bcc1d071SRick Macklem has_publicfh = 0; 1984bcc1d071SRick Macklem 19850f0869bcSRick Macklem /* exphead == NULL if not yet allocated (first call). */ 19860f0869bcSRick Macklem if (exphead != NULL) { 19870f0869bcSRick Macklem /* 19880f0869bcSRick Macklem * First, get rid of the old lists. 19890f0869bcSRick Macklem */ 19900f0869bcSRick Macklem free_exports(exphead); 19910f0869bcSRick Macklem free_exports(oldexphead); 19920f0869bcSRick Macklem } 19930f0869bcSRick Macklem 1994bcc1d071SRick Macklem /* 199596968c22SPawel Jakub Dawidek * And delete exports that are in the kernel for all local 199696968c22SPawel Jakub Dawidek * filesystems. 19970f0869bcSRick Macklem * XXX: Should know how to handle all local exportable 19980f0869bcSRick Macklem * filesystems. 199996968c22SPawel Jakub Dawidek */ 200096968c22SPawel Jakub Dawidek num = getmntinfo(&mntbufp, MNT_NOWAIT); 200196968c22SPawel Jakub Dawidek 200246a6b5c4SRick Macklem /* Allocate hash tables, for first call. */ 200346a6b5c4SRick Macklem if (exphead == NULL) { 200446a6b5c4SRick Macklem /* Target an average linked list length of 10. */ 200546a6b5c4SRick Macklem exphashsize = num / 10; 200646a6b5c4SRick Macklem if (exphashsize < 1) 200746a6b5c4SRick Macklem exphashsize = 1; 200846a6b5c4SRick Macklem else if (exphashsize > 100000) 200946a6b5c4SRick Macklem exphashsize = 100000; 201046a6b5c4SRick Macklem exphead = malloc(exphashsize * sizeof(*exphead)); 20110f0869bcSRick Macklem oldexphead = malloc(exphashsize * sizeof(*oldexphead)); 20120f0869bcSRick Macklem if (exphead == NULL || oldexphead == NULL) 20130f0869bcSRick Macklem errx(1, "Can't malloc hash tables"); 201446a6b5c4SRick Macklem 20150f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) { 201646a6b5c4SRick Macklem SLIST_INIT(&exphead[i]); 20170f0869bcSRick Macklem SLIST_INIT(&oldexphead[i]); 201846a6b5c4SRick Macklem } 201996968c22SPawel Jakub Dawidek } 202096968c22SPawel Jakub Dawidek 20213e08dc74SRick Macklem for (i = 0; i < num; i++) 20223e08dc74SRick Macklem delete_export(iov, iovlen, &mntbufp[i], errmsg); 202396968c22SPawel Jakub Dawidek 20240f0869bcSRick Macklem 20250f0869bcSRick Macklem /* Read the export file(s) and process them */ 20260f0869bcSRick Macklem read_exportfile(0); 20270f0869bcSRick Macklem } 20280f0869bcSRick Macklem 202909673fc0SRick Macklem if (strlen(v4root_dirpath) == 0) { 203009673fc0SRick Macklem /* Check to see if a V4: line is needed. */ 203109673fc0SRick Macklem nfs_maxvers_size = sizeof(nfs_maxvers); 203209673fc0SRick Macklem error = sysctlbyname("vfs.nfsd.server_max_nfsvers", 203309673fc0SRick Macklem &nfs_maxvers, &nfs_maxvers_size, NULL, 0); 203409673fc0SRick Macklem if (error != 0 || nfs_maxvers < NFS_VER2 || nfs_maxvers > 203509673fc0SRick Macklem NFS_VER4) { 203609673fc0SRick Macklem syslog(LOG_ERR, "sysctlbyname(vfs.nfsd." 203709673fc0SRick Macklem "server_max_nfsvers) failed, defaulting to NFSv3"); 203809673fc0SRick Macklem nfs_maxvers = NFS_VER3; 203909673fc0SRick Macklem } 204009673fc0SRick Macklem if (nfs_maxvers == NFS_VER4) 204109673fc0SRick Macklem syslog(LOG_ERR, "NFSv4 requires at least one V4: line"); 204209673fc0SRick Macklem } 204309673fc0SRick Macklem 204496968c22SPawel Jakub Dawidek if (iov != NULL) { 204596968c22SPawel Jakub Dawidek /* Free strings allocated by strdup() in getmntopts.c */ 204696968c22SPawel Jakub Dawidek free(iov[0].iov_base); /* fstype */ 204796968c22SPawel Jakub Dawidek free(iov[2].iov_base); /* fspath */ 204896968c22SPawel Jakub Dawidek free(iov[4].iov_base); /* from */ 204996968c22SPawel Jakub Dawidek free(iov[6].iov_base); /* update */ 205096968c22SPawel Jakub Dawidek free(iov[8].iov_base); /* export */ 205196968c22SPawel Jakub Dawidek free(iov[10].iov_base); /* errmsg */ 205296968c22SPawel Jakub Dawidek 205396968c22SPawel Jakub Dawidek /* free iov, allocated by realloc() */ 205496968c22SPawel Jakub Dawidek free(iov); 205596968c22SPawel Jakub Dawidek iovlen = 0; 205696968c22SPawel Jakub Dawidek } 205796968c22SPawel Jakub Dawidek 2058bcc1d071SRick Macklem /* 2059bcc1d071SRick Macklem * If there was no public fh, clear any previous one set. 2060bcc1d071SRick Macklem */ 20610f0869bcSRick Macklem if (has_publicfh == 0) { 20620f0869bcSRick Macklem LOGDEBUG("clear public fh"); 2063bcc1d071SRick Macklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 20640f0869bcSRick Macklem } 2065c548eb5cSRick Macklem 2066c548eb5cSRick Macklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 2067c548eb5cSRick Macklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 20680f0869bcSRick Macklem LOGDEBUG("eo get_exportlist"); 206996968c22SPawel Jakub Dawidek } 20708fae3551SRodney W. Grimes 20718fae3551SRodney W. Grimes /* 20721a9a992fSRick Macklem * Insert an export entry in the appropriate list. 20731a9a992fSRick Macklem */ 20741a9a992fSRick Macklem static void 20751a9a992fSRick Macklem insert_exports(struct exportlist *ep, struct exportlisthead *exhp) 20761a9a992fSRick Macklem { 207746a6b5c4SRick Macklem uint32_t i; 20781a9a992fSRick Macklem 207946a6b5c4SRick Macklem i = EXPHASH(&ep->ex_fs); 20800f0869bcSRick Macklem LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i); 208146a6b5c4SRick Macklem SLIST_INSERT_HEAD(&exhp[i], ep, entries); 20821a9a992fSRick Macklem } 20831a9a992fSRick Macklem 20841a9a992fSRick Macklem /* 20851a9a992fSRick Macklem * Free up the exports lists passed in as arguments. 20861a9a992fSRick Macklem */ 20871a9a992fSRick Macklem static void 20881a9a992fSRick Macklem free_exports(struct exportlisthead *exhp) 20891a9a992fSRick Macklem { 20901a9a992fSRick Macklem struct exportlist *ep, *ep2; 209146a6b5c4SRick Macklem int i; 20921a9a992fSRick Macklem 209346a6b5c4SRick Macklem for (i = 0; i < exphashsize; i++) { 209446a6b5c4SRick Macklem SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) { 209546a6b5c4SRick Macklem SLIST_REMOVE(&exhp[i], ep, exportlist, entries); 20961a9a992fSRick Macklem free_exp(ep); 20971a9a992fSRick Macklem } 209846a6b5c4SRick Macklem SLIST_INIT(&exhp[i]); 209946a6b5c4SRick Macklem } 21001a9a992fSRick Macklem } 21011a9a992fSRick Macklem 21021a9a992fSRick Macklem /* 21033e08dc74SRick Macklem * Read the exports file(s) and call get_exportlist_one() for each line. 21043e08dc74SRick Macklem */ 21053e08dc74SRick Macklem static void 21060f0869bcSRick Macklem read_exportfile(int passno) 21073e08dc74SRick Macklem { 21083e08dc74SRick Macklem int done, i; 21093e08dc74SRick Macklem 21103e08dc74SRick Macklem /* 21113e08dc74SRick Macklem * Read in the exports file and build the list, calling 21123e08dc74SRick Macklem * nmount() as we go along to push the export rules into the kernel. 21133e08dc74SRick Macklem */ 21143e08dc74SRick Macklem done = 0; 21153e08dc74SRick Macklem for (i = 0; exnames[i] != NULL; i++) { 21163e08dc74SRick Macklem if (debug) 21173e08dc74SRick Macklem warnx("reading exports from %s", exnames[i]); 21183e08dc74SRick Macklem if ((exp_file = fopen(exnames[i], "r")) == NULL) { 21193e08dc74SRick Macklem syslog(LOG_WARNING, "can't open %s", exnames[i]); 21203e08dc74SRick Macklem continue; 21213e08dc74SRick Macklem } 21220f0869bcSRick Macklem get_exportlist_one(passno); 21233e08dc74SRick Macklem fclose(exp_file); 21243e08dc74SRick Macklem done++; 21253e08dc74SRick Macklem } 21263e08dc74SRick Macklem if (done == 0) { 21273e08dc74SRick Macklem syslog(LOG_ERR, "can't open any exports file"); 21283e08dc74SRick Macklem exit(2); 21293e08dc74SRick Macklem } 21303e08dc74SRick Macklem } 21313e08dc74SRick Macklem 21323e08dc74SRick Macklem /* 21330f0869bcSRick Macklem * Compare the export lists against the old ones and do nmount() operations 21340f0869bcSRick Macklem * for any cases that have changed. This avoids doing nmount() for entries 21350f0869bcSRick Macklem * that have not changed. 21360f0869bcSRick Macklem * Return 0 upon success, 1 otherwise. 21370f0869bcSRick Macklem */ 21380f0869bcSRick Macklem static int 21390f0869bcSRick Macklem compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg) 21400f0869bcSRick Macklem { 21410f0869bcSRick Macklem struct exportlist *ep, *oep; 21420f0869bcSRick Macklem struct grouplist *grp; 21430f0869bcSRick Macklem struct statfs fs, ofs; 21440f0869bcSRick Macklem int i, ret; 21450f0869bcSRick Macklem 21460f0869bcSRick Macklem /* 21470f0869bcSRick Macklem * Loop through the current list and look for an entry in the old 21480f0869bcSRick Macklem * list. 21490f0869bcSRick Macklem * If found, check to see if it the same. 21500f0869bcSRick Macklem * If it is not the same, delete and re-export. 21510f0869bcSRick Macklem * Then mark it done on the old list. 21520f0869bcSRick Macklem * else (not found) 21530f0869bcSRick Macklem * export it. 21540f0869bcSRick Macklem * Any entries left in the old list after processing must have their 21550f0869bcSRick Macklem * exports deleted. 21560f0869bcSRick Macklem */ 21570f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 21580f0869bcSRick Macklem SLIST_FOREACH(ep, &exphead[i], entries) { 21590f0869bcSRick Macklem LOGDEBUG("foreach ep=%s", ep->ex_fsdir); 21600f0869bcSRick Macklem oep = ex_search(&ep->ex_fs, oldexphead); 21610f0869bcSRick Macklem if (oep != NULL) { 21620f0869bcSRick Macklem /* 21630f0869bcSRick Macklem * Check the mount paths are the same. 21640f0869bcSRick Macklem * If not, return 1 so that the reload of the 21650f0869bcSRick Macklem * exports will be done in bulk, the 21660f0869bcSRick Macklem * passno == 0 way. 21670f0869bcSRick Macklem */ 21680f0869bcSRick Macklem LOGDEBUG("found old exp"); 21690f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) 21700f0869bcSRick Macklem return (1); 21710f0869bcSRick Macklem LOGDEBUG("same fsdir"); 21720f0869bcSRick Macklem /* 21730f0869bcSRick Macklem * Test to see if the entry is the same. 21740f0869bcSRick Macklem * If not the same delete exports and 21750f0869bcSRick Macklem * re-export. 21760f0869bcSRick Macklem */ 21770f0869bcSRick Macklem if (compare_export(ep, oep) != 0) { 21780f0869bcSRick Macklem /* 21790f0869bcSRick Macklem * Clear has_publicfh if if was set 21800f0869bcSRick Macklem * in the old exports, but only if it 21810f0869bcSRick Macklem * has not been set during processing of 21820f0869bcSRick Macklem * the exports for this pass, as 21830f0869bcSRick Macklem * indicated by has_set_publicfh. 21840f0869bcSRick Macklem */ 21850f0869bcSRick Macklem if (has_set_publicfh == 0 && 21860f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0) 21870f0869bcSRick Macklem has_publicfh = 0; 21880f0869bcSRick Macklem 21890f0869bcSRick Macklem /* Delete and re-export. */ 21900f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0) 21910f0869bcSRick Macklem return (1); 21920f0869bcSRick Macklem delete_export(iov, iovlen, &fs, errmsg); 21930f0869bcSRick Macklem ret = do_export_mount(ep, &fs); 21940f0869bcSRick Macklem if (ret != 0) 21950f0869bcSRick Macklem return (ret); 21960f0869bcSRick Macklem } 21970f0869bcSRick Macklem oep->ex_flag |= EX_DONE; 21980f0869bcSRick Macklem LOGDEBUG("exdone"); 21990f0869bcSRick Macklem } else { 22000f0869bcSRick Macklem LOGDEBUG("not found so export"); 22010f0869bcSRick Macklem /* Not found, so do export. */ 22020f0869bcSRick Macklem if (statfs(ep->ex_fsdir, &fs) < 0) 22030f0869bcSRick Macklem return (1); 22040f0869bcSRick Macklem ret = do_export_mount(ep, &fs); 22050f0869bcSRick Macklem if (ret != 0) 22060f0869bcSRick Macklem return (ret); 22070f0869bcSRick Macklem } 22080f0869bcSRick Macklem } 22090f0869bcSRick Macklem 22100f0869bcSRick Macklem /* Delete exports not done. */ 22110f0869bcSRick Macklem for (i = 0; i < exphashsize; i++) 22120f0869bcSRick Macklem SLIST_FOREACH(oep, &oldexphead[i], entries) { 22130f0869bcSRick Macklem if ((oep->ex_flag & EX_DONE) == 0) { 22140f0869bcSRick Macklem LOGDEBUG("not done delete=%s", oep->ex_fsdir); 22150f0869bcSRick Macklem if (statfs(oep->ex_fsdir, &ofs) >= 0 && 2216245bfd34SRyan Moeller fsidcmp(&oep->ex_fs, &ofs.f_fsid) == 0) { 22170f0869bcSRick Macklem LOGDEBUG("do delete"); 22180f0869bcSRick Macklem /* 22190f0869bcSRick Macklem * Clear has_publicfh if if was set 22200f0869bcSRick Macklem * in the old exports, but only if it 22210f0869bcSRick Macklem * has not been set during processing of 22220f0869bcSRick Macklem * the exports for this pass, as 22230f0869bcSRick Macklem * indicated by has_set_publicfh. 22240f0869bcSRick Macklem */ 22250f0869bcSRick Macklem if (has_set_publicfh == 0 && 22260f0869bcSRick Macklem (oep->ex_flag & EX_PUBLICFH) != 0) 22270f0869bcSRick Macklem has_publicfh = 0; 22280f0869bcSRick Macklem 22290f0869bcSRick Macklem delete_export(iov, iovlen, &ofs, 22300f0869bcSRick Macklem errmsg); 22310f0869bcSRick Macklem } 22320f0869bcSRick Macklem } 22330f0869bcSRick Macklem } 22340f0869bcSRick Macklem 22350f0869bcSRick Macklem /* Do the V4 root exports, as required. */ 22360f0869bcSRick Macklem grp = NULL; 22370f0869bcSRick Macklem if (v4root_ep != NULL) 22380f0869bcSRick Macklem grp = v4root_ep->ex_grphead; 22390f0869bcSRick Macklem v4root_phase = 2; 22400f0869bcSRick Macklem while (v4root_ep != NULL && grp != NULL) { 22410f0869bcSRick Macklem LOGDEBUG("v4root expath=%s", v4root_dirpath); 22420f0869bcSRick Macklem ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon, 22430f0869bcSRick Macklem v4root_dirpath, strlen(v4root_dirpath), &fs, 22440f0869bcSRick Macklem grp->gr_numsecflavors, grp->gr_secflavors); 22450f0869bcSRick Macklem if (ret != 0) { 22460f0869bcSRick Macklem v4root_phase = 0; 22470f0869bcSRick Macklem return (ret); 22480f0869bcSRick Macklem } 22490f0869bcSRick Macklem grp = grp->gr_next; 22500f0869bcSRick Macklem } 22510f0869bcSRick Macklem v4root_phase = 0; 22520f0869bcSRick Macklem free_v4rootexp(); 22530f0869bcSRick Macklem return (0); 22540f0869bcSRick Macklem } 22550f0869bcSRick Macklem 22560f0869bcSRick Macklem /* 22570f0869bcSRick Macklem * Compare old and current exportlist entries for the fsid and return 0 22580f0869bcSRick Macklem * if they are the same, 1 otherwise. 22590f0869bcSRick Macklem */ 22600f0869bcSRick Macklem static int 22610f0869bcSRick Macklem compare_export(struct exportlist *ep, struct exportlist *oep) 22620f0869bcSRick Macklem { 22630f0869bcSRick Macklem struct grouplist *grp, *ogrp; 22640f0869bcSRick Macklem 22650f0869bcSRick Macklem if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) 22660f0869bcSRick Macklem return (1); 22670f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET)) 22680f0869bcSRick Macklem return (1); 22690f0869bcSRick Macklem if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) || 22700f0869bcSRick Macklem (ep->ex_defdir == NULL && oep->ex_defdir != NULL)) 22710f0869bcSRick Macklem return (1); 22720f0869bcSRick Macklem if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) != 22730f0869bcSRick Macklem (oep->ex_defdir->dp_flag & DP_DEFSET)) 22740f0869bcSRick Macklem return (1); 22750f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors != 22760f0869bcSRick Macklem oep->ex_defnumsecflavors || ep->ex_defexflags != 22770f0869bcSRick Macklem oep->ex_defexflags || compare_cred(&ep->ex_defanon, 22780f0869bcSRick Macklem &oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors, 22790f0869bcSRick Macklem oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0)) 22800f0869bcSRick Macklem return (1); 22810f0869bcSRick Macklem 22820f0869bcSRick Macklem /* Now, check all the groups. */ 22830f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) 22840f0869bcSRick Macklem ogrp->gr_flag = 0; 22850f0869bcSRick Macklem for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) { 22860f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = 22870f0869bcSRick Macklem ogrp->gr_next) 22880f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0 && 22890f0869bcSRick Macklem grp->gr_numsecflavors == ogrp->gr_numsecflavors && 22900f0869bcSRick Macklem grp->gr_exflags == ogrp->gr_exflags && 22910f0869bcSRick Macklem compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 && 22920f0869bcSRick Macklem compare_secflavor(grp->gr_secflavors, 22930f0869bcSRick Macklem ogrp->gr_secflavors, grp->gr_numsecflavors) == 0) 22940f0869bcSRick Macklem break; 22950f0869bcSRick Macklem if (ogrp != NULL) 22960f0869bcSRick Macklem ogrp->gr_flag |= GR_FND; 22970f0869bcSRick Macklem else 22980f0869bcSRick Macklem return (1); 22990f0869bcSRick Macklem } 23000f0869bcSRick Macklem for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) 23010f0869bcSRick Macklem if ((ogrp->gr_flag & GR_FND) == 0) 23020f0869bcSRick Macklem return (1); 23030f0869bcSRick Macklem return (0); 23040f0869bcSRick Macklem } 23050f0869bcSRick Macklem 23060f0869bcSRick Macklem /* 23070f0869bcSRick Macklem * This algorithm compares two arrays of "n" items. It returns 0 if they are 23080f0869bcSRick Macklem * the "same" and 1 otherwise. Although suboptimal, it is always safe to 23090f0869bcSRick Macklem * return 1, which makes compare_nmount_export() reload the exports entry. 23100f0869bcSRick Macklem * "same" refers to having the same set of values in the two arrays. 23110f0869bcSRick Macklem * The arrays are in no particular order and duplicates (multiple entries 23120f0869bcSRick Macklem * in an array with the same value) is allowed. 23130f0869bcSRick Macklem * The algorithm is inefficient, but the common case of indentical arrays is 23140f0869bcSRick Macklem * handled first and "n" is normally fairly small. 23150f0869bcSRick Macklem * Since the two functions need the same algorithm but for arrays of 23160f0869bcSRick Macklem * different types (gid_t vs int), this is done as a macro. 23170f0869bcSRick Macklem */ 23180f0869bcSRick Macklem #define COMPARE_ARRAYS(a1, a2, n) \ 23190f0869bcSRick Macklem do { \ 23200f0869bcSRick Macklem int fnd, fndarray[(n)], i, j; \ 23210f0869bcSRick Macklem /* Handle common case of identical arrays. */ \ 23220f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 23230f0869bcSRick Macklem if ((a1)[i] != (a2)[i]) \ 23240f0869bcSRick Macklem break; \ 23250f0869bcSRick Macklem if (i == (n)) \ 23260f0869bcSRick Macklem return (0); \ 23270f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 23280f0869bcSRick Macklem fndarray[i] = 0; \ 23290f0869bcSRick Macklem for (i = 0; i < (n); i++) { \ 23300f0869bcSRick Macklem fnd = 0; \ 23310f0869bcSRick Macklem for (j = 0; j < (n); j++) { \ 23320f0869bcSRick Macklem if ((a1)[i] == (a2)[j]) { \ 23330f0869bcSRick Macklem fndarray[j] = 1; \ 23340f0869bcSRick Macklem fnd = 1; \ 23350f0869bcSRick Macklem } \ 23360f0869bcSRick Macklem } \ 23370f0869bcSRick Macklem if (fnd == 0) \ 23380f0869bcSRick Macklem return (1); \ 23390f0869bcSRick Macklem } \ 23400f0869bcSRick Macklem for (i = 0; i < (n); i++) \ 23410f0869bcSRick Macklem if (fndarray[i] == 0) \ 23420f0869bcSRick Macklem return (1); \ 23430f0869bcSRick Macklem return (0); \ 23440f0869bcSRick Macklem } while (0) 23450f0869bcSRick Macklem 23460f0869bcSRick Macklem /* 2347cc5efddeSRick Macklem * Compare two struct expcred's. Return 0 if the same and 1 otherwise. 23480f0869bcSRick Macklem */ 23490f0869bcSRick Macklem static int 2350cc5efddeSRick Macklem compare_cred(struct expcred *cr0, struct expcred *cr1) 23510f0869bcSRick Macklem { 23520f0869bcSRick Macklem 23530f0869bcSRick Macklem if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) 23540f0869bcSRick Macklem return (1); 23550f0869bcSRick Macklem 23560f0869bcSRick Macklem COMPARE_ARRAYS(cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups); 23570f0869bcSRick Macklem } 23580f0869bcSRick Macklem 23590f0869bcSRick Macklem /* 23600f0869bcSRick Macklem * Compare two lists of security flavors. Return 0 if the same and 1 otherwise. 23610f0869bcSRick Macklem */ 23620f0869bcSRick Macklem static int 23630f0869bcSRick Macklem compare_secflavor(int *sec1, int *sec2, int nsec) 23640f0869bcSRick Macklem { 23650f0869bcSRick Macklem 23660f0869bcSRick Macklem COMPARE_ARRAYS(sec1, sec2, nsec); 23670f0869bcSRick Macklem } 23680f0869bcSRick Macklem 23690f0869bcSRick Macklem /* 23703e08dc74SRick Macklem * Delete an exports entry. 23713e08dc74SRick Macklem */ 23723e08dc74SRick Macklem static void 23733e08dc74SRick Macklem delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) 23743e08dc74SRick Macklem { 23753e08dc74SRick Macklem struct xvfsconf vfc; 23763e08dc74SRick Macklem 23773e08dc74SRick Macklem if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 23783e08dc74SRick Macklem syslog(LOG_ERR, "getvfsbyname() failed for %s", 23793e08dc74SRick Macklem fsp->f_fstypename); 23803e08dc74SRick Macklem return; 23813e08dc74SRick Macklem } 23823e08dc74SRick Macklem 23833e08dc74SRick Macklem /* 23843e08dc74SRick Macklem * We do not need to delete "export" flag from 23853e08dc74SRick Macklem * filesystems that do not have it set. 23863e08dc74SRick Macklem */ 23873e08dc74SRick Macklem if (!(fsp->f_flags & MNT_EXPORTED)) 23883e08dc74SRick Macklem return; 23893e08dc74SRick Macklem /* 23903e08dc74SRick Macklem * Do not delete export for network filesystem by 23913e08dc74SRick Macklem * passing "export" arg to nmount(). 23923e08dc74SRick Macklem * It only makes sense to do this for local filesystems. 23933e08dc74SRick Macklem */ 23943e08dc74SRick Macklem if (vfc.vfc_flags & VFCF_NETWORK) 23953e08dc74SRick Macklem return; 23963e08dc74SRick Macklem 23973e08dc74SRick Macklem iov[1].iov_base = fsp->f_fstypename; 23983e08dc74SRick Macklem iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 23993e08dc74SRick Macklem iov[3].iov_base = fsp->f_mntonname; 24003e08dc74SRick Macklem iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 24013e08dc74SRick Macklem iov[5].iov_base = fsp->f_mntfromname; 24023e08dc74SRick Macklem iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 24033e08dc74SRick Macklem errmsg[0] = '\0'; 24043e08dc74SRick Macklem 24053e08dc74SRick Macklem /* 24063e08dc74SRick Macklem * EXDEV is returned when path exists but is not a 24073e08dc74SRick Macklem * mount point. May happens if raced with unmount. 24083e08dc74SRick Macklem */ 24093e08dc74SRick Macklem if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT && 24103e08dc74SRick Macklem errno != ENOTSUP && errno != EXDEV) { 24113e08dc74SRick Macklem syslog(LOG_ERR, 24123e08dc74SRick Macklem "can't delete exports for %s: %m %s", 24133e08dc74SRick Macklem fsp->f_mntonname, errmsg); 24143e08dc74SRick Macklem } 24153e08dc74SRick Macklem } 24163e08dc74SRick Macklem 24173e08dc74SRick Macklem /* 24188fae3551SRodney W. Grimes * Allocate an export list element 24198fae3551SRodney W. Grimes */ 242019c46d8cSEdward Tomasz Napierala static struct exportlist * 2421a7a7d96cSPhilippe Charnier get_exp(void) 24228fae3551SRodney W. Grimes { 24238fae3551SRodney W. Grimes struct exportlist *ep; 24248fae3551SRodney W. Grimes 242553750151SXin LI ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 24268fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) 24278fae3551SRodney W. Grimes out_of_mem(); 24288fae3551SRodney W. Grimes return (ep); 24298fae3551SRodney W. Grimes } 24308fae3551SRodney W. Grimes 24318fae3551SRodney W. Grimes /* 24328fae3551SRodney W. Grimes * Allocate a group list element 24338fae3551SRodney W. Grimes */ 243419c46d8cSEdward Tomasz Napierala static struct grouplist * 2435a7a7d96cSPhilippe Charnier get_grp(void) 24368fae3551SRodney W. Grimes { 24378fae3551SRodney W. Grimes struct grouplist *gp; 24388fae3551SRodney W. Grimes 243953750151SXin LI gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 24408fae3551SRodney W. Grimes if (gp == (struct grouplist *)NULL) 24418fae3551SRodney W. Grimes out_of_mem(); 24428fae3551SRodney W. Grimes return (gp); 24438fae3551SRodney W. Grimes } 24448fae3551SRodney W. Grimes 24458fae3551SRodney W. Grimes /* 24468fae3551SRodney W. Grimes * Clean up upon an error in get_exportlist(). 24478fae3551SRodney W. Grimes */ 244819c46d8cSEdward Tomasz Napierala static void 2449354fce28SConrad Meyer getexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason) 24508fae3551SRodney W. Grimes { 24518fae3551SRodney W. Grimes struct grouplist *tgrp; 24528fae3551SRodney W. Grimes 2453354fce28SConrad Meyer if (!(opt_flags & OP_QUIET)) { 2454354fce28SConrad Meyer if (reason != NULL) 2455354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s': %s", line, 2456354fce28SConrad Meyer reason); 2457354fce28SConrad Meyer else 2458354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s'", line); 2459354fce28SConrad Meyer } 24608fae3551SRodney W. Grimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 24618fae3551SRodney W. Grimes free_exp(ep); 24628fae3551SRodney W. Grimes while (grp) { 24638fae3551SRodney W. Grimes tgrp = grp; 24648fae3551SRodney W. Grimes grp = grp->gr_next; 24658fae3551SRodney W. Grimes free_grp(tgrp); 24668fae3551SRodney W. Grimes } 24678fae3551SRodney W. Grimes } 24688fae3551SRodney W. Grimes 24698fae3551SRodney W. Grimes /* 24708fae3551SRodney W. Grimes * Search the export list for a matching fs. 24718fae3551SRodney W. Grimes */ 247219c46d8cSEdward Tomasz Napierala static struct exportlist * 24731a9a992fSRick Macklem ex_search(fsid_t *fsid, struct exportlisthead *exhp) 24748fae3551SRodney W. Grimes { 24758fae3551SRodney W. Grimes struct exportlist *ep; 247646a6b5c4SRick Macklem uint32_t i; 24778fae3551SRodney W. Grimes 247846a6b5c4SRick Macklem i = EXPHASH(fsid); 247946a6b5c4SRick Macklem SLIST_FOREACH(ep, &exhp[i], entries) { 2480245bfd34SRyan Moeller if (fsidcmp(&ep->ex_fs, fsid) == 0) 24818fae3551SRodney W. Grimes return (ep); 24828fae3551SRodney W. Grimes } 2483c9ac0f71SEmmanuel Vadot 24848fae3551SRodney W. Grimes return (ep); 24858fae3551SRodney W. Grimes } 24868fae3551SRodney W. Grimes 24878fae3551SRodney W. Grimes /* 24888fae3551SRodney W. Grimes * Add a directory path to the list. 24898fae3551SRodney W. Grimes */ 249019c46d8cSEdward Tomasz Napierala static char * 2491a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len) 24928fae3551SRodney W. Grimes { 24938fae3551SRodney W. Grimes struct dirlist *dp; 24948fae3551SRodney W. Grimes 249589b859e3SEmmanuel Vadot dp = malloc(sizeof (struct dirlist)); 249674853402SPhilippe Charnier if (dp == (struct dirlist *)NULL) 249774853402SPhilippe Charnier out_of_mem(); 24988fae3551SRodney W. Grimes dp->dp_left = *dpp; 24998fae3551SRodney W. Grimes dp->dp_right = (struct dirlist *)NULL; 25008fae3551SRodney W. Grimes dp->dp_flag = 0; 25018fae3551SRodney W. Grimes dp->dp_hosts = (struct hostlist *)NULL; 2502380a3fcdSEmmanuel Vadot dp->dp_dirp = strndup(cp, len); 2503380a3fcdSEmmanuel Vadot if (dp->dp_dirp == NULL) 2504380a3fcdSEmmanuel Vadot out_of_mem(); 25058fae3551SRodney W. Grimes *dpp = dp; 25068fae3551SRodney W. Grimes return (dp->dp_dirp); 25078fae3551SRodney W. Grimes } 25088fae3551SRodney W. Grimes 25098fae3551SRodney W. Grimes /* 25108fae3551SRodney W. Grimes * Hang the dir list element off the dirpath binary tree as required 25118fae3551SRodney W. Grimes * and update the entry for host. 25128fae3551SRodney W. Grimes */ 251319c46d8cSEdward Tomasz Napierala static void 2514a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 2515cc5efddeSRick Macklem int flags, struct expcred *anoncrp, uint64_t exflags) 25168fae3551SRodney W. Grimes { 25178fae3551SRodney W. Grimes struct hostlist *hp; 25188fae3551SRodney W. Grimes struct dirlist *dp2; 25198fae3551SRodney W. Grimes 2520a62dc406SDoug Rabson if (flags & OP_ALLDIRS) { 25218fae3551SRodney W. Grimes if (ep->ex_defdir) 25228fae3551SRodney W. Grimes free((caddr_t)dp); 25238fae3551SRodney W. Grimes else 25248fae3551SRodney W. Grimes ep->ex_defdir = dp; 2525a62dc406SDoug Rabson if (grp == (struct grouplist *)NULL) { 25260f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET; 25278fae3551SRodney W. Grimes ep->ex_defdir->dp_flag |= DP_DEFSET; 2528c3f86a25SRick Macklem /* Save the default security flavors list. */ 2529c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2530c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2531c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2532c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 2533cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp); 25340f0869bcSRick Macklem ep->ex_defexflags = exflags; 2535a62dc406SDoug Rabson } else while (grp) { 25368fae3551SRodney W. Grimes hp = get_ht(); 25378fae3551SRodney W. Grimes hp->ht_grp = grp; 25388fae3551SRodney W. Grimes hp->ht_next = ep->ex_defdir->dp_hosts; 25398fae3551SRodney W. Grimes ep->ex_defdir->dp_hosts = hp; 2540c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 2541c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2542c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2543c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2544c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 25458fae3551SRodney W. Grimes grp = grp->gr_next; 25468fae3551SRodney W. Grimes } 25478fae3551SRodney W. Grimes } else { 25488fae3551SRodney W. Grimes 25498fae3551SRodney W. Grimes /* 255074853402SPhilippe Charnier * Loop through the directories adding them to the tree. 25518fae3551SRodney W. Grimes */ 25528fae3551SRodney W. Grimes while (dp) { 25538fae3551SRodney W. Grimes dp2 = dp->dp_left; 25540f0869bcSRick Macklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp, 25550f0869bcSRick Macklem exflags); 25568fae3551SRodney W. Grimes dp = dp2; 25578fae3551SRodney W. Grimes } 25588fae3551SRodney W. Grimes } 25598fae3551SRodney W. Grimes } 25608fae3551SRodney W. Grimes 25618fae3551SRodney W. Grimes /* 25628fae3551SRodney W. Grimes * Traverse the binary tree either updating a node that is already there 25638fae3551SRodney W. Grimes * for the new directory or adding the new node. 25648fae3551SRodney W. Grimes */ 256519c46d8cSEdward Tomasz Napierala static void 2566a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2567cc5efddeSRick Macklem int flags, struct exportlist *ep, struct expcred *anoncrp, 2568cc5efddeSRick Macklem uint64_t exflags) 25698fae3551SRodney W. Grimes { 25708fae3551SRodney W. Grimes struct dirlist *dp; 25718fae3551SRodney W. Grimes struct hostlist *hp; 25728fae3551SRodney W. Grimes int cmp; 25738fae3551SRodney W. Grimes 25748fae3551SRodney W. Grimes dp = *dpp; 25758fae3551SRodney W. Grimes if (dp) { 25768fae3551SRodney W. Grimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 25778fae3551SRodney W. Grimes if (cmp > 0) { 25780f0869bcSRick Macklem add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp, 25790f0869bcSRick Macklem exflags); 25808fae3551SRodney W. Grimes return; 25818fae3551SRodney W. Grimes } else if (cmp < 0) { 25820f0869bcSRick Macklem add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp, 25830f0869bcSRick Macklem exflags); 25848fae3551SRodney W. Grimes return; 25858fae3551SRodney W. Grimes } else 25868fae3551SRodney W. Grimes free((caddr_t)newdp); 25878fae3551SRodney W. Grimes } else { 25888fae3551SRodney W. Grimes dp = newdp; 25898fae3551SRodney W. Grimes dp->dp_left = (struct dirlist *)NULL; 25908fae3551SRodney W. Grimes *dpp = dp; 25918fae3551SRodney W. Grimes } 25928fae3551SRodney W. Grimes if (grp) { 25938fae3551SRodney W. Grimes 25948fae3551SRodney W. Grimes /* 25958fae3551SRodney W. Grimes * Hang all of the host(s) off of the directory point. 25968fae3551SRodney W. Grimes */ 25978fae3551SRodney W. Grimes do { 25988fae3551SRodney W. Grimes hp = get_ht(); 25998fae3551SRodney W. Grimes hp->ht_grp = grp; 26008fae3551SRodney W. Grimes hp->ht_next = dp->dp_hosts; 26018fae3551SRodney W. Grimes dp->dp_hosts = hp; 2602c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 2603c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2604c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2605c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2606c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 26078fae3551SRodney W. Grimes grp = grp->gr_next; 26088fae3551SRodney W. Grimes } while (grp); 2609a62dc406SDoug Rabson } else { 26100f0869bcSRick Macklem ep->ex_flag |= EX_DEFSET; 26118fae3551SRodney W. Grimes dp->dp_flag |= DP_DEFSET; 2612c3f86a25SRick Macklem /* Save the default security flavors list. */ 2613c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2614c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2615c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2616c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 2617cc5efddeSRick Macklem cp_cred(&ep->ex_defanon, anoncrp); 26180f0869bcSRick Macklem ep->ex_defexflags = exflags; 2619a62dc406SDoug Rabson } 26208fae3551SRodney W. Grimes } 26218fae3551SRodney W. Grimes 26228fae3551SRodney W. Grimes /* 26238fae3551SRodney W. Grimes * Search for a dirpath on the export point. 26248fae3551SRodney W. Grimes */ 262519c46d8cSEdward Tomasz Napierala static struct dirlist * 2626a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp) 26278fae3551SRodney W. Grimes { 26288fae3551SRodney W. Grimes int cmp; 26298fae3551SRodney W. Grimes 26308fae3551SRodney W. Grimes if (dp) { 26318360efbdSAlfred Perlstein cmp = strcmp(dp->dp_dirp, dirp); 26328fae3551SRodney W. Grimes if (cmp > 0) 26338360efbdSAlfred Perlstein return (dirp_search(dp->dp_left, dirp)); 26348fae3551SRodney W. Grimes else if (cmp < 0) 26358360efbdSAlfred Perlstein return (dirp_search(dp->dp_right, dirp)); 26368fae3551SRodney W. Grimes else 26378fae3551SRodney W. Grimes return (dp); 26388fae3551SRodney W. Grimes } 26398fae3551SRodney W. Grimes return (dp); 26408fae3551SRodney W. Grimes } 26418fae3551SRodney W. Grimes 26428fae3551SRodney W. Grimes /* 26438fae3551SRodney W. Grimes * Scan for a host match in a directory tree. 26448fae3551SRodney W. Grimes */ 264519c46d8cSEdward Tomasz Napierala static int 2646a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2647c3f86a25SRick Macklem int *hostsetp, int *numsecflavors, int **secflavorsp) 26488fae3551SRodney W. Grimes { 26498fae3551SRodney W. Grimes struct hostlist *hp; 26508fae3551SRodney W. Grimes struct grouplist *grp; 26518360efbdSAlfred Perlstein struct addrinfo *ai; 26528fae3551SRodney W. Grimes 26538fae3551SRodney W. Grimes if (dp) { 26548fae3551SRodney W. Grimes if (dp->dp_flag & DP_DEFSET) 2655a62dc406SDoug Rabson *defsetp = dp->dp_flag; 26568fae3551SRodney W. Grimes hp = dp->dp_hosts; 26578fae3551SRodney W. Grimes while (hp) { 26588fae3551SRodney W. Grimes grp = hp->ht_grp; 26598fae3551SRodney W. Grimes switch (grp->gr_type) { 26608fae3551SRodney W. Grimes case GT_HOST: 26618360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 26628360efbdSAlfred Perlstein for (; ai; ai = ai->ai_next) { 266360caaee2SIan Dowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 26648360efbdSAlfred Perlstein *hostsetp = 26658360efbdSAlfred Perlstein (hp->ht_flag | DP_HOSTSET); 2666c3f86a25SRick Macklem if (numsecflavors != NULL) { 2667c3f86a25SRick Macklem *numsecflavors = 2668c3f86a25SRick Macklem grp->gr_numsecflavors; 2669c3f86a25SRick Macklem *secflavorsp = 2670c3f86a25SRick Macklem grp->gr_secflavors; 2671c3f86a25SRick Macklem } 26728fae3551SRodney W. Grimes return (1); 2673a62dc406SDoug Rabson } 26748fae3551SRodney W. Grimes } 26758fae3551SRodney W. Grimes break; 26768fae3551SRodney W. Grimes case GT_NET: 267760caaee2SIan Dowse if (!sacmp(saddr, (struct sockaddr *) 267860caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_net, 267960caaee2SIan Dowse (struct sockaddr *) 268060caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_mask)) { 2681a62dc406SDoug Rabson *hostsetp = (hp->ht_flag | DP_HOSTSET); 2682c3f86a25SRick Macklem if (numsecflavors != NULL) { 2683c3f86a25SRick Macklem *numsecflavors = 2684c3f86a25SRick Macklem grp->gr_numsecflavors; 2685c3f86a25SRick Macklem *secflavorsp = 2686c3f86a25SRick Macklem grp->gr_secflavors; 2687c3f86a25SRick Macklem } 26888fae3551SRodney W. Grimes return (1); 2689a62dc406SDoug Rabson } 26908fae3551SRodney W. Grimes break; 269160caaee2SIan Dowse } 26928fae3551SRodney W. Grimes hp = hp->ht_next; 26938fae3551SRodney W. Grimes } 26948fae3551SRodney W. Grimes } 26958fae3551SRodney W. Grimes return (0); 26968fae3551SRodney W. Grimes } 26978fae3551SRodney W. Grimes 26988fae3551SRodney W. Grimes /* 26998fae3551SRodney W. Grimes * Scan tree for a host that matches the address. 27008fae3551SRodney W. Grimes */ 270119c46d8cSEdward Tomasz Napierala static int 2702a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr) 27038fae3551SRodney W. Grimes { 2704a62dc406SDoug Rabson int defset, hostset; 27058fae3551SRodney W. Grimes 27068fae3551SRodney W. Grimes if (dp) { 27078fae3551SRodney W. Grimes if (scan_tree(dp->dp_left, saddr)) 27088fae3551SRodney W. Grimes return (1); 2709c3f86a25SRick Macklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 27108fae3551SRodney W. Grimes return (1); 27118fae3551SRodney W. Grimes if (scan_tree(dp->dp_right, saddr)) 27128fae3551SRodney W. Grimes return (1); 27138fae3551SRodney W. Grimes } 27148fae3551SRodney W. Grimes return (0); 27158fae3551SRodney W. Grimes } 27168fae3551SRodney W. Grimes 27178fae3551SRodney W. Grimes /* 27188fae3551SRodney W. Grimes * Traverse the dirlist tree and free it up. 27198fae3551SRodney W. Grimes */ 272019c46d8cSEdward Tomasz Napierala static void 2721a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp) 27228fae3551SRodney W. Grimes { 27238fae3551SRodney W. Grimes 27248fae3551SRodney W. Grimes if (dp) { 27258fae3551SRodney W. Grimes free_dir(dp->dp_left); 27268fae3551SRodney W. Grimes free_dir(dp->dp_right); 27278fae3551SRodney W. Grimes free_host(dp->dp_hosts); 272892e73cccSEmmanuel Vadot free(dp->dp_dirp); 272992e73cccSEmmanuel Vadot free(dp); 27308fae3551SRodney W. Grimes } 27318fae3551SRodney W. Grimes } 27328fae3551SRodney W. Grimes 27338fae3551SRodney W. Grimes /* 2734a9148abdSDoug Rabson * Parse a colon separated list of security flavors 2735a9148abdSDoug Rabson */ 273619c46d8cSEdward Tomasz Napierala static int 2737a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep) 2738a9148abdSDoug Rabson { 2739a9148abdSDoug Rabson char *cp, savedc; 2740a9148abdSDoug Rabson int flavor; 2741a9148abdSDoug Rabson 2742a9148abdSDoug Rabson ep->ex_numsecflavors = 0; 2743a9148abdSDoug Rabson for (;;) { 2744a9148abdSDoug Rabson cp = strchr(seclist, ':'); 2745a9148abdSDoug Rabson if (cp) { 2746a9148abdSDoug Rabson savedc = *cp; 2747a9148abdSDoug Rabson *cp = '\0'; 2748a9148abdSDoug Rabson } 2749a9148abdSDoug Rabson 2750a9148abdSDoug Rabson if (!strcmp(seclist, "sys")) 2751a9148abdSDoug Rabson flavor = AUTH_SYS; 2752a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5")) 2753a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5; 2754a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5i")) 2755a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5I; 2756a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5p")) 2757a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5P; 2758a9148abdSDoug Rabson else { 2759a9148abdSDoug Rabson if (cp) 2760a9148abdSDoug Rabson *cp = savedc; 2761a9148abdSDoug Rabson syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2762a9148abdSDoug Rabson return (1); 2763a9148abdSDoug Rabson } 2764a9148abdSDoug Rabson if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2765a9148abdSDoug Rabson if (cp) 2766a9148abdSDoug Rabson *cp = savedc; 2767a9148abdSDoug Rabson syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2768a9148abdSDoug Rabson return (1); 2769a9148abdSDoug Rabson } 2770a9148abdSDoug Rabson ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2771a9148abdSDoug Rabson ep->ex_numsecflavors++; 2772a9148abdSDoug Rabson if (cp) { 2773a9148abdSDoug Rabson *cp = savedc; 2774a9148abdSDoug Rabson seclist = cp + 1; 2775a9148abdSDoug Rabson } else { 2776a9148abdSDoug Rabson break; 2777a9148abdSDoug Rabson } 2778a9148abdSDoug Rabson } 2779a9148abdSDoug Rabson return (0); 2780a9148abdSDoug Rabson } 2781a9148abdSDoug Rabson 2782a9148abdSDoug Rabson /* 27838fae3551SRodney W. Grimes * Parse the option string and update fields. 27848fae3551SRodney W. Grimes * Option arguments may either be -<option>=<value> or 27858fae3551SRodney W. Grimes * -<option> <value> 27868fae3551SRodney W. Grimes */ 278719c46d8cSEdward Tomasz Napierala static int 2788a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2789cc5efddeSRick Macklem int *has_hostp, uint64_t *exflagsp, struct expcred *cr) 27908fae3551SRodney W. Grimes { 27918fae3551SRodney W. Grimes char *cpoptarg, *cpoptend; 27928fae3551SRodney W. Grimes char *cp, *endcp, *cpopt, savedc, savedc2; 27938fae3551SRodney W. Grimes int allflag, usedarg; 27948fae3551SRodney W. Grimes 2795cb479b11SAlfred Perlstein savedc2 = '\0'; 27968fae3551SRodney W. Grimes cpopt = *cpp; 27978fae3551SRodney W. Grimes cpopt++; 27988fae3551SRodney W. Grimes cp = *endcpp; 27998fae3551SRodney W. Grimes savedc = *cp; 28008fae3551SRodney W. Grimes *cp = '\0'; 28018fae3551SRodney W. Grimes while (cpopt && *cpopt) { 28028fae3551SRodney W. Grimes allflag = 1; 28038fae3551SRodney W. Grimes usedarg = -2; 280474853402SPhilippe Charnier if ((cpoptend = strchr(cpopt, ','))) { 28058fae3551SRodney W. Grimes *cpoptend++ = '\0'; 280674853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 28078fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 28088fae3551SRodney W. Grimes } else { 280974853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 28108fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 28118fae3551SRodney W. Grimes else { 28128fae3551SRodney W. Grimes *cp = savedc; 28138fae3551SRodney W. Grimes nextfield(&cp, &endcp); 28148fae3551SRodney W. Grimes **endcpp = '\0'; 28158fae3551SRodney W. Grimes if (endcp > cp && *cp != '-') { 28168fae3551SRodney W. Grimes cpoptarg = cp; 28178fae3551SRodney W. Grimes savedc2 = *endcp; 28188fae3551SRodney W. Grimes *endcp = '\0'; 28198fae3551SRodney W. Grimes usedarg = 0; 28208fae3551SRodney W. Grimes } 28218fae3551SRodney W. Grimes } 28228fae3551SRodney W. Grimes } 28238fae3551SRodney W. Grimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 28248fae3551SRodney W. Grimes *exflagsp |= MNT_EXRDONLY; 28258fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 28268fae3551SRodney W. Grimes !(allflag = strcmp(cpopt, "mapall")) || 28278fae3551SRodney W. Grimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 28288fae3551SRodney W. Grimes usedarg++; 28298fae3551SRodney W. Grimes parsecred(cpoptarg, cr); 28308fae3551SRodney W. Grimes if (allflag == 0) { 28318fae3551SRodney W. Grimes *exflagsp |= MNT_EXPORTANON; 28328fae3551SRodney W. Grimes opt_flags |= OP_MAPALL; 28338fae3551SRodney W. Grimes } else 28348fae3551SRodney W. Grimes opt_flags |= OP_MAPROOT; 28358fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 28368fae3551SRodney W. Grimes !strcmp(cpopt, "m"))) { 28378fae3551SRodney W. Grimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 283874853402SPhilippe Charnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 28398fae3551SRodney W. Grimes return (1); 28408fae3551SRodney W. Grimes } 28418fae3551SRodney W. Grimes usedarg++; 28428fae3551SRodney W. Grimes opt_flags |= OP_MASK; 28438fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 28448fae3551SRodney W. Grimes !strcmp(cpopt, "n"))) { 28458360efbdSAlfred Perlstein if (strchr(cpoptarg, '/') != NULL) { 28468360efbdSAlfred Perlstein if (debug) 28478360efbdSAlfred Perlstein fprintf(stderr, "setting OP_MASKLEN\n"); 28488360efbdSAlfred Perlstein opt_flags |= OP_MASKLEN; 28498360efbdSAlfred Perlstein } 28508fae3551SRodney W. Grimes if (grp->gr_type != GT_NULL) { 285174853402SPhilippe Charnier syslog(LOG_ERR, "network/host conflict"); 28528fae3551SRodney W. Grimes return (1); 28538fae3551SRodney W. Grimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 285474853402SPhilippe Charnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 28558fae3551SRodney W. Grimes return (1); 28568fae3551SRodney W. Grimes } 28578fae3551SRodney W. Grimes grp->gr_type = GT_NET; 28588fae3551SRodney W. Grimes *has_hostp = 1; 28598fae3551SRodney W. Grimes usedarg++; 28608fae3551SRodney W. Grimes opt_flags |= OP_NET; 28618fae3551SRodney W. Grimes } else if (!strcmp(cpopt, "alldirs")) { 28628fae3551SRodney W. Grimes opt_flags |= OP_ALLDIRS; 2863cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "public")) { 2864cb3923e0SDoug Rabson *exflagsp |= MNT_EXPUBLIC; 2865cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "webnfs")) { 2866cb3923e0SDoug Rabson *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2867cb3923e0SDoug Rabson opt_flags |= OP_MAPALL; 2868cb3923e0SDoug Rabson } else if (cpoptarg && !strcmp(cpopt, "index")) { 2869cb3923e0SDoug Rabson ep->ex_indexfile = strdup(cpoptarg); 2870288fa14aSJoerg Wunsch } else if (!strcmp(cpopt, "quiet")) { 2871288fa14aSJoerg Wunsch opt_flags |= OP_QUIET; 2872dcdc127bSSergey Kandaurov } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2873a9148abdSDoug Rabson if (parsesec(cpoptarg, ep)) 2874a9148abdSDoug Rabson return (1); 2875a9148abdSDoug Rabson opt_flags |= OP_SEC; 2876a9148abdSDoug Rabson usedarg++; 2877813837baSRick Macklem } else if (!strcmp(cpopt, "tls")) { 2878813837baSRick Macklem *exflagsp |= MNT_EXTLS; 2879813837baSRick Macklem } else if (!strcmp(cpopt, "tlscert")) { 2880813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT); 2881813837baSRick Macklem } else if (!strcmp(cpopt, "tlscertuser")) { 2882813837baSRick Macklem *exflagsp |= (MNT_EXTLS | MNT_EXTLSCERT | 2883813837baSRick Macklem MNT_EXTLSCERTUSER); 28848fae3551SRodney W. Grimes } else { 288574853402SPhilippe Charnier syslog(LOG_ERR, "bad opt %s", cpopt); 28868fae3551SRodney W. Grimes return (1); 28878fae3551SRodney W. Grimes } 28888fae3551SRodney W. Grimes if (usedarg >= 0) { 28898fae3551SRodney W. Grimes *endcp = savedc2; 28908fae3551SRodney W. Grimes **endcpp = savedc; 28918fae3551SRodney W. Grimes if (usedarg > 0) { 28928fae3551SRodney W. Grimes *cpp = cp; 28938fae3551SRodney W. Grimes *endcpp = endcp; 28948fae3551SRodney W. Grimes } 28958fae3551SRodney W. Grimes return (0); 28968fae3551SRodney W. Grimes } 28978fae3551SRodney W. Grimes cpopt = cpoptend; 28988fae3551SRodney W. Grimes } 28998fae3551SRodney W. Grimes **endcpp = savedc; 29008fae3551SRodney W. Grimes return (0); 29018fae3551SRodney W. Grimes } 29028fae3551SRodney W. Grimes 29038fae3551SRodney W. Grimes /* 29048fae3551SRodney W. Grimes * Translate a character string to the corresponding list of network 29058fae3551SRodney W. Grimes * addresses for a hostname. 29068fae3551SRodney W. Grimes */ 290719c46d8cSEdward Tomasz Napierala static int 2908a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 29098fae3551SRodney W. Grimes { 29108b5a6d67SBill Paul struct grouplist *checkgrp; 291101709abfSIan Dowse struct addrinfo *ai, *tai, hints; 29128360efbdSAlfred Perlstein int ecode; 29138360efbdSAlfred Perlstein char host[NI_MAXHOST]; 29148fae3551SRodney W. Grimes 29158360efbdSAlfred Perlstein if (grp->gr_type != GT_NULL) { 29168360efbdSAlfred Perlstein syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 29178fae3551SRodney W. Grimes return (1); 29188fae3551SRodney W. Grimes } 29198360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 29208360efbdSAlfred Perlstein hints.ai_flags = AI_CANONNAME; 29218360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 29228360efbdSAlfred Perlstein ecode = getaddrinfo(cp, NULL, &hints, &ai); 29238360efbdSAlfred Perlstein if (ecode != 0) { 292401709abfSIan Dowse syslog(LOG_ERR,"can't get address info for host %s", cp); 29258360efbdSAlfred Perlstein return 1; 29268fae3551SRodney W. Grimes } 29278360efbdSAlfred Perlstein grp->gr_ptr.gt_addrinfo = ai; 29288360efbdSAlfred Perlstein while (ai != NULL) { 29298360efbdSAlfred Perlstein if (ai->ai_canonname == NULL) { 29308360efbdSAlfred Perlstein if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 29314f101318SHajimu UMEMOTO sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 29328360efbdSAlfred Perlstein strlcpy(host, "?", sizeof(host)); 29338360efbdSAlfred Perlstein ai->ai_canonname = strdup(host); 29348360efbdSAlfred Perlstein ai->ai_flags |= AI_CANONNAME; 29356d359f31SIan Dowse } 29368fae3551SRodney W. Grimes if (debug) 293701709abfSIan Dowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 293801709abfSIan Dowse /* 293901709abfSIan Dowse * Sanity check: make sure we don't already have an entry 294001709abfSIan Dowse * for this host in the grouplist. 294101709abfSIan Dowse */ 294201709abfSIan Dowse for (checkgrp = tgrp; checkgrp != NULL; 294301709abfSIan Dowse checkgrp = checkgrp->gr_next) { 294401709abfSIan Dowse if (checkgrp->gr_type != GT_HOST) 294501709abfSIan Dowse continue; 294601709abfSIan Dowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 294701709abfSIan Dowse tai = tai->ai_next) { 294860caaee2SIan Dowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 294901709abfSIan Dowse continue; 295001709abfSIan Dowse if (debug) 295101709abfSIan Dowse fprintf(stderr, 295201709abfSIan Dowse "ignoring duplicate host %s\n", 295301709abfSIan Dowse ai->ai_canonname); 295401709abfSIan Dowse grp->gr_type = GT_IGNORE; 295501709abfSIan Dowse return (0); 295601709abfSIan Dowse } 295701709abfSIan Dowse } 29588360efbdSAlfred Perlstein ai = ai->ai_next; 29598360efbdSAlfred Perlstein } 296001709abfSIan Dowse grp->gr_type = GT_HOST; 29618fae3551SRodney W. Grimes return (0); 29628fae3551SRodney W. Grimes } 29638fae3551SRodney W. Grimes 29648fae3551SRodney W. Grimes /* 29658fae3551SRodney W. Grimes * Free up an exports list component 29668fae3551SRodney W. Grimes */ 296719c46d8cSEdward Tomasz Napierala static void 2968a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep) 29698fae3551SRodney W. Grimes { 2970711d44eeSRick Macklem struct grouplist *grp, *tgrp; 29718fae3551SRodney W. Grimes 29728fae3551SRodney W. Grimes if (ep->ex_defdir) { 29738fae3551SRodney W. Grimes free_host(ep->ex_defdir->dp_hosts); 29748fae3551SRodney W. Grimes free((caddr_t)ep->ex_defdir); 29758fae3551SRodney W. Grimes } 29768fae3551SRodney W. Grimes if (ep->ex_fsdir) 29778fae3551SRodney W. Grimes free(ep->ex_fsdir); 2978cb3923e0SDoug Rabson if (ep->ex_indexfile) 2979cb3923e0SDoug Rabson free(ep->ex_indexfile); 29808fae3551SRodney W. Grimes free_dir(ep->ex_dirl); 2981711d44eeSRick Macklem grp = ep->ex_grphead; 2982711d44eeSRick Macklem while (grp) { 2983711d44eeSRick Macklem tgrp = grp; 2984711d44eeSRick Macklem grp = grp->gr_next; 2985711d44eeSRick Macklem free_grp(tgrp); 2986711d44eeSRick Macklem } 29872ffad162SRick Macklem if (ep->ex_defanon.cr_groups != ep->ex_defanon.cr_smallgrps) 29882ffad162SRick Macklem free(ep->ex_defanon.cr_groups); 29898fae3551SRodney W. Grimes free((caddr_t)ep); 29908fae3551SRodney W. Grimes } 29918fae3551SRodney W. Grimes 29928fae3551SRodney W. Grimes /* 29930f0869bcSRick Macklem * Free up the v4root exports. 29940f0869bcSRick Macklem */ 29950f0869bcSRick Macklem static void 29960f0869bcSRick Macklem free_v4rootexp(void) 29970f0869bcSRick Macklem { 29980f0869bcSRick Macklem 29990f0869bcSRick Macklem if (v4root_ep != NULL) { 30000f0869bcSRick Macklem free_exp(v4root_ep); 30010f0869bcSRick Macklem v4root_ep = NULL; 30020f0869bcSRick Macklem } 30030f0869bcSRick Macklem } 30040f0869bcSRick Macklem 30050f0869bcSRick Macklem /* 30068fae3551SRodney W. Grimes * Free hosts. 30078fae3551SRodney W. Grimes */ 300819c46d8cSEdward Tomasz Napierala static void 3009a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp) 30108fae3551SRodney W. Grimes { 30118fae3551SRodney W. Grimes struct hostlist *hp2; 30128fae3551SRodney W. Grimes 30138fae3551SRodney W. Grimes while (hp) { 30148fae3551SRodney W. Grimes hp2 = hp; 30158fae3551SRodney W. Grimes hp = hp->ht_next; 30168fae3551SRodney W. Grimes free((caddr_t)hp2); 30178fae3551SRodney W. Grimes } 30188fae3551SRodney W. Grimes } 30198fae3551SRodney W. Grimes 302019c46d8cSEdward Tomasz Napierala static struct hostlist * 3021a7a7d96cSPhilippe Charnier get_ht(void) 30228fae3551SRodney W. Grimes { 30238fae3551SRodney W. Grimes struct hostlist *hp; 30248fae3551SRodney W. Grimes 30258fae3551SRodney W. Grimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 30268fae3551SRodney W. Grimes if (hp == (struct hostlist *)NULL) 30278fae3551SRodney W. Grimes out_of_mem(); 30288fae3551SRodney W. Grimes hp->ht_next = (struct hostlist *)NULL; 3029a62dc406SDoug Rabson hp->ht_flag = 0; 30308fae3551SRodney W. Grimes return (hp); 30318fae3551SRodney W. Grimes } 30328fae3551SRodney W. Grimes 30338fae3551SRodney W. Grimes /* 30348fae3551SRodney W. Grimes * Out of memory, fatal 30358fae3551SRodney W. Grimes */ 303619c46d8cSEdward Tomasz Napierala static void 3037a7a7d96cSPhilippe Charnier out_of_mem(void) 30388fae3551SRodney W. Grimes { 30398fae3551SRodney W. Grimes 304074853402SPhilippe Charnier syslog(LOG_ERR, "out of memory"); 30418fae3551SRodney W. Grimes exit(2); 30428fae3551SRodney W. Grimes } 30438fae3551SRodney W. Grimes 30448fae3551SRodney W. Grimes /* 30450f0869bcSRick Macklem * Call do_mount() from the struct exportlist, for each case needed. 30460f0869bcSRick Macklem */ 30470f0869bcSRick Macklem static int 30480f0869bcSRick Macklem do_export_mount(struct exportlist *ep, struct statfs *fsp) 30490f0869bcSRick Macklem { 30500f0869bcSRick Macklem struct grouplist *grp, defgrp; 30510f0869bcSRick Macklem int ret; 30520f0869bcSRick Macklem size_t dirlen; 30530f0869bcSRick Macklem 30540f0869bcSRick Macklem LOGDEBUG("do_export_mount=%s", ep->ex_fsdir); 30550f0869bcSRick Macklem dirlen = strlen(ep->ex_fsdir); 30560f0869bcSRick Macklem if ((ep->ex_flag & EX_DEFSET) != 0) { 30570f0869bcSRick Macklem defgrp.gr_type = GT_DEFAULT; 30580f0869bcSRick Macklem defgrp.gr_next = NULL; 30590f0869bcSRick Macklem /* We have an entry for all other hosts/nets. */ 3060cc5efddeSRick Macklem LOGDEBUG("ex_defexflags=0x%jx", (uintmax_t)ep->ex_defexflags); 30610f0869bcSRick Macklem ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, 30620f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors, 30630f0869bcSRick Macklem ep->ex_defsecflavors); 30640f0869bcSRick Macklem if (ret != 0) 30650f0869bcSRick Macklem return (ret); 30660f0869bcSRick Macklem } 30670f0869bcSRick Macklem 30680f0869bcSRick Macklem /* Do a mount for each group. */ 30690f0869bcSRick Macklem grp = ep->ex_grphead; 30700f0869bcSRick Macklem while (grp != NULL) { 3071cc5efddeSRick Macklem LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%jx", 3072cc5efddeSRick Macklem grp->gr_type, (uintmax_t)grp->gr_exflags); 30730f0869bcSRick Macklem ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, 30740f0869bcSRick Macklem ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors, 30750f0869bcSRick Macklem grp->gr_secflavors); 30760f0869bcSRick Macklem if (ret != 0) 30770f0869bcSRick Macklem return (ret); 30780f0869bcSRick Macklem grp = grp->gr_next; 30790f0869bcSRick Macklem } 30800f0869bcSRick Macklem return (0); 30810f0869bcSRick Macklem } 30820f0869bcSRick Macklem 30830f0869bcSRick Macklem /* 30846a09faf2SCraig Rodrigues * Do the nmount() syscall with the update flag to push the export info into 30858fae3551SRodney W. Grimes * the kernel. 30868fae3551SRodney W. Grimes */ 308719c46d8cSEdward Tomasz Napierala static int 3088cc5efddeSRick Macklem do_mount(struct exportlist *ep, struct grouplist *grp, uint64_t exflags, 3089cc5efddeSRick Macklem struct expcred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, 30900f0869bcSRick Macklem int numsecflavors, int *secflavors) 30918fae3551SRodney W. Grimes { 3092f93caef2SIan Dowse struct statfs fsb1; 30938360efbdSAlfred Perlstein struct addrinfo *ai; 309479b86807SEdward Tomasz Napierala struct export_args *eap; 30956a09faf2SCraig Rodrigues char errmsg[255]; 30966a09faf2SCraig Rodrigues char *cp; 30978fae3551SRodney W. Grimes int done; 30986a09faf2SCraig Rodrigues char savedc; 30996a09faf2SCraig Rodrigues struct iovec *iov; 3100a9148abdSDoug Rabson int i, iovlen; 31016a09faf2SCraig Rodrigues int ret; 3102bcc1d071SRick Macklem struct nfsex_args nfsea; 3103bcc1d071SRick Macklem 3104bcc1d071SRick Macklem eap = &nfsea.export; 31058fae3551SRodney W. Grimes 31066a09faf2SCraig Rodrigues cp = NULL; 31076a09faf2SCraig Rodrigues savedc = '\0'; 31086a09faf2SCraig Rodrigues iov = NULL; 31096a09faf2SCraig Rodrigues iovlen = 0; 31106a09faf2SCraig Rodrigues ret = 0; 311160caaee2SIan Dowse 3112bcc1d071SRick Macklem bzero(eap, sizeof (struct export_args)); 31136a09faf2SCraig Rodrigues bzero(errmsg, sizeof(errmsg)); 3114bcc1d071SRick Macklem eap->ex_flags = exflags; 3115cc5efddeSRick Macklem eap->ex_uid = anoncrp->cr_uid; 3116cc5efddeSRick Macklem eap->ex_ngroups = anoncrp->cr_ngroups; 3117cc5efddeSRick Macklem if (eap->ex_ngroups > 0) { 3118cc5efddeSRick Macklem eap->ex_groups = malloc(eap->ex_ngroups * sizeof(gid_t)); 3119cc5efddeSRick Macklem memcpy(eap->ex_groups, anoncrp->cr_groups, eap->ex_ngroups * 3120cc5efddeSRick Macklem sizeof(gid_t)); 3121cc5efddeSRick Macklem } 3122cc5efddeSRick Macklem LOGDEBUG("do_mount exflags=0x%jx", (uintmax_t)exflags); 3123bcc1d071SRick Macklem eap->ex_indexfile = ep->ex_indexfile; 31246d359f31SIan Dowse if (grp->gr_type == GT_HOST) 31258360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 31266d359f31SIan Dowse else 31276d359f31SIan Dowse ai = NULL; 31280f0869bcSRick Macklem eap->ex_numsecflavors = numsecflavors; 31290f0869bcSRick Macklem LOGDEBUG("do_mount numsec=%d", numsecflavors); 3130bcc1d071SRick Macklem for (i = 0; i < eap->ex_numsecflavors; i++) 31310f0869bcSRick Macklem eap->ex_secflavors[i] = secflavors[i]; 3132bcc1d071SRick Macklem if (eap->ex_numsecflavors == 0) { 3133bcc1d071SRick Macklem eap->ex_numsecflavors = 1; 3134bcc1d071SRick Macklem eap->ex_secflavors[0] = AUTH_SYS; 3135a9148abdSDoug Rabson } 31368fae3551SRodney W. Grimes done = FALSE; 31376a09faf2SCraig Rodrigues 3138bcc1d071SRick Macklem if (v4root_phase == 0) { 31396a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", NULL, 0); 31406a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", NULL, 0); 31416a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "from", NULL, 0); 31426a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "update", NULL, 0); 3143bcc1d071SRick Macklem build_iovec(&iov, &iovlen, "export", eap, 3144bcc1d071SRick Macklem sizeof (struct export_args)); 31456a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 3146bcc1d071SRick Macklem } 31476a09faf2SCraig Rodrigues 31488fae3551SRodney W. Grimes while (!done) { 31498fae3551SRodney W. Grimes switch (grp->gr_type) { 31508fae3551SRodney W. Grimes case GT_HOST: 31516d359f31SIan Dowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 31528360efbdSAlfred Perlstein goto skip; 3153bcc1d071SRick Macklem eap->ex_addr = ai->ai_addr; 3154bcc1d071SRick Macklem eap->ex_addrlen = ai->ai_addrlen; 3155bcc1d071SRick Macklem eap->ex_masklen = 0; 31568fae3551SRodney W. Grimes break; 31578fae3551SRodney W. Grimes case GT_NET: 315860caaee2SIan Dowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 31598360efbdSAlfred Perlstein have_v6 == 0) 31608360efbdSAlfred Perlstein goto skip; 3161bcc1d071SRick Macklem eap->ex_addr = 316260caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 3163bcc1d071SRick Macklem eap->ex_addrlen = 31646a09faf2SCraig Rodrigues ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 3165bcc1d071SRick Macklem eap->ex_mask = 316660caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 3167bcc1d071SRick Macklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 31688fae3551SRodney W. Grimes break; 31696d359f31SIan Dowse case GT_DEFAULT: 3170bcc1d071SRick Macklem eap->ex_addr = NULL; 3171bcc1d071SRick Macklem eap->ex_addrlen = 0; 3172bcc1d071SRick Macklem eap->ex_mask = NULL; 3173bcc1d071SRick Macklem eap->ex_masklen = 0; 31746d359f31SIan Dowse break; 31758b5a6d67SBill Paul case GT_IGNORE: 31766a09faf2SCraig Rodrigues ret = 0; 31776a09faf2SCraig Rodrigues goto error_exit; 31788b5a6d67SBill Paul break; 31798fae3551SRodney W. Grimes default: 318074853402SPhilippe Charnier syslog(LOG_ERR, "bad grouptype"); 31818fae3551SRodney W. Grimes if (cp) 31828fae3551SRodney W. Grimes *cp = savedc; 31836a09faf2SCraig Rodrigues ret = 1; 31846a09faf2SCraig Rodrigues goto error_exit; 318580c7cc1cSPedro F. Giffuni } 31868fae3551SRodney W. Grimes 31878fae3551SRodney W. Grimes /* 3188bcc1d071SRick Macklem * For V4:, use the nfssvc() syscall, instead of mount(). 3189bcc1d071SRick Macklem */ 3190bcc1d071SRick Macklem if (v4root_phase == 2) { 3191bcc1d071SRick Macklem nfsea.fspec = v4root_dirpath; 3192cc5efddeSRick Macklem if (nfssvc(NFSSVC_V4ROOTEXPORT | NFSSVC_NEWSTRUCT, 3193cc5efddeSRick Macklem (caddr_t)&nfsea) < 0) { 3194bcc1d071SRick Macklem syslog(LOG_ERR, "Exporting V4: failed"); 3195cc5efddeSRick Macklem ret = 2; 3196cc5efddeSRick Macklem goto error_exit; 3197bcc1d071SRick Macklem } 3198bcc1d071SRick Macklem } else { 3199bcc1d071SRick Macklem /* 32008fae3551SRodney W. Grimes * XXX: 3201bcc1d071SRick Macklem * Maybe I should just use the fsb->f_mntonname path 3202bcc1d071SRick Macklem * instead of looping back up the dirp to the mount 3203bcc1d071SRick Macklem * point?? 32048fae3551SRodney W. Grimes * Also, needs to know how to export all types of local 320587564113SPeter Wemm * exportable filesystems and not just "ufs". 32068fae3551SRodney W. Grimes */ 32076a09faf2SCraig Rodrigues iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 32086a09faf2SCraig Rodrigues iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 32096a09faf2SCraig Rodrigues iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 32106a09faf2SCraig Rodrigues iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 32116a09faf2SCraig Rodrigues iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 32126a09faf2SCraig Rodrigues iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 32134a185fa6SBryan Drewery errmsg[0] = '\0'; 32146a09faf2SCraig Rodrigues 321555dd1327SCraig Rodrigues while (nmount(iov, iovlen, fsb->f_flags) < 0) { 32168fae3551SRodney W. Grimes if (cp) 32178fae3551SRodney W. Grimes *cp-- = savedc; 32188fae3551SRodney W. Grimes else 32198fae3551SRodney W. Grimes cp = dirp + dirplen - 1; 32206a09faf2SCraig Rodrigues if (opt_flags & OP_QUIET) { 32216a09faf2SCraig Rodrigues ret = 1; 32226a09faf2SCraig Rodrigues goto error_exit; 32236a09faf2SCraig Rodrigues } 32248fae3551SRodney W. Grimes if (errno == EPERM) { 322501709abfSIan Dowse if (debug) 322677909162SXin LI warnx("can't change attributes for %s: %s", 322777909162SXin LI dirp, errmsg); 32288fae3551SRodney W. Grimes syslog(LOG_ERR, 322977909162SXin LI "can't change attributes for %s: %s", 323077909162SXin LI dirp, errmsg); 32316a09faf2SCraig Rodrigues ret = 1; 32326a09faf2SCraig Rodrigues goto error_exit; 32338fae3551SRodney W. Grimes } 32348fae3551SRodney W. Grimes if (opt_flags & OP_ALLDIRS) { 3235288fa14aSJoerg Wunsch if (errno == EINVAL) 3236288fa14aSJoerg Wunsch syslog(LOG_ERR, 3237288fa14aSJoerg Wunsch "-alldirs requested but %s is not a filesystem mountpoint", 3238288fa14aSJoerg Wunsch dirp); 3239288fa14aSJoerg Wunsch else 3240288fa14aSJoerg Wunsch syslog(LOG_ERR, 3241288fa14aSJoerg Wunsch "could not remount %s: %m", 32423980ac4fSGarrett Wollman dirp); 32436a09faf2SCraig Rodrigues ret = 1; 32446a09faf2SCraig Rodrigues goto error_exit; 32458fae3551SRodney W. Grimes } 32468fae3551SRodney W. Grimes /* back up over the last component */ 3247d90b3641SBrooks Davis while (cp > dirp && *cp == '/') 32488fae3551SRodney W. Grimes cp--; 3249d90b3641SBrooks Davis while (cp > dirp && *(cp - 1) != '/') 32508fae3551SRodney W. Grimes cp--; 32518fae3551SRodney W. Grimes if (cp == dirp) { 32528fae3551SRodney W. Grimes if (debug) 325374853402SPhilippe Charnier warnx("mnt unsucc"); 3254bcc1d071SRick Macklem syslog(LOG_ERR, "can't export %s %s", 3255bcc1d071SRick Macklem dirp, errmsg); 32566a09faf2SCraig Rodrigues ret = 1; 32576a09faf2SCraig Rodrigues goto error_exit; 32588fae3551SRodney W. Grimes } 32598fae3551SRodney W. Grimes savedc = *cp; 32608fae3551SRodney W. Grimes *cp = '\0'; 3261bcc1d071SRick Macklem /* 3262bcc1d071SRick Macklem * Check that we're still on the same 3263bcc1d071SRick Macklem * filesystem. 3264bcc1d071SRick Macklem */ 3265bcc1d071SRick Macklem if (statfs(dirp, &fsb1) != 0 || 3266245bfd34SRyan Moeller fsidcmp(&fsb1.f_fsid, &fsb->f_fsid) != 0) { 3267f93caef2SIan Dowse *cp = savedc; 3268bcc1d071SRick Macklem syslog(LOG_ERR, 3269bcc1d071SRick Macklem "can't export %s %s", dirp, 327037518a88SCraig Rodrigues errmsg); 32716a09faf2SCraig Rodrigues ret = 1; 32726a09faf2SCraig Rodrigues goto error_exit; 3273f93caef2SIan Dowse } 32748fae3551SRodney W. Grimes } 3275bcc1d071SRick Macklem } 3276bcc1d071SRick Macklem 3277bcc1d071SRick Macklem /* 3278bcc1d071SRick Macklem * For the experimental server: 3279bcc1d071SRick Macklem * If this is the public directory, get the file handle 3280bcc1d071SRick Macklem * and load it into the kernel via the nfssvc() syscall. 3281bcc1d071SRick Macklem */ 328279b86807SEdward Tomasz Napierala if ((exflags & MNT_EXPUBLIC) != 0) { 3283bcc1d071SRick Macklem fhandle_t fh; 3284bcc1d071SRick Macklem char *public_name; 3285bcc1d071SRick Macklem 3286bcc1d071SRick Macklem if (eap->ex_indexfile != NULL) 3287bcc1d071SRick Macklem public_name = eap->ex_indexfile; 3288bcc1d071SRick Macklem else 3289bcc1d071SRick Macklem public_name = dirp; 3290bcc1d071SRick Macklem if (getfh(public_name, &fh) < 0) 3291bcc1d071SRick Macklem syslog(LOG_ERR, 3292bcc1d071SRick Macklem "Can't get public fh for %s", public_name); 3293bcc1d071SRick Macklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 3294bcc1d071SRick Macklem syslog(LOG_ERR, 3295bcc1d071SRick Macklem "Can't set public fh for %s", public_name); 32960f0869bcSRick Macklem else { 3297bcc1d071SRick Macklem has_publicfh = 1; 32980f0869bcSRick Macklem has_set_publicfh = 1; 32990f0869bcSRick Macklem ep->ex_flag |= EX_PUBLICFH; 33000f0869bcSRick Macklem } 3301bcc1d071SRick Macklem } 33028360efbdSAlfred Perlstein skip: 33036d359f31SIan Dowse if (ai != NULL) 33048360efbdSAlfred Perlstein ai = ai->ai_next; 33058360efbdSAlfred Perlstein if (ai == NULL) 33068fae3551SRodney W. Grimes done = TRUE; 33078fae3551SRodney W. Grimes } 33088fae3551SRodney W. Grimes if (cp) 33098fae3551SRodney W. Grimes *cp = savedc; 33106a09faf2SCraig Rodrigues error_exit: 3311cc5efddeSRick Macklem free(eap->ex_groups); 33126a09faf2SCraig Rodrigues /* free strings allocated by strdup() in getmntopts.c */ 33136a09faf2SCraig Rodrigues if (iov != NULL) { 33146a09faf2SCraig Rodrigues free(iov[0].iov_base); /* fstype */ 33156a09faf2SCraig Rodrigues free(iov[2].iov_base); /* fspath */ 33166a09faf2SCraig Rodrigues free(iov[4].iov_base); /* from */ 33176a09faf2SCraig Rodrigues free(iov[6].iov_base); /* update */ 33186a09faf2SCraig Rodrigues free(iov[8].iov_base); /* export */ 33196a09faf2SCraig Rodrigues free(iov[10].iov_base); /* errmsg */ 33206a09faf2SCraig Rodrigues 33216a09faf2SCraig Rodrigues /* free iov, allocated by realloc() */ 33226a09faf2SCraig Rodrigues free(iov); 33236a09faf2SCraig Rodrigues } 33246a09faf2SCraig Rodrigues return (ret); 33258fae3551SRodney W. Grimes } 33268fae3551SRodney W. Grimes 33278fae3551SRodney W. Grimes /* 33288fae3551SRodney W. Grimes * Translate a net address. 332960caaee2SIan Dowse * 333060caaee2SIan Dowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 33318fae3551SRodney W. Grimes */ 333219c46d8cSEdward Tomasz Napierala static int 3333a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg) 33348fae3551SRodney W. Grimes { 3335931c04f1SIan Dowse struct netent *np = NULL; 33368360efbdSAlfred Perlstein char *name, *p, *prefp; 333760caaee2SIan Dowse struct sockaddr_in sin; 3338931c04f1SIan Dowse struct sockaddr *sa = NULL; 33398360efbdSAlfred Perlstein struct addrinfo hints, *ai = NULL; 33408360efbdSAlfred Perlstein char netname[NI_MAXHOST]; 33418360efbdSAlfred Perlstein long preflen; 33428fae3551SRodney W. Grimes 334301709abfSIan Dowse p = prefp = NULL; 33448360efbdSAlfred Perlstein if ((opt_flags & OP_MASKLEN) && !maskflg) { 33458360efbdSAlfred Perlstein p = strchr(cp, '/'); 33468360efbdSAlfred Perlstein *p = '\0'; 33478360efbdSAlfred Perlstein prefp = p + 1; 33488360efbdSAlfred Perlstein } 33498360efbdSAlfred Perlstein 3350931c04f1SIan Dowse /* 3351931c04f1SIan Dowse * Check for a numeric address first. We wish to avoid 3352931c04f1SIan Dowse * possible DNS lookups in getnetbyname(). 3353931c04f1SIan Dowse */ 3354931c04f1SIan Dowse if (isxdigit(*cp) || *cp == ':') { 33558360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 335660caaee2SIan Dowse /* Ensure the mask and the network have the same family. */ 335760caaee2SIan Dowse if (maskflg && (opt_flags & OP_NET)) 335860caaee2SIan Dowse hints.ai_family = net->nt_net.ss_family; 335960caaee2SIan Dowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 336060caaee2SIan Dowse hints.ai_family = net->nt_mask.ss_family; 336160caaee2SIan Dowse else 33628360efbdSAlfred Perlstein hints.ai_family = AF_UNSPEC; 33638360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 3364931c04f1SIan Dowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 3365931c04f1SIan Dowse sa = ai->ai_addr; 3366931c04f1SIan Dowse if (sa != NULL && ai->ai_family == AF_INET) { 33678fae3551SRodney W. Grimes /* 336860caaee2SIan Dowse * The address in `cp' is really a network address, so 336960caaee2SIan Dowse * use inet_network() to re-interpret this correctly. 337060caaee2SIan Dowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 33718fae3551SRodney W. Grimes */ 337260caaee2SIan Dowse bzero(&sin, sizeof sin); 33738360efbdSAlfred Perlstein sin.sin_family = AF_INET; 33748360efbdSAlfred Perlstein sin.sin_len = sizeof sin; 33758360efbdSAlfred Perlstein sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 33768360efbdSAlfred Perlstein if (debug) 337760caaee2SIan Dowse fprintf(stderr, "get_net: v4 addr %s\n", 337860caaee2SIan Dowse inet_ntoa(sin.sin_addr)); 33798360efbdSAlfred Perlstein sa = (struct sockaddr *)&sin; 3380931c04f1SIan Dowse } 3381931c04f1SIan Dowse } 3382931c04f1SIan Dowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 3383931c04f1SIan Dowse bzero(&sin, sizeof sin); 3384931c04f1SIan Dowse sin.sin_family = AF_INET; 3385931c04f1SIan Dowse sin.sin_len = sizeof sin; 3386931c04f1SIan Dowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 3387931c04f1SIan Dowse sa = (struct sockaddr *)&sin; 3388931c04f1SIan Dowse } 3389931c04f1SIan Dowse if (sa == NULL) 33908360efbdSAlfred Perlstein goto fail; 33918360efbdSAlfred Perlstein 339260caaee2SIan Dowse if (maskflg) { 339360caaee2SIan Dowse /* The specified sockaddr is a mask. */ 339460caaee2SIan Dowse if (checkmask(sa) != 0) 33958360efbdSAlfred Perlstein goto fail; 339660caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 339760caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 339860caaee2SIan Dowse } else { 339960caaee2SIan Dowse /* The specified sockaddr is a network address. */ 340060caaee2SIan Dowse bcopy(sa, &net->nt_net, sa->sa_len); 34010f4b7baaSPaul Traina 340260caaee2SIan Dowse /* Get a network name for the export list. */ 340360caaee2SIan Dowse if (np) { 340460caaee2SIan Dowse name = np->n_name; 340560caaee2SIan Dowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 34064f101318SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) { 340760caaee2SIan Dowse name = netname; 340860caaee2SIan Dowse } else { 340960caaee2SIan Dowse goto fail; 341060caaee2SIan Dowse } 341160caaee2SIan Dowse if ((net->nt_name = strdup(name)) == NULL) 341260caaee2SIan Dowse out_of_mem(); 341360caaee2SIan Dowse 341460caaee2SIan Dowse /* 341560caaee2SIan Dowse * Extract a mask from either a "/<masklen>" suffix, or 341660caaee2SIan Dowse * from the class of an IPv4 address. 341760caaee2SIan Dowse */ 34188360efbdSAlfred Perlstein if (opt_flags & OP_MASKLEN) { 34198360efbdSAlfred Perlstein preflen = strtol(prefp, NULL, 10); 342060caaee2SIan Dowse if (preflen < 0L || preflen == LONG_MAX) 34218360efbdSAlfred Perlstein goto fail; 342260caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 342360caaee2SIan Dowse if (makemask(&net->nt_mask, (int)preflen) != 0) 342460caaee2SIan Dowse goto fail; 342560caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 34268360efbdSAlfred Perlstein *p = '/'; 342760caaee2SIan Dowse } else if (sa->sa_family == AF_INET && 342860caaee2SIan Dowse (opt_flags & OP_MASK) == 0) { 342960caaee2SIan Dowse in_addr_t addr; 34308360efbdSAlfred Perlstein 343192aebdeaSMike Karels syslog(LOG_WARNING, 343292aebdeaSMike Karels "WARNING: No mask specified for %s, " 343392aebdeaSMike Karels "using out-of-date default", name); 343460caaee2SIan Dowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 343560caaee2SIan Dowse if (IN_CLASSA(addr)) 343660caaee2SIan Dowse preflen = 8; 343760caaee2SIan Dowse else if (IN_CLASSB(addr)) 343860caaee2SIan Dowse preflen = 16; 343960caaee2SIan Dowse else if (IN_CLASSC(addr)) 344060caaee2SIan Dowse preflen = 24; 344192aebdeaSMike Karels else if (IN_CLASSD(addr)) /* XXX Multicast??? */ 344260caaee2SIan Dowse preflen = 28; 34438360efbdSAlfred Perlstein else 344460caaee2SIan Dowse preflen = 32; /* XXX */ 344560caaee2SIan Dowse 344660caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 344760caaee2SIan Dowse makemask(&net->nt_mask, (int)preflen); 344860caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 344960caaee2SIan Dowse } 34508360efbdSAlfred Perlstein } 34518360efbdSAlfred Perlstein 34528360efbdSAlfred Perlstein if (ai) 34538360efbdSAlfred Perlstein freeaddrinfo(ai); 34548360efbdSAlfred Perlstein return 0; 34558360efbdSAlfred Perlstein 34568360efbdSAlfred Perlstein fail: 34578360efbdSAlfred Perlstein if (ai) 34588360efbdSAlfred Perlstein freeaddrinfo(ai); 34598360efbdSAlfred Perlstein return 1; 34608fae3551SRodney W. Grimes } 34618fae3551SRodney W. Grimes 34628fae3551SRodney W. Grimes /* 34638fae3551SRodney W. Grimes * Parse out the next white space separated field 34648fae3551SRodney W. Grimes */ 346519c46d8cSEdward Tomasz Napierala static void 3466a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp) 34678fae3551SRodney W. Grimes { 34688fae3551SRodney W. Grimes char *p; 3469eb1f7f43SAlexander Motin char quot = 0; 34708fae3551SRodney W. Grimes 34718fae3551SRodney W. Grimes p = *cp; 34728fae3551SRodney W. Grimes while (*p == ' ' || *p == '\t') 34738fae3551SRodney W. Grimes p++; 3474eb1f7f43SAlexander Motin *cp = p; 3475eb1f7f43SAlexander Motin while (*p != '\0') { 3476eb1f7f43SAlexander Motin if (quot) { 3477eb1f7f43SAlexander Motin if (*p == quot) 3478eb1f7f43SAlexander Motin quot = 0; 3479eb1f7f43SAlexander Motin } else { 3480eb1f7f43SAlexander Motin if (*p == '\\' && *(p + 1) != '\0') 34818fae3551SRodney W. Grimes p++; 3482eb1f7f43SAlexander Motin else if (*p == '\'' || *p == '"') 3483eb1f7f43SAlexander Motin quot = *p; 3484eb1f7f43SAlexander Motin else if (*p == ' ' || *p == '\t') 3485eb1f7f43SAlexander Motin break; 34868fae3551SRodney W. Grimes } 3487eb1f7f43SAlexander Motin p++; 3488eb1f7f43SAlexander Motin }; 3489eb1f7f43SAlexander Motin *endcp = p; 34908fae3551SRodney W. Grimes } 34918fae3551SRodney W. Grimes 34928fae3551SRodney W. Grimes /* 34938fae3551SRodney W. Grimes * Get an exports file line. Skip over blank lines and handle line 34948fae3551SRodney W. Grimes * continuations. 34958fae3551SRodney W. Grimes */ 349619c46d8cSEdward Tomasz Napierala static int 3497a7a7d96cSPhilippe Charnier get_line(void) 34988fae3551SRodney W. Grimes { 34998fae3551SRodney W. Grimes char *p, *cp; 350091ca1a91SIan Dowse size_t len; 35018fae3551SRodney W. Grimes int totlen, cont_line; 35028fae3551SRodney W. Grimes 35038fae3551SRodney W. Grimes /* 35048fae3551SRodney W. Grimes * Loop around ignoring blank lines and getting all continuation lines. 35058fae3551SRodney W. Grimes */ 35068fae3551SRodney W. Grimes p = line; 35078fae3551SRodney W. Grimes totlen = 0; 35088fae3551SRodney W. Grimes do { 350991ca1a91SIan Dowse if ((p = fgetln(exp_file, &len)) == NULL) 35108fae3551SRodney W. Grimes return (0); 35118fae3551SRodney W. Grimes cp = p + len - 1; 35128fae3551SRodney W. Grimes cont_line = 0; 35138fae3551SRodney W. Grimes while (cp >= p && 35148fae3551SRodney W. Grimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 35158fae3551SRodney W. Grimes if (*cp == '\\') 35168fae3551SRodney W. Grimes cont_line = 1; 35178fae3551SRodney W. Grimes cp--; 35188fae3551SRodney W. Grimes len--; 35198fae3551SRodney W. Grimes } 3520376f8390SDima Dorfman if (cont_line) { 3521376f8390SDima Dorfman *++cp = ' '; 3522376f8390SDima Dorfman len++; 3523376f8390SDima Dorfman } 352491ca1a91SIan Dowse if (linesize < len + totlen + 1) { 352591ca1a91SIan Dowse linesize = len + totlen + 1; 352691ca1a91SIan Dowse line = realloc(line, linesize); 352791ca1a91SIan Dowse if (line == NULL) 352891ca1a91SIan Dowse out_of_mem(); 352991ca1a91SIan Dowse } 353091ca1a91SIan Dowse memcpy(line + totlen, p, len); 35318fae3551SRodney W. Grimes totlen += len; 353291ca1a91SIan Dowse line[totlen] = '\0'; 35338fae3551SRodney W. Grimes } while (totlen == 0 || cont_line); 35348fae3551SRodney W. Grimes return (1); 35358fae3551SRodney W. Grimes } 35368fae3551SRodney W. Grimes 35378fae3551SRodney W. Grimes /* 35388fae3551SRodney W. Grimes * Parse a description of a credential. 35398fae3551SRodney W. Grimes */ 354019c46d8cSEdward Tomasz Napierala static void 3541cc5efddeSRick Macklem parsecred(char *namelist, struct expcred *cr) 35428fae3551SRodney W. Grimes { 35438fae3551SRodney W. Grimes char *name; 35442ffad162SRick Macklem int inpos; 35458fae3551SRodney W. Grimes char *names; 35468fae3551SRodney W. Grimes struct passwd *pw; 35478fae3551SRodney W. Grimes struct group *gr; 35482ffad162SRick Macklem gid_t groups[NGROUPS_MAX + 1]; 35492ffad162SRick Macklem int ngroups; 3550f4bf849bSRick Macklem unsigned long name_ul; 3551f4bf849bSRick Macklem char *end = NULL; 35528fae3551SRodney W. Grimes 35538fae3551SRodney W. Grimes /* 355474853402SPhilippe Charnier * Set up the unprivileged user. 35558fae3551SRodney W. Grimes */ 35562ffad162SRick Macklem cr->cr_groups = cr->cr_smallgrps; 35573e2d36ffSRick Macklem cr->cr_uid = UID_NOBODY; 35583e2d36ffSRick Macklem cr->cr_groups[0] = GID_NOGROUP; 35598fae3551SRodney W. Grimes cr->cr_ngroups = 1; 35608fae3551SRodney W. Grimes /* 35618fae3551SRodney W. Grimes * Get the user's password table entry. 35628fae3551SRodney W. Grimes */ 3563eb1f7f43SAlexander Motin names = namelist; 3564eb1f7f43SAlexander Motin name = strsep_quote(&names, ":"); 3565b875c2e9SJosh Paetzel /* Bug? name could be NULL here */ 3566f4bf849bSRick Macklem name_ul = strtoul(name, &end, 10); 3567f4bf849bSRick Macklem if (*end != '\0' || end == name) 35688fae3551SRodney W. Grimes pw = getpwnam(name); 3569f4bf849bSRick Macklem else 3570f4bf849bSRick Macklem pw = getpwuid((uid_t)name_ul); 35718fae3551SRodney W. Grimes /* 35728fae3551SRodney W. Grimes * Credentials specified as those of a user. 35738fae3551SRodney W. Grimes */ 35748fae3551SRodney W. Grimes if (names == NULL) { 35758fae3551SRodney W. Grimes if (pw == NULL) { 357674853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 35778fae3551SRodney W. Grimes return; 35788fae3551SRodney W. Grimes } 35798fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 35802ffad162SRick Macklem ngroups = NGROUPS_MAX + 1; 35812ffad162SRick Macklem if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { 358274853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 35832ffad162SRick Macklem ngroups = NGROUPS_MAX + 1; 3584020d6f96SAndriy Gapon } 3585020d6f96SAndriy Gapon 35868fae3551SRodney W. Grimes /* 3587950cc395SStefan Farfeleder * Compress out duplicate. 35888fae3551SRodney W. Grimes */ 35892ffad162SRick Macklem if (ngroups > 1 && groups[0] == groups[1]) { 35902ffad162SRick Macklem ngroups--; 35912ffad162SRick Macklem inpos = 2; 3592f4bf849bSRick Macklem } else { 35932ffad162SRick Macklem inpos = 1; 3594f4bf849bSRick Macklem } 35952ffad162SRick Macklem if (ngroups > NGROUPS_MAX) 35962ffad162SRick Macklem ngroups = NGROUPS_MAX; 35972ffad162SRick Macklem if (ngroups > SMALLNGROUPS) 35982ffad162SRick Macklem cr->cr_groups = malloc(ngroups * sizeof(gid_t)); 35992ffad162SRick Macklem cr->cr_ngroups = ngroups; 36002ffad162SRick Macklem cr->cr_groups[0] = groups[0]; 36012ffad162SRick Macklem memcpy(&cr->cr_groups[1], &groups[inpos], (ngroups - 1) * 36022ffad162SRick Macklem sizeof(gid_t)); 36038fae3551SRodney W. Grimes return; 36048fae3551SRodney W. Grimes } 36058fae3551SRodney W. Grimes /* 36068fae3551SRodney W. Grimes * Explicit credential specified as a colon separated list: 36078fae3551SRodney W. Grimes * uid:gid:gid:... 36088fae3551SRodney W. Grimes */ 3609f4bf849bSRick Macklem if (pw != NULL) { 36108fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 3611f4bf849bSRick Macklem } else if (*end != '\0' || end == name) { 361274853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 36138fae3551SRodney W. Grimes return; 3614f4bf849bSRick Macklem } else { 3615f4bf849bSRick Macklem cr->cr_uid = name_ul; 36168fae3551SRodney W. Grimes } 36178fae3551SRodney W. Grimes cr->cr_ngroups = 0; 3618cc5efddeSRick Macklem while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS_MAX) { 3619eb1f7f43SAlexander Motin name = strsep_quote(&names, ":"); 3620f4bf849bSRick Macklem name_ul = strtoul(name, &end, 10); 3621f4bf849bSRick Macklem if (*end != '\0' || end == name) { 36228fae3551SRodney W. Grimes if ((gr = getgrnam(name)) == NULL) { 362374853402SPhilippe Charnier syslog(LOG_ERR, "unknown group: %s", name); 36248fae3551SRodney W. Grimes continue; 36258fae3551SRodney W. Grimes } 36262ffad162SRick Macklem groups[cr->cr_ngroups++] = gr->gr_gid; 3627f4bf849bSRick Macklem } else { 3628f4bf849bSRick Macklem groups[cr->cr_ngroups++] = name_ul; 36298fae3551SRodney W. Grimes } 36308fae3551SRodney W. Grimes } 3631cc5efddeSRick Macklem if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS_MAX) 363274853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 36332ffad162SRick Macklem if (cr->cr_ngroups > SMALLNGROUPS) 36342ffad162SRick Macklem cr->cr_groups = malloc(cr->cr_ngroups * sizeof(gid_t)); 36352ffad162SRick Macklem memcpy(cr->cr_groups, groups, cr->cr_ngroups * sizeof(gid_t)); 36368fae3551SRodney W. Grimes } 36378fae3551SRodney W. Grimes 36380775314bSDoug Rabson #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 36398fae3551SRodney W. Grimes /* 36408fae3551SRodney W. Grimes * Routines that maintain the remote mounttab 36418fae3551SRodney W. Grimes */ 364219c46d8cSEdward Tomasz Napierala static void 3643a7a7d96cSPhilippe Charnier get_mountlist(void) 36448fae3551SRodney W. Grimes { 36451da3e8b0SEmmanuel Vadot struct mountlist *mlp; 364687564113SPeter Wemm char *host, *dirp, *cp; 36478fae3551SRodney W. Grimes char str[STRSIZ]; 36488fae3551SRodney W. Grimes FILE *mlfile; 36498fae3551SRodney W. Grimes 36508fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 365139539916SBill Fumerola if (errno == ENOENT) 365239539916SBill Fumerola return; 365339539916SBill Fumerola else { 365474853402SPhilippe Charnier syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 36558fae3551SRodney W. Grimes return; 36568fae3551SRodney W. Grimes } 365739539916SBill Fumerola } 36588fae3551SRodney W. Grimes while (fgets(str, STRSIZ, mlfile) != NULL) { 365987564113SPeter Wemm cp = str; 366087564113SPeter Wemm host = strsep(&cp, " \t\n"); 366187564113SPeter Wemm dirp = strsep(&cp, " \t\n"); 366287564113SPeter Wemm if (host == NULL || dirp == NULL) 36638fae3551SRodney W. Grimes continue; 36648fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 366574853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 366674853402SPhilippe Charnier out_of_mem(); 36670775314bSDoug Rabson strncpy(mlp->ml_host, host, MNTNAMLEN); 36680775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 36690775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 36700775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 36711da3e8b0SEmmanuel Vadot 36721da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 36738fae3551SRodney W. Grimes } 36748fae3551SRodney W. Grimes fclose(mlfile); 36758fae3551SRodney W. Grimes } 36768fae3551SRodney W. Grimes 367719c46d8cSEdward Tomasz Napierala static void 367801709abfSIan Dowse del_mlist(char *hostp, char *dirp) 36798fae3551SRodney W. Grimes { 36801da3e8b0SEmmanuel Vadot struct mountlist *mlp, *mlp2; 36818fae3551SRodney W. Grimes FILE *mlfile; 36828fae3551SRodney W. Grimes int fnd = 0; 36838fae3551SRodney W. Grimes 36841da3e8b0SEmmanuel Vadot SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) { 36858fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && 36868fae3551SRodney W. Grimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 36878fae3551SRodney W. Grimes fnd = 1; 36881da3e8b0SEmmanuel Vadot SLIST_REMOVE(&mlhead, mlp, mountlist, next); 36891da3e8b0SEmmanuel Vadot free((caddr_t)mlp); 36908fae3551SRodney W. Grimes } 36918fae3551SRodney W. Grimes } 36928fae3551SRodney W. Grimes if (fnd) { 36938fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 369474853402SPhilippe Charnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 36958fae3551SRodney W. Grimes return; 36968fae3551SRodney W. Grimes } 36971da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 36988fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 36998fae3551SRodney W. Grimes } 37008fae3551SRodney W. Grimes fclose(mlfile); 37018fae3551SRodney W. Grimes } 37028fae3551SRodney W. Grimes } 37038fae3551SRodney W. Grimes 370419c46d8cSEdward Tomasz Napierala static void 3705a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp) 37068fae3551SRodney W. Grimes { 37071da3e8b0SEmmanuel Vadot struct mountlist *mlp; 37088fae3551SRodney W. Grimes FILE *mlfile; 37098fae3551SRodney W. Grimes 37101da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 37118fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 37128fae3551SRodney W. Grimes return; 37138fae3551SRodney W. Grimes } 37141da3e8b0SEmmanuel Vadot 37158fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 371674853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 371774853402SPhilippe Charnier out_of_mem(); 37180775314bSDoug Rabson strncpy(mlp->ml_host, hostp, MNTNAMLEN); 37190775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 37200775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 37210775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 37221da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 37238fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 372474853402SPhilippe Charnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 37258fae3551SRodney W. Grimes return; 37268fae3551SRodney W. Grimes } 37278fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 37288fae3551SRodney W. Grimes fclose(mlfile); 37298fae3551SRodney W. Grimes } 37308fae3551SRodney W. Grimes 37318fae3551SRodney W. Grimes /* 37328fae3551SRodney W. Grimes * Free up a group list. 37338fae3551SRodney W. Grimes */ 373419c46d8cSEdward Tomasz Napierala static void 3735a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp) 37368fae3551SRodney W. Grimes { 37378fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 37388360efbdSAlfred Perlstein if (grp->gr_ptr.gt_addrinfo != NULL) 37398360efbdSAlfred Perlstein freeaddrinfo(grp->gr_ptr.gt_addrinfo); 37408fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 37418fae3551SRodney W. Grimes if (grp->gr_ptr.gt_net.nt_name) 37428fae3551SRodney W. Grimes free(grp->gr_ptr.gt_net.nt_name); 37438fae3551SRodney W. Grimes } 37442ffad162SRick Macklem if (grp->gr_anon.cr_groups != grp->gr_anon.cr_smallgrps) 37452ffad162SRick Macklem free(grp->gr_anon.cr_groups); 37468fae3551SRodney W. Grimes free((caddr_t)grp); 37478fae3551SRodney W. Grimes } 37488fae3551SRodney W. Grimes 37498fae3551SRodney W. Grimes #ifdef DEBUG 375019c46d8cSEdward Tomasz Napierala static void 37518fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...) 37528fae3551SRodney W. Grimes { 37538fae3551SRodney W. Grimes va_list ap; 37548fae3551SRodney W. Grimes 37558fae3551SRodney W. Grimes va_start(ap, fmt); 37568fae3551SRodney W. Grimes vfprintf(stderr, fmt, ap); 37578fae3551SRodney W. Grimes va_end(ap); 37588fae3551SRodney W. Grimes } 37598fae3551SRodney W. Grimes #endif /* DEBUG */ 37608fae3551SRodney W. Grimes 37618fae3551SRodney W. Grimes /* 37628fae3551SRodney W. Grimes * Check options for consistency. 37638fae3551SRodney W. Grimes */ 376419c46d8cSEdward Tomasz Napierala static int 3765a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp) 37668fae3551SRodney W. Grimes { 37678fae3551SRodney W. Grimes 3768bcc1d071SRick Macklem if (v4root_phase == 0 && dp == NULL) 37698fae3551SRodney W. Grimes return (1); 377091196234SPeter Wemm if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 377191196234SPeter Wemm syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 37728fae3551SRodney W. Grimes return (1); 37738fae3551SRodney W. Grimes } 37748fae3551SRodney W. Grimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 377560caaee2SIan Dowse syslog(LOG_ERR, "-mask requires -network"); 377660caaee2SIan Dowse return (1); 377760caaee2SIan Dowse } 377860caaee2SIan Dowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 377960caaee2SIan Dowse syslog(LOG_ERR, "-network requires mask specification"); 378060caaee2SIan Dowse return (1); 378160caaee2SIan Dowse } 378260caaee2SIan Dowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 378360caaee2SIan Dowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 37848fae3551SRodney W. Grimes return (1); 37858fae3551SRodney W. Grimes } 3786bcc1d071SRick Macklem if (v4root_phase > 0 && 3787bcc1d071SRick Macklem (opt_flags & 3788bcc1d071SRick Macklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3789bcc1d071SRick Macklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3790bcc1d071SRick Macklem return (1); 3791bcc1d071SRick Macklem } 379256cfc5edSRick Macklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 379356cfc5edSRick Macklem syslog(LOG_ERR, "-alldirs has multiple directories"); 379456cfc5edSRick Macklem return (1); 379556cfc5edSRick Macklem } 37968fae3551SRodney W. Grimes return (0); 37978fae3551SRodney W. Grimes } 37988fae3551SRodney W. Grimes 379919c46d8cSEdward Tomasz Napierala static int 3800*572b77f8SAlexander Motin check_path_component(const char *path, char **err) 38018fae3551SRodney W. Grimes { 38028fae3551SRodney W. Grimes struct stat sb; 38038fae3551SRodney W. Grimes 3804*572b77f8SAlexander Motin if (lstat(path, &sb)) { 3805*572b77f8SAlexander Motin asprintf(err, "%s: lstat() failed: %s.\n", 3806*572b77f8SAlexander Motin path, strerror(errno)); 3807*572b77f8SAlexander Motin return (0); 3808*572b77f8SAlexander Motin } 3809*572b77f8SAlexander Motin 3810*572b77f8SAlexander Motin switch (sb.st_mode & S_IFMT) { 3811*572b77f8SAlexander Motin case S_IFDIR: 3812*572b77f8SAlexander Motin return (1); 3813*572b77f8SAlexander Motin case S_IFLNK: 3814*572b77f8SAlexander Motin asprintf(err, "%s: path is a symbolic link.\n", path); 3815*572b77f8SAlexander Motin break; 3816*572b77f8SAlexander Motin case S_IFREG: 3817*572b77f8SAlexander Motin asprintf(err, "%s: path is a file rather than a directory.\n", 3818*572b77f8SAlexander Motin path); 3819*572b77f8SAlexander Motin break; 3820*572b77f8SAlexander Motin default: 3821*572b77f8SAlexander Motin asprintf(err, "%s: path is not a directory.\n", path); 3822*572b77f8SAlexander Motin } 3823*572b77f8SAlexander Motin 3824*572b77f8SAlexander Motin return (0); 3825*572b77f8SAlexander Motin } 3826*572b77f8SAlexander Motin 3827*572b77f8SAlexander Motin /* 3828*572b77f8SAlexander Motin * Check each path component for the presence of symbolic links. Return true 3829*572b77f8SAlexander Motin */ 3830*572b77f8SAlexander Motin static int 3831*572b77f8SAlexander Motin check_dirpath(char *dirp, char **err) 3832*572b77f8SAlexander Motin { 3833*572b77f8SAlexander Motin char *cp; 3834*572b77f8SAlexander Motin 38358fae3551SRodney W. Grimes cp = dirp + 1; 3836*572b77f8SAlexander Motin while (*cp) { 38378fae3551SRodney W. Grimes if (*cp == '/') { 38388fae3551SRodney W. Grimes *cp = '\0'; 3839*572b77f8SAlexander Motin 3840*572b77f8SAlexander Motin if (!check_path_component(dirp, err)) { 3841*572b77f8SAlexander Motin *cp = '/'; 3842*572b77f8SAlexander Motin return (0); 3843*572b77f8SAlexander Motin } 3844*572b77f8SAlexander Motin 38458fae3551SRodney W. Grimes *cp = '/'; 38468fae3551SRodney W. Grimes } 38478fae3551SRodney W. Grimes cp++; 38488fae3551SRodney W. Grimes } 3849*572b77f8SAlexander Motin 3850*572b77f8SAlexander Motin if (!check_path_component(dirp, err)) 3851*572b77f8SAlexander Motin return (0); 3852*572b77f8SAlexander Motin 3853*572b77f8SAlexander Motin return (1); 3854*572b77f8SAlexander Motin } 3855*572b77f8SAlexander Motin 3856*572b77f8SAlexander Motin /* 3857*572b77f8SAlexander Motin * Populate statfs information. Return true on success. 3858*572b77f8SAlexander Motin */ 3859*572b77f8SAlexander Motin static int 3860*572b77f8SAlexander Motin check_statfs(const char *dirp, struct statfs *fsb, char **err) 3861*572b77f8SAlexander Motin { 3862*572b77f8SAlexander Motin if (statfs(dirp, fsb)) { 3863*572b77f8SAlexander Motin asprintf(err, "%s: statfs() failed: %s\n", dirp, 3864*572b77f8SAlexander Motin strerror(errno)); 3865*572b77f8SAlexander Motin return (0); 3866*572b77f8SAlexander Motin } 3867*572b77f8SAlexander Motin 3868*572b77f8SAlexander Motin return (1); 38698fae3551SRodney W. Grimes } 3870a62dc406SDoug Rabson 387160caaee2SIan Dowse /* 387260caaee2SIan Dowse * Make a netmask according to the specified prefix length. The ss_family 387360caaee2SIan Dowse * and other non-address fields must be initialised before calling this. 387460caaee2SIan Dowse */ 387519c46d8cSEdward Tomasz Napierala static int 387660caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen) 38778360efbdSAlfred Perlstein { 387860caaee2SIan Dowse u_char *p; 387960caaee2SIan Dowse int bits, i, len; 38808360efbdSAlfred Perlstein 388160caaee2SIan Dowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 388260caaee2SIan Dowse return (-1); 388389fdc4e1SMike Barcroft if (bitlen > len * CHAR_BIT) 388460caaee2SIan Dowse return (-1); 38858360efbdSAlfred Perlstein 388660caaee2SIan Dowse for (i = 0; i < len; i++) { 3887a175f065SMarcelo Araujo bits = MIN(CHAR_BIT, bitlen); 388858202d89SRuslan Ermilov *p++ = (u_char)~0 << (CHAR_BIT - bits); 388960caaee2SIan Dowse bitlen -= bits; 38908360efbdSAlfred Perlstein } 38918360efbdSAlfred Perlstein return 0; 38928360efbdSAlfred Perlstein } 38938360efbdSAlfred Perlstein 389460caaee2SIan Dowse /* 389560caaee2SIan Dowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 389660caaee2SIan Dowse * is acceptable (i.e. of the form 1...10....0). 389760caaee2SIan Dowse */ 389819c46d8cSEdward Tomasz Napierala static int 389960caaee2SIan Dowse checkmask(struct sockaddr *sa) 39008360efbdSAlfred Perlstein { 390160caaee2SIan Dowse u_char *mask; 390260caaee2SIan Dowse int i, len; 390360caaee2SIan Dowse 390460caaee2SIan Dowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 390560caaee2SIan Dowse return (-1); 390660caaee2SIan Dowse 390760caaee2SIan Dowse for (i = 0; i < len; i++) 390860caaee2SIan Dowse if (mask[i] != 0xff) 390960caaee2SIan Dowse break; 391060caaee2SIan Dowse if (i < len) { 391160caaee2SIan Dowse if (~mask[i] & (u_char)(~mask[i] + 1)) 391260caaee2SIan Dowse return (-1); 391360caaee2SIan Dowse i++; 391460caaee2SIan Dowse } 391560caaee2SIan Dowse for (; i < len; i++) 391660caaee2SIan Dowse if (mask[i] != 0) 391760caaee2SIan Dowse return (-1); 391860caaee2SIan Dowse return (0); 391960caaee2SIan Dowse } 392060caaee2SIan Dowse 392160caaee2SIan Dowse /* 392260caaee2SIan Dowse * Compare two sockaddrs according to a specified mask. Return zero if 392360caaee2SIan Dowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 39243df5ecacSUlrich Spörlein * If samask is NULL, perform a full comparison. 392560caaee2SIan Dowse */ 392619c46d8cSEdward Tomasz Napierala static int 392760caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 392860caaee2SIan Dowse { 392960caaee2SIan Dowse unsigned char *p1, *p2, *mask; 393060caaee2SIan Dowse int len, i; 393160caaee2SIan Dowse 393260caaee2SIan Dowse if (sa1->sa_family != sa2->sa_family || 393360caaee2SIan Dowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 393460caaee2SIan Dowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 393560caaee2SIan Dowse return (1); 393660caaee2SIan Dowse 393760caaee2SIan Dowse switch (sa1->sa_family) { 393860caaee2SIan Dowse case AF_INET6: 393960caaee2SIan Dowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 394060caaee2SIan Dowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 394160caaee2SIan Dowse return (1); 394260caaee2SIan Dowse break; 394360caaee2SIan Dowse } 394460caaee2SIan Dowse 394560caaee2SIan Dowse /* Simple binary comparison if no mask specified. */ 394660caaee2SIan Dowse if (samask == NULL) 394760caaee2SIan Dowse return (memcmp(p1, p2, len)); 394860caaee2SIan Dowse 394960caaee2SIan Dowse /* Set up the mask, and do a mask-based comparison. */ 395060caaee2SIan Dowse if (sa1->sa_family != samask->sa_family || 395160caaee2SIan Dowse (mask = sa_rawaddr(samask, NULL)) == NULL) 395260caaee2SIan Dowse return (1); 395360caaee2SIan Dowse 395460caaee2SIan Dowse for (i = 0; i < len; i++) 395560caaee2SIan Dowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 395660caaee2SIan Dowse return (1); 395760caaee2SIan Dowse return (0); 395860caaee2SIan Dowse } 395960caaee2SIan Dowse 396060caaee2SIan Dowse /* 396160caaee2SIan Dowse * Return a pointer to the part of the sockaddr that contains the 396260caaee2SIan Dowse * raw address, and set *nbytes to its length in bytes. Returns 396360caaee2SIan Dowse * NULL if the address family is unknown. 396460caaee2SIan Dowse */ 396519c46d8cSEdward Tomasz Napierala static void * 396660caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) { 396760caaee2SIan Dowse void *p; 396860caaee2SIan Dowse int len; 39698360efbdSAlfred Perlstein 39708360efbdSAlfred Perlstein switch (sa->sa_family) { 39718360efbdSAlfred Perlstein case AF_INET: 397260caaee2SIan Dowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 397360caaee2SIan Dowse p = &((struct sockaddr_in *)sa)->sin_addr; 39748360efbdSAlfred Perlstein break; 39758360efbdSAlfred Perlstein case AF_INET6: 397660caaee2SIan Dowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 397760caaee2SIan Dowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 39788360efbdSAlfred Perlstein break; 39798360efbdSAlfred Perlstein default: 398060caaee2SIan Dowse p = NULL; 398160caaee2SIan Dowse len = 0; 39828360efbdSAlfred Perlstein } 39838360efbdSAlfred Perlstein 398460caaee2SIan Dowse if (nbytes != NULL) 398560caaee2SIan Dowse *nbytes = len; 398660caaee2SIan Dowse return (p); 39878360efbdSAlfred Perlstein } 39888360efbdSAlfred Perlstein 398919c46d8cSEdward Tomasz Napierala static void 3990a7a7d96cSPhilippe Charnier huphandler(int sig __unused) 399169d65572SIan Dowse { 399219c46d8cSEdward Tomasz Napierala 399369d65572SIan Dowse got_sighup = 1; 399469d65572SIan Dowse } 399569d65572SIan Dowse 399619c46d8cSEdward Tomasz Napierala static void 399719c46d8cSEdward Tomasz Napierala terminate(int sig __unused) 39988360efbdSAlfred Perlstein { 3999a032b226SPawel Jakub Dawidek pidfile_remove(pfh); 40000775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 40010775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 40028360efbdSAlfred Perlstein exit (0); 40038360efbdSAlfred Perlstein } 4004cc5efddeSRick Macklem 4005cc5efddeSRick Macklem static void 4006cc5efddeSRick Macklem cp_cred(struct expcred *outcr, struct expcred *incr) 4007cc5efddeSRick Macklem { 4008cc5efddeSRick Macklem 4009cc5efddeSRick Macklem outcr->cr_uid = incr->cr_uid; 4010cc5efddeSRick Macklem outcr->cr_ngroups = incr->cr_ngroups; 40112ffad162SRick Macklem if (outcr->cr_ngroups > SMALLNGROUPS) 40122ffad162SRick Macklem outcr->cr_groups = malloc(outcr->cr_ngroups * sizeof(gid_t)); 40132ffad162SRick Macklem else 40142ffad162SRick Macklem outcr->cr_groups = outcr->cr_smallgrps; 4015cc5efddeSRick Macklem memcpy(outcr->cr_groups, incr->cr_groups, incr->cr_ngroups * 4016cc5efddeSRick Macklem sizeof(gid_t)); 4017cc5efddeSRick Macklem } 4018