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