18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 48fae3551SRodney W. Grimes * Copyright (c) 1989, 1993 58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 68fae3551SRodney W. Grimes * 78fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 88fae3551SRodney W. Grimes * Herb Hasler and Rick Macklem at The University of Guelph. 98fae3551SRodney W. Grimes * 108fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 118fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 128fae3551SRodney W. Grimes * are met: 138fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 158fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 168fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 178fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 198fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 208fae3551SRodney W. Grimes * without specific prior written permission. 218fae3551SRodney W. Grimes * 228fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 238fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 248fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 258fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 268fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 278fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 288fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 298fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 308fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 318fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 328fae3551SRodney W. Grimes * SUCH DAMAGE. 338fae3551SRodney W. Grimes */ 348fae3551SRodney W. Grimes 358fae3551SRodney W. Grimes #ifndef lint 3674853402SPhilippe Charnier static const char copyright[] = 378fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\ 388fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 39d599144dSGarrett Wollman #endif /*not lint*/ 408fae3551SRodney W. Grimes 4174853402SPhilippe Charnier #if 0 4275201fa4SPhilippe Charnier #ifndef lint 4374853402SPhilippe Charnier static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 44d599144dSGarrett Wollman #endif /*not lint*/ 4575201fa4SPhilippe Charnier #endif 4675201fa4SPhilippe Charnier 4775201fa4SPhilippe Charnier #include <sys/cdefs.h> 4875201fa4SPhilippe Charnier __FBSDID("$FreeBSD$"); 498fae3551SRodney W. Grimes 508fae3551SRodney W. Grimes #include <sys/param.h> 518360efbdSAlfred Perlstein #include <sys/fcntl.h> 5291ca1a91SIan Dowse #include <sys/linker.h> 5391ca1a91SIan Dowse #include <sys/module.h> 54bcc1d071SRick Macklem #include <sys/mount.h> 55c9ac0f71SEmmanuel Vadot #include <sys/queue.h> 56bcc1d071SRick Macklem #include <sys/stat.h> 57bcc1d071SRick Macklem #include <sys/sysctl.h> 58bcc1d071SRick Macklem #include <sys/syslog.h> 598fae3551SRodney W. Grimes 608fae3551SRodney W. Grimes #include <rpc/rpc.h> 61bcb53b16SMartin Blapp #include <rpc/rpc_com.h> 628fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 638360efbdSAlfred Perlstein #include <rpc/pmap_prot.h> 648360efbdSAlfred Perlstein #include <rpcsvc/mount.h> 65a62dc406SDoug Rabson #include <nfs/nfsproto.h> 66bcc1d071SRick Macklem #include <nfs/nfssvc.h> 6791196234SPeter Wemm #include <nfsserver/nfs.h> 688fae3551SRodney W. Grimes 69bcc1d071SRick Macklem #include <fs/nfs/nfsport.h> 70bcc1d071SRick Macklem 718fae3551SRodney W. Grimes #include <arpa/inet.h> 728fae3551SRodney W. Grimes 738fae3551SRodney W. Grimes #include <ctype.h> 7474853402SPhilippe Charnier #include <err.h> 758fae3551SRodney W. Grimes #include <errno.h> 768fae3551SRodney W. Grimes #include <grp.h> 77a032b226SPawel Jakub Dawidek #include <libutil.h> 7889fdc4e1SMike Barcroft #include <limits.h> 798fae3551SRodney W. Grimes #include <netdb.h> 808fae3551SRodney W. Grimes #include <pwd.h> 818fae3551SRodney W. Grimes #include <signal.h> 828fae3551SRodney W. Grimes #include <stdio.h> 838fae3551SRodney W. Grimes #include <stdlib.h> 848fae3551SRodney W. Grimes #include <string.h> 858fae3551SRodney W. Grimes #include <unistd.h> 868fae3551SRodney W. Grimes #include "pathnames.h" 876a09faf2SCraig Rodrigues #include "mntopts.h" 888fae3551SRodney W. Grimes 898fae3551SRodney W. Grimes #ifdef DEBUG 908fae3551SRodney W. Grimes #include <stdarg.h> 918fae3551SRodney W. Grimes #endif 928fae3551SRodney W. Grimes 938fae3551SRodney W. Grimes /* 948fae3551SRodney W. Grimes * Structures for keeping the mount list and export list 958fae3551SRodney W. Grimes */ 968fae3551SRodney W. Grimes struct mountlist { 970775314bSDoug Rabson char ml_host[MNTNAMLEN+1]; 980775314bSDoug Rabson char ml_dirp[MNTPATHLEN+1]; 991da3e8b0SEmmanuel Vadot 1001da3e8b0SEmmanuel Vadot SLIST_ENTRY(mountlist) next; 1018fae3551SRodney W. Grimes }; 1028fae3551SRodney W. Grimes 1038fae3551SRodney W. Grimes struct dirlist { 1048fae3551SRodney W. Grimes struct dirlist *dp_left; 1058fae3551SRodney W. Grimes struct dirlist *dp_right; 1068fae3551SRodney W. Grimes int dp_flag; 1078fae3551SRodney W. Grimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 108380a3fcdSEmmanuel Vadot char *dp_dirp; 1098fae3551SRodney W. Grimes }; 1108fae3551SRodney W. Grimes /* dp_flag bits */ 1118fae3551SRodney W. Grimes #define DP_DEFSET 0x1 112a62dc406SDoug Rabson #define DP_HOSTSET 0x2 1138fae3551SRodney W. Grimes 1148fae3551SRodney W. Grimes struct exportlist { 1158fae3551SRodney W. Grimes struct dirlist *ex_dirl; 1168fae3551SRodney W. Grimes struct dirlist *ex_defdir; 1178fae3551SRodney W. Grimes int ex_flag; 1188fae3551SRodney W. Grimes fsid_t ex_fs; 1198fae3551SRodney W. Grimes char *ex_fsdir; 120cb3923e0SDoug Rabson char *ex_indexfile; 121a9148abdSDoug Rabson int ex_numsecflavors; 122a9148abdSDoug Rabson int ex_secflavors[MAXSECFLAVORS]; 123c3f86a25SRick Macklem int ex_defnumsecflavors; 124c3f86a25SRick Macklem int ex_defsecflavors[MAXSECFLAVORS]; 125c9ac0f71SEmmanuel Vadot 126c9ac0f71SEmmanuel Vadot SLIST_ENTRY(exportlist) entries; 1278fae3551SRodney W. Grimes }; 1288fae3551SRodney W. Grimes /* ex_flag bits */ 1298fae3551SRodney W. Grimes #define EX_LINKED 0x1 1308fae3551SRodney W. Grimes 1318fae3551SRodney W. Grimes struct netmsk { 1328360efbdSAlfred Perlstein struct sockaddr_storage nt_net; 13360caaee2SIan Dowse struct sockaddr_storage nt_mask; 1348fae3551SRodney W. Grimes char *nt_name; 1358fae3551SRodney W. Grimes }; 1368fae3551SRodney W. Grimes 1378fae3551SRodney W. Grimes union grouptypes { 1388360efbdSAlfred Perlstein struct addrinfo *gt_addrinfo; 1398fae3551SRodney W. Grimes struct netmsk gt_net; 1408fae3551SRodney W. Grimes }; 1418fae3551SRodney W. Grimes 1428fae3551SRodney W. Grimes struct grouplist { 1438fae3551SRodney W. Grimes int gr_type; 1448fae3551SRodney W. Grimes union grouptypes gr_ptr; 1458fae3551SRodney W. Grimes struct grouplist *gr_next; 146c3f86a25SRick Macklem int gr_numsecflavors; 147c3f86a25SRick Macklem int gr_secflavors[MAXSECFLAVORS]; 1488fae3551SRodney W. Grimes }; 1498fae3551SRodney W. Grimes /* Group types */ 1508fae3551SRodney W. Grimes #define GT_NULL 0x0 1518fae3551SRodney W. Grimes #define GT_HOST 0x1 1528fae3551SRodney W. Grimes #define GT_NET 0x2 1536d359f31SIan Dowse #define GT_DEFAULT 0x3 1548b5a6d67SBill Paul #define GT_IGNORE 0x5 1558fae3551SRodney W. Grimes 1568fae3551SRodney W. Grimes struct hostlist { 157a62dc406SDoug Rabson int ht_flag; /* Uses DP_xx bits */ 1588fae3551SRodney W. Grimes struct grouplist *ht_grp; 1598fae3551SRodney W. Grimes struct hostlist *ht_next; 1608fae3551SRodney W. Grimes }; 1618fae3551SRodney W. Grimes 162a62dc406SDoug Rabson struct fhreturn { 163a62dc406SDoug Rabson int fhr_flag; 164a62dc406SDoug Rabson int fhr_vers; 165a62dc406SDoug Rabson nfsfh_t fhr_fh; 166a9148abdSDoug Rabson int fhr_numsecflavors; 167a9148abdSDoug Rabson int *fhr_secflavors; 168a62dc406SDoug Rabson }; 169a62dc406SDoug Rabson 1708fb6ad5dSRick Macklem #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 1718fb6ad5dSRick Macklem 1728fae3551SRodney W. Grimes /* Global defs */ 17319c46d8cSEdward Tomasz Napierala static char *add_expdir(struct dirlist **, char *, int); 17419c46d8cSEdward Tomasz Napierala static void add_dlist(struct dirlist **, struct dirlist *, 175c3f86a25SRick Macklem struct grouplist *, int, struct exportlist *); 17619c46d8cSEdward Tomasz Napierala static void add_mlist(char *, char *); 17719c46d8cSEdward Tomasz Napierala static int check_dirpath(char *); 17819c46d8cSEdward Tomasz Napierala static int check_options(struct dirlist *); 17919c46d8cSEdward Tomasz Napierala static int checkmask(struct sockaddr *sa); 18019c46d8cSEdward Tomasz Napierala static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, 18119c46d8cSEdward Tomasz Napierala int *, int **); 182b875c2e9SJosh Paetzel static char *strsep_quote(char **stringp, const char *delim); 1838fb6ad5dSRick Macklem static int create_service(struct netconfig *nconf); 1848fb6ad5dSRick Macklem static void complete_service(struct netconfig *nconf, char *port_str); 1858fb6ad5dSRick Macklem static void clearout_service(void); 18619c46d8cSEdward Tomasz Napierala static void del_mlist(char *hostp, char *dirp); 18719c46d8cSEdward Tomasz Napierala static struct dirlist *dirp_search(struct dirlist *, char *); 18819c46d8cSEdward Tomasz Napierala static int do_mount(struct exportlist *, struct grouplist *, int, 18985429990SWarner Losh struct xucred *, char *, int, struct statfs *); 19019c46d8cSEdward Tomasz Napierala static int do_opt(char **, char **, struct exportlist *, 19119c46d8cSEdward Tomasz Napierala struct grouplist *, int *, int *, struct xucred *); 19219c46d8cSEdward Tomasz Napierala static struct exportlist *ex_search(fsid_t *); 19319c46d8cSEdward Tomasz Napierala static struct exportlist *get_exp(void); 19419c46d8cSEdward Tomasz Napierala static void free_dir(struct dirlist *); 19519c46d8cSEdward Tomasz Napierala static void free_exp(struct exportlist *); 19619c46d8cSEdward Tomasz Napierala static void free_grp(struct grouplist *); 19719c46d8cSEdward Tomasz Napierala static void free_host(struct hostlist *); 19819c46d8cSEdward Tomasz Napierala static void get_exportlist(void); 19919c46d8cSEdward Tomasz Napierala static int get_host(char *, struct grouplist *, struct grouplist *); 20019c46d8cSEdward Tomasz Napierala static struct hostlist *get_ht(void); 20119c46d8cSEdward Tomasz Napierala static int get_line(void); 20219c46d8cSEdward Tomasz Napierala static void get_mountlist(void); 20319c46d8cSEdward Tomasz Napierala static int get_net(char *, struct netmsk *, int); 204354fce28SConrad Meyer static void getexp_err(struct exportlist *, struct grouplist *, const char *); 20519c46d8cSEdward Tomasz Napierala static struct grouplist *get_grp(void); 20619c46d8cSEdward Tomasz Napierala static void hang_dirp(struct dirlist *, struct grouplist *, 20785429990SWarner Losh struct exportlist *, int); 20819c46d8cSEdward Tomasz Napierala static void huphandler(int sig); 20919c46d8cSEdward Tomasz Napierala static int makemask(struct sockaddr_storage *ssp, int bitlen); 21019c46d8cSEdward Tomasz Napierala static void mntsrv(struct svc_req *, SVCXPRT *); 21119c46d8cSEdward Tomasz Napierala static void nextfield(char **, char **); 21219c46d8cSEdward Tomasz Napierala static void out_of_mem(void); 21319c46d8cSEdward Tomasz Napierala static void parsecred(char *, struct xucred *); 21419c46d8cSEdward Tomasz Napierala static int parsesec(char *, struct exportlist *); 21519c46d8cSEdward Tomasz Napierala static int put_exlist(struct dirlist *, XDR *, struct dirlist *, 21619c46d8cSEdward Tomasz Napierala int *, int); 21719c46d8cSEdward Tomasz Napierala static void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 21819c46d8cSEdward Tomasz Napierala static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 21960caaee2SIan Dowse struct sockaddr *samask); 22019c46d8cSEdward Tomasz Napierala static int scan_tree(struct dirlist *, struct sockaddr *); 22185429990SWarner Losh static void usage(void); 22219c46d8cSEdward Tomasz Napierala static int xdr_dir(XDR *, char *); 22319c46d8cSEdward Tomasz Napierala static int xdr_explist(XDR *, caddr_t); 22419c46d8cSEdward Tomasz Napierala static int xdr_explist_brief(XDR *, caddr_t); 22519c46d8cSEdward Tomasz Napierala static int xdr_explist_common(XDR *, caddr_t, int); 22619c46d8cSEdward Tomasz Napierala static int xdr_fhs(XDR *, caddr_t); 22719c46d8cSEdward Tomasz Napierala static int xdr_mlist(XDR *, caddr_t); 22819c46d8cSEdward Tomasz Napierala static void terminate(int); 2298fae3551SRodney W. Grimes 230c9ac0f71SEmmanuel Vadot static SLIST_HEAD(, exportlist) exphead = SLIST_HEAD_INITIALIZER(exphead); 2311da3e8b0SEmmanuel Vadot static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(mlhead); 23219c46d8cSEdward Tomasz Napierala static struct grouplist *grphead; 23319c46d8cSEdward Tomasz Napierala static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 23419c46d8cSEdward Tomasz Napierala static char **exnames; 23519c46d8cSEdward Tomasz Napierala static char **hosts = NULL; 23619c46d8cSEdward Tomasz Napierala static struct xucred def_anon = { 23776183f34SDima Dorfman XUCRED_VERSION, 238947572b4SRick Macklem (uid_t)65534, 2398fae3551SRodney W. Grimes 1, 240947572b4SRick Macklem { (gid_t)65533 }, 241c0511d3bSBrian Feldman NULL 2428fae3551SRodney W. Grimes }; 24319c46d8cSEdward Tomasz Napierala static int force_v2 = 0; 24419c46d8cSEdward Tomasz Napierala static int resvport_only = 1; 24519c46d8cSEdward Tomasz Napierala static int nhosts = 0; 24619c46d8cSEdward Tomasz Napierala static int dir_only = 1; 24719c46d8cSEdward Tomasz Napierala static int dolog = 0; 24819c46d8cSEdward Tomasz Napierala static int got_sighup = 0; 24919c46d8cSEdward Tomasz Napierala static int xcreated = 0; 250d11e3645SMatteo Riondato 25119c46d8cSEdward Tomasz Napierala static char *svcport_str = NULL; 2528fb6ad5dSRick Macklem static int mallocd_svcport = 0; 2538fb6ad5dSRick Macklem static int *sock_fd; 2548fb6ad5dSRick Macklem static int sock_fdcnt; 2558fb6ad5dSRick Macklem static int sock_fdpos; 256c548eb5cSRick Macklem static int suspend_nfsd = 0; 2578360efbdSAlfred Perlstein 25819c46d8cSEdward Tomasz Napierala static int opt_flags; 2598360efbdSAlfred Perlstein static int have_v6 = 1; 2608360efbdSAlfred Perlstein 26119c46d8cSEdward Tomasz Napierala static int v4root_phase = 0; 26219c46d8cSEdward Tomasz Napierala static char v4root_dirpath[PATH_MAX + 1]; 26319c46d8cSEdward Tomasz Napierala static int has_publicfh = 0; 264bcc1d071SRick Macklem 26519c46d8cSEdward Tomasz Napierala static struct pidfh *pfh = NULL; 26660caaee2SIan Dowse /* Bits for opt_flags above */ 2678fae3551SRodney W. Grimes #define OP_MAPROOT 0x01 2688fae3551SRodney W. Grimes #define OP_MAPALL 0x02 26991196234SPeter Wemm /* 0x4 free */ 2708fae3551SRodney W. Grimes #define OP_MASK 0x08 2718fae3551SRodney W. Grimes #define OP_NET 0x10 2728fae3551SRodney W. Grimes #define OP_ALLDIRS 0x40 27360caaee2SIan Dowse #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 274288fa14aSJoerg Wunsch #define OP_QUIET 0x100 2758360efbdSAlfred Perlstein #define OP_MASKLEN 0x200 276a9148abdSDoug Rabson #define OP_SEC 0x400 2778fae3551SRodney W. Grimes 2788fae3551SRodney W. Grimes #ifdef DEBUG 27919c46d8cSEdward Tomasz Napierala static int debug = 1; 28019c46d8cSEdward Tomasz Napierala static void SYSLOG(int, const char *, ...) __printflike(2, 3); 2818fae3551SRodney W. Grimes #define syslog SYSLOG 2828fae3551SRodney W. Grimes #else 28319c46d8cSEdward Tomasz Napierala static int debug = 0; 2848fae3551SRodney W. Grimes #endif 2858fae3551SRodney W. Grimes 2868fae3551SRodney W. Grimes /* 287b875c2e9SJosh Paetzel * Similar to strsep(), but it allows for quoted strings 288b875c2e9SJosh Paetzel * and escaped characters. 289b875c2e9SJosh Paetzel * 290b875c2e9SJosh Paetzel * It returns the string (or NULL, if *stringp is NULL), 291b875c2e9SJosh Paetzel * which is a de-quoted version of the string if necessary. 292b875c2e9SJosh Paetzel * 293b875c2e9SJosh Paetzel * It modifies *stringp in place. 294b875c2e9SJosh Paetzel */ 295b875c2e9SJosh Paetzel static char * 296b875c2e9SJosh Paetzel strsep_quote(char **stringp, const char *delim) 297b875c2e9SJosh Paetzel { 298b875c2e9SJosh Paetzel char *srcptr, *dstptr, *retval; 299b875c2e9SJosh Paetzel char quot = 0; 300b875c2e9SJosh Paetzel 301b875c2e9SJosh Paetzel if (stringp == NULL || *stringp == NULL) 302b875c2e9SJosh Paetzel return (NULL); 303b875c2e9SJosh Paetzel 304b875c2e9SJosh Paetzel srcptr = dstptr = retval = *stringp; 305b875c2e9SJosh Paetzel 306b875c2e9SJosh Paetzel while (*srcptr) { 307b875c2e9SJosh Paetzel /* 308b875c2e9SJosh Paetzel * We're looking for several edge cases here. 309b875c2e9SJosh Paetzel * First: if we're in quote state (quot != 0), 310b875c2e9SJosh Paetzel * then we ignore the delim characters, but otherwise 311b875c2e9SJosh Paetzel * process as normal, unless it is the quote character. 312b875c2e9SJosh Paetzel * Second: if the current character is a backslash, 313b875c2e9SJosh Paetzel * we take the next character as-is, without checking 314b875c2e9SJosh Paetzel * for delim, quote, or backslash. Exception: if the 315b875c2e9SJosh Paetzel * next character is a NUL, that's the end of the string. 316b875c2e9SJosh Paetzel * Third: if the character is a quote character, we toggle 317b875c2e9SJosh Paetzel * quote state. 318b875c2e9SJosh Paetzel * Otherwise: check the current character for NUL, or 319b875c2e9SJosh Paetzel * being in delim, and end the string if either is true. 320b875c2e9SJosh Paetzel */ 321b875c2e9SJosh Paetzel if (*srcptr == '\\') { 322b875c2e9SJosh Paetzel srcptr++; 323b875c2e9SJosh Paetzel /* 324b875c2e9SJosh Paetzel * The edge case here is if the next character 325b875c2e9SJosh Paetzel * is NUL, we want to stop processing. But if 326b875c2e9SJosh Paetzel * it's not NUL, then we simply want to copy it. 327b875c2e9SJosh Paetzel */ 328b875c2e9SJosh Paetzel if (*srcptr) { 329b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 330b875c2e9SJosh Paetzel } 331b875c2e9SJosh Paetzel continue; 332b875c2e9SJosh Paetzel } 333b875c2e9SJosh Paetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 334b875c2e9SJosh Paetzel quot = *srcptr++; 335b875c2e9SJosh Paetzel continue; 336b875c2e9SJosh Paetzel } 337b875c2e9SJosh Paetzel if (quot && *srcptr == quot) { 338b875c2e9SJosh Paetzel /* End of the quoted part */ 339b875c2e9SJosh Paetzel quot = 0; 340b875c2e9SJosh Paetzel srcptr++; 341b875c2e9SJosh Paetzel continue; 342b875c2e9SJosh Paetzel } 343b875c2e9SJosh Paetzel if (!quot && strchr(delim, *srcptr)) 344b875c2e9SJosh Paetzel break; 345b875c2e9SJosh Paetzel *dstptr++ = *srcptr++; 346b875c2e9SJosh Paetzel } 347b875c2e9SJosh Paetzel 348b875c2e9SJosh Paetzel *dstptr = 0; /* Terminate the string */ 349b875c2e9SJosh Paetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 350b875c2e9SJosh Paetzel return (retval); 351b875c2e9SJosh Paetzel } 352b875c2e9SJosh Paetzel 353b875c2e9SJosh Paetzel /* 3548fae3551SRodney W. Grimes * Mountd server for NFS mount protocol as described in: 3558fae3551SRodney W. Grimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 3568fae3551SRodney W. Grimes * The optional arguments are the exports file name 3578fae3551SRodney W. Grimes * default: _PATH_EXPORTS 3588fae3551SRodney W. Grimes * and "-n" to allow nonroot mount. 3598fae3551SRodney W. Grimes */ 3608fae3551SRodney W. Grimes int 361a7a7d96cSPhilippe Charnier main(int argc, char **argv) 3628fae3551SRodney W. Grimes { 36369d65572SIan Dowse fd_set readfds; 364d11e3645SMatteo Riondato struct netconfig *nconf; 365d11e3645SMatteo Riondato char *endptr, **hosts_bak; 366d11e3645SMatteo Riondato void *nc_handle; 367a032b226SPawel Jakub Dawidek pid_t otherpid; 368d11e3645SMatteo Riondato in_port_t svcport; 369d11e3645SMatteo Riondato int c, k, s; 370bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE; 3718fb6ad5dSRick Macklem int attempt_cnt, port_len, port_pos, ret; 3728fb6ad5dSRick Macklem char **port_list; 3738360efbdSAlfred Perlstein 37401709abfSIan Dowse /* Check that another mountd isn't already running. */ 3758b28aef2SPawel Jakub Dawidek pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 376a032b226SPawel Jakub Dawidek if (pfh == NULL) { 377a032b226SPawel Jakub Dawidek if (errno == EEXIST) 378a032b226SPawel Jakub Dawidek errx(1, "mountd already running, pid: %d.", otherpid); 379a032b226SPawel Jakub Dawidek warn("cannot open or create pidfile"); 380a032b226SPawel Jakub Dawidek } 3818360efbdSAlfred Perlstein 3828360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 3838360efbdSAlfred Perlstein if (s < 0) 3848360efbdSAlfred Perlstein have_v6 = 0; 3858360efbdSAlfred Perlstein else 3868360efbdSAlfred Perlstein close(s); 3878fae3551SRodney W. Grimes 38879b86807SEdward Tomasz Napierala while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) 3898fae3551SRodney W. Grimes switch (c) { 3902a66cfc5SDoug Rabson case '2': 3912a66cfc5SDoug Rabson force_v2 = 1; 3922a66cfc5SDoug Rabson break; 3932179ae1eSRick Macklem case 'e': 3942a85df8cSRick Macklem /* now a no-op, since this is the default */ 395bcc1d071SRick Macklem break; 396a62dc406SDoug Rabson case 'n': 397a62dc406SDoug Rabson resvport_only = 0; 398a62dc406SDoug Rabson break; 399a62dc406SDoug Rabson case 'r': 400a62dc406SDoug Rabson dir_only = 0; 401a62dc406SDoug Rabson break; 4026444ef3bSPoul-Henning Kamp case 'd': 4036444ef3bSPoul-Henning Kamp debug = debug ? 0 : 1; 4046444ef3bSPoul-Henning Kamp break; 405f51631d7SGuido van Rooij case 'l': 406c903443aSPeter Wemm dolog = 1; 407f51631d7SGuido van Rooij break; 408c203da27SBruce M Simpson case 'p': 409c203da27SBruce M Simpson endptr = NULL; 410c203da27SBruce M Simpson svcport = (in_port_t)strtoul(optarg, &endptr, 10); 411c203da27SBruce M Simpson if (endptr == NULL || *endptr != '\0' || 412c203da27SBruce M Simpson svcport == 0 || svcport >= IPPORT_MAX) 413c203da27SBruce M Simpson usage(); 414d11e3645SMatteo Riondato svcport_str = strdup(optarg); 415d11e3645SMatteo Riondato break; 416d11e3645SMatteo Riondato case 'h': 417d11e3645SMatteo Riondato ++nhosts; 418d11e3645SMatteo Riondato hosts_bak = hosts; 419d11e3645SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 420d11e3645SMatteo Riondato if (hosts_bak == NULL) { 421d11e3645SMatteo Riondato if (hosts != NULL) { 422d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 423d11e3645SMatteo Riondato free(hosts[k]); 424d11e3645SMatteo Riondato free(hosts); 425d11e3645SMatteo Riondato out_of_mem(); 426d11e3645SMatteo Riondato } 427d11e3645SMatteo Riondato } 428d11e3645SMatteo Riondato hosts = hosts_bak; 429d11e3645SMatteo Riondato hosts[nhosts - 1] = strdup(optarg); 430d11e3645SMatteo Riondato if (hosts[nhosts - 1] == NULL) { 431d11e3645SMatteo Riondato for (k = 0; k < (nhosts - 1); k++) 432d11e3645SMatteo Riondato free(hosts[k]); 433d11e3645SMatteo Riondato free(hosts); 434d11e3645SMatteo Riondato out_of_mem(); 435d11e3645SMatteo Riondato } 436c203da27SBruce M Simpson break; 437c548eb5cSRick Macklem case 'S': 438c548eb5cSRick Macklem suspend_nfsd = 1; 439c548eb5cSRick Macklem break; 4408fae3551SRodney W. Grimes default: 44174853402SPhilippe Charnier usage(); 44280c7cc1cSPedro F. Giffuni } 443bcc1d071SRick Macklem 444bcc1d071SRick Macklem if (modfind("nfsd") < 0) { 445bcc1d071SRick Macklem /* Not present in kernel, try loading it */ 446bcc1d071SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 447bcc1d071SRick Macklem errx(1, "NFS server is not available"); 448bcc1d071SRick Macklem } 449bcc1d071SRick Macklem 4508fae3551SRodney W. Grimes argc -= optind; 4518fae3551SRodney W. Grimes argv += optind; 4528fae3551SRodney W. Grimes grphead = (struct grouplist *)NULL; 45396968c22SPawel Jakub Dawidek if (argc > 0) 45496968c22SPawel Jakub Dawidek exnames = argv; 45596968c22SPawel Jakub Dawidek else 45696968c22SPawel Jakub Dawidek exnames = exnames_default; 4578fae3551SRodney W. Grimes openlog("mountd", LOG_PID, LOG_DAEMON); 4588fae3551SRodney W. Grimes if (debug) 45974853402SPhilippe Charnier warnx("getting export list"); 4608fae3551SRodney W. Grimes get_exportlist(); 4618fae3551SRodney W. Grimes if (debug) 46274853402SPhilippe Charnier warnx("getting mount list"); 4638fae3551SRodney W. Grimes get_mountlist(); 4648fae3551SRodney W. Grimes if (debug) 46574853402SPhilippe Charnier warnx("here we go"); 4668fae3551SRodney W. Grimes if (debug == 0) { 4678fae3551SRodney W. Grimes daemon(0, 0); 4688fae3551SRodney W. Grimes signal(SIGINT, SIG_IGN); 4698fae3551SRodney W. Grimes signal(SIGQUIT, SIG_IGN); 4708fae3551SRodney W. Grimes } 47169d65572SIan Dowse signal(SIGHUP, huphandler); 4728360efbdSAlfred Perlstein signal(SIGTERM, terminate); 47309fc9dc6SCraig Rodrigues signal(SIGPIPE, SIG_IGN); 474a032b226SPawel Jakub Dawidek 475a032b226SPawel Jakub Dawidek pidfile_write(pfh); 476a032b226SPawel Jakub Dawidek 4770775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 4780775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 479bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 480bcb53b16SMartin Blapp 481c6e5e158SGuido van Rooij if (!resvport_only) { 4825ebee88dSRick Macklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL, 4834a0785aaSPeter Wemm &resvport_only, sizeof(resvport_only)) != 0 && 4844a0785aaSPeter Wemm errno != ENOENT) { 485394da4c1SGuido van Rooij syslog(LOG_ERR, "sysctl: %m"); 486394da4c1SGuido van Rooij exit(1); 487394da4c1SGuido van Rooij } 488c6e5e158SGuido van Rooij } 489c203da27SBruce M Simpson 490d11e3645SMatteo Riondato /* 491d11e3645SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to 492d11e3645SMatteo Riondato * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 493d11e3645SMatteo Riondato * list. 494d11e3645SMatteo Riondato */ 495d11e3645SMatteo Riondato if (nhosts == 0) { 496c9e1c304SUlrich Spörlein hosts = malloc(sizeof(char *)); 497d11e3645SMatteo Riondato if (hosts == NULL) 498d11e3645SMatteo Riondato out_of_mem(); 499d11e3645SMatteo Riondato hosts[0] = "*"; 500d11e3645SMatteo Riondato nhosts = 1; 501d11e3645SMatteo Riondato } else { 502d11e3645SMatteo Riondato hosts_bak = hosts; 503d11e3645SMatteo Riondato if (have_v6) { 504d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) * 505d11e3645SMatteo Riondato sizeof(char *)); 506d11e3645SMatteo Riondato if (hosts_bak == NULL) { 507d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 508d11e3645SMatteo Riondato free(hosts[k]); 509d11e3645SMatteo Riondato free(hosts); 510d11e3645SMatteo Riondato out_of_mem(); 511c203da27SBruce M Simpson } else 512d11e3645SMatteo Riondato hosts = hosts_bak; 513d11e3645SMatteo Riondato nhosts += 2; 514d11e3645SMatteo Riondato hosts[nhosts - 2] = "::1"; 515d11e3645SMatteo Riondato } else { 516d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 517d11e3645SMatteo Riondato if (hosts_bak == NULL) { 518d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 519d11e3645SMatteo Riondato free(hosts[k]); 520d11e3645SMatteo Riondato free(hosts); 521d11e3645SMatteo Riondato out_of_mem(); 522d11e3645SMatteo Riondato } else { 523d11e3645SMatteo Riondato nhosts += 1; 524d11e3645SMatteo Riondato hosts = hosts_bak; 5258fae3551SRodney W. Grimes } 526d11e3645SMatteo Riondato } 5278360efbdSAlfred Perlstein 528d11e3645SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1"; 5298360efbdSAlfred Perlstein } 5308360efbdSAlfred Perlstein 5318fb6ad5dSRick Macklem attempt_cnt = 1; 5328fb6ad5dSRick Macklem sock_fdcnt = 0; 5338fb6ad5dSRick Macklem sock_fd = NULL; 5348fb6ad5dSRick Macklem port_list = NULL; 5358fb6ad5dSRick Macklem port_len = 0; 536d11e3645SMatteo Riondato nc_handle = setnetconfig(); 537d11e3645SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) { 538d11e3645SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) { 539d11e3645SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 540d11e3645SMatteo Riondato "inet6") == 0) { 541d11e3645SMatteo Riondato /* DO NOTHING */ 5428fb6ad5dSRick Macklem } else { 5438fb6ad5dSRick Macklem ret = create_service(nconf); 5448fb6ad5dSRick Macklem if (ret == 1) 5458fb6ad5dSRick Macklem /* Ignore this call */ 5468fb6ad5dSRick Macklem continue; 5478fb6ad5dSRick Macklem if (ret < 0) { 5488fb6ad5dSRick Macklem /* 5498fb6ad5dSRick Macklem * Failed to bind port, so close off 5508fb6ad5dSRick Macklem * all sockets created and try again 5518fb6ad5dSRick Macklem * if the port# was dynamically 5528fb6ad5dSRick Macklem * assigned via bind(2). 5538fb6ad5dSRick Macklem */ 5548fb6ad5dSRick Macklem clearout_service(); 5558fb6ad5dSRick Macklem if (mallocd_svcport != 0 && 5568fb6ad5dSRick Macklem attempt_cnt < GETPORT_MAXTRY) { 5578fb6ad5dSRick Macklem free(svcport_str); 5588fb6ad5dSRick Macklem svcport_str = NULL; 5598fb6ad5dSRick Macklem mallocd_svcport = 0; 5608fb6ad5dSRick Macklem } else { 5618fb6ad5dSRick Macklem errno = EADDRINUSE; 5628fb6ad5dSRick Macklem syslog(LOG_ERR, 5638fb6ad5dSRick Macklem "bindresvport_sa: %m"); 5648fb6ad5dSRick Macklem exit(1); 5658fb6ad5dSRick Macklem } 5668fb6ad5dSRick Macklem 5678fb6ad5dSRick Macklem /* Start over at the first service. */ 5688fb6ad5dSRick Macklem free(sock_fd); 5698fb6ad5dSRick Macklem sock_fdcnt = 0; 5708fb6ad5dSRick Macklem sock_fd = NULL; 5718fb6ad5dSRick Macklem nc_handle = setnetconfig(); 5728fb6ad5dSRick Macklem attempt_cnt++; 5738fb6ad5dSRick Macklem } else if (mallocd_svcport != 0 && 5748fb6ad5dSRick Macklem attempt_cnt == GETPORT_MAXTRY) { 5758fb6ad5dSRick Macklem /* 5768fb6ad5dSRick Macklem * For the last attempt, allow 5778fb6ad5dSRick Macklem * different port #s for each nconf 5788fb6ad5dSRick Macklem * by saving the svcport_str and 5798fb6ad5dSRick Macklem * setting it back to NULL. 5808fb6ad5dSRick Macklem */ 5818fb6ad5dSRick Macklem port_list = realloc(port_list, 5828fb6ad5dSRick Macklem (port_len + 1) * sizeof(char *)); 5838fb6ad5dSRick Macklem if (port_list == NULL) 5848fb6ad5dSRick Macklem out_of_mem(); 5858fb6ad5dSRick Macklem port_list[port_len++] = svcport_str; 5868fb6ad5dSRick Macklem svcport_str = NULL; 5878fb6ad5dSRick Macklem mallocd_svcport = 0; 5888fb6ad5dSRick Macklem } 5898fb6ad5dSRick Macklem } 5908fb6ad5dSRick Macklem } 5918fb6ad5dSRick Macklem } 5928fb6ad5dSRick Macklem 5938fb6ad5dSRick Macklem /* 5948fb6ad5dSRick Macklem * Successfully bound the ports, so call complete_service() to 5958fb6ad5dSRick Macklem * do the rest of the setup on the service(s). 5968fb6ad5dSRick Macklem */ 5978fb6ad5dSRick Macklem sock_fdpos = 0; 5988fb6ad5dSRick Macklem port_pos = 0; 5998fb6ad5dSRick Macklem nc_handle = setnetconfig(); 6008fb6ad5dSRick Macklem while ((nconf = getnetconfig(nc_handle))) { 6018fb6ad5dSRick Macklem if (nconf->nc_flag & NC_VISIBLE) { 6028fb6ad5dSRick Macklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 6038fb6ad5dSRick Macklem "inet6") == 0) { 6048fb6ad5dSRick Macklem /* DO NOTHING */ 6058fb6ad5dSRick Macklem } else if (port_list != NULL) { 6068fb6ad5dSRick Macklem if (port_pos >= port_len) { 6078fb6ad5dSRick Macklem syslog(LOG_ERR, "too many port#s"); 6088fb6ad5dSRick Macklem exit(1); 6098fb6ad5dSRick Macklem } 6108fb6ad5dSRick Macklem complete_service(nconf, port_list[port_pos++]); 611c203da27SBruce M Simpson } else 6128fb6ad5dSRick Macklem complete_service(nconf, svcport_str); 6138360efbdSAlfred Perlstein } 614d11e3645SMatteo Riondato } 615d11e3645SMatteo Riondato endnetconfig(nc_handle); 6168fb6ad5dSRick Macklem free(sock_fd); 6178fb6ad5dSRick Macklem if (port_list != NULL) { 6188fb6ad5dSRick Macklem for (port_pos = 0; port_pos < port_len; port_pos++) 6198fb6ad5dSRick Macklem free(port_list[port_pos]); 6208fb6ad5dSRick Macklem free(port_list); 6218fb6ad5dSRick Macklem } 6228360efbdSAlfred Perlstein 6238360efbdSAlfred Perlstein if (xcreated == 0) { 6248360efbdSAlfred Perlstein syslog(LOG_ERR, "could not create any services"); 6252a66cfc5SDoug Rabson exit(1); 6262a66cfc5SDoug Rabson } 62769d65572SIan Dowse 62869d65572SIan Dowse /* Expand svc_run() here so that we can call get_exportlist(). */ 62969d65572SIan Dowse for (;;) { 63069d65572SIan Dowse if (got_sighup) { 63169d65572SIan Dowse get_exportlist(); 63269d65572SIan Dowse got_sighup = 0; 63369d65572SIan Dowse } 63469d65572SIan Dowse readfds = svc_fdset; 63569d65572SIan Dowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 63669d65572SIan Dowse case -1: 63769d65572SIan Dowse if (errno == EINTR) 63869d65572SIan Dowse continue; 63969d65572SIan Dowse syslog(LOG_ERR, "mountd died: select: %m"); 64074853402SPhilippe Charnier exit(1); 64169d65572SIan Dowse case 0: 64269d65572SIan Dowse continue; 64369d65572SIan Dowse default: 64469d65572SIan Dowse svc_getreqset(&readfds); 64569d65572SIan Dowse } 64669d65572SIan Dowse } 64774853402SPhilippe Charnier } 64874853402SPhilippe Charnier 649d11e3645SMatteo Riondato /* 650d11e3645SMatteo Riondato * This routine creates and binds sockets on the appropriate 6518fb6ad5dSRick Macklem * addresses. It gets called one time for each transport. 6528fb6ad5dSRick Macklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 6538fb6ad5dSRick Macklem * bind failed with EADDRINUSE. 6548fb6ad5dSRick Macklem * Any file descriptors that have been created are stored in sock_fd and 6558fb6ad5dSRick Macklem * the total count of them is maintained in sock_fdcnt. 656d11e3645SMatteo Riondato */ 6578fb6ad5dSRick Macklem static int 658d11e3645SMatteo Riondato create_service(struct netconfig *nconf) 659d11e3645SMatteo Riondato { 660d11e3645SMatteo Riondato struct addrinfo hints, *res = NULL; 661d11e3645SMatteo Riondato struct sockaddr_in *sin; 662d11e3645SMatteo Riondato struct sockaddr_in6 *sin6; 663d11e3645SMatteo Riondato struct __rpc_sockinfo si; 664d11e3645SMatteo Riondato int aicode; 665d11e3645SMatteo Riondato int fd; 666d11e3645SMatteo Riondato int nhostsbak; 667d11e3645SMatteo Riondato int one = 1; 668d11e3645SMatteo Riondato int r; 669d11e3645SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 6708fb6ad5dSRick Macklem int mallocd_res; 671d11e3645SMatteo Riondato 672d11e3645SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) && 673d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) && 674d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD)) 6758fb6ad5dSRick Macklem return (1); /* not my type */ 676d11e3645SMatteo Riondato 677d11e3645SMatteo Riondato /* 678d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 679d11e3645SMatteo Riondato */ 680d11e3645SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) { 681d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s", 682d11e3645SMatteo Riondato nconf->nc_netid); 6838fb6ad5dSRick Macklem return (1); 684d11e3645SMatteo Riondato } 685d11e3645SMatteo Riondato 686d11e3645SMatteo Riondato /* Get mountd's address on this transport */ 687d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 688d11e3645SMatteo Riondato hints.ai_family = si.si_af; 689d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 690d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 691d11e3645SMatteo Riondato 692d11e3645SMatteo Riondato /* 693d11e3645SMatteo Riondato * Bind to specific IPs if asked to 694d11e3645SMatteo Riondato */ 695d11e3645SMatteo Riondato nhostsbak = nhosts; 696d11e3645SMatteo Riondato while (nhostsbak > 0) { 697d11e3645SMatteo Riondato --nhostsbak; 6988fb6ad5dSRick Macklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 6998fb6ad5dSRick Macklem if (sock_fd == NULL) 7008fb6ad5dSRick Macklem out_of_mem(); 7018fb6ad5dSRick Macklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 7028fb6ad5dSRick Macklem mallocd_res = 0; 7038fb6ad5dSRick Macklem 7049745de4cSRyan Stone hints.ai_flags = AI_PASSIVE; 7059745de4cSRyan Stone 706d11e3645SMatteo Riondato /* 707d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 708d11e3645SMatteo Riondato */ 709d11e3645SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) { 710d11e3645SMatteo Riondato int non_fatal = 0; 711a5752d55SKevin Lo if (errno == EAFNOSUPPORT && 712d11e3645SMatteo Riondato nconf->nc_semantics != NC_TPI_CLTS) 713d11e3645SMatteo Riondato non_fatal = 1; 714d11e3645SMatteo Riondato 715d11e3645SMatteo Riondato syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 716d11e3645SMatteo Riondato "cannot create socket for %s", nconf->nc_netid); 7178fb6ad5dSRick Macklem if (non_fatal != 0) 7188fb6ad5dSRick Macklem continue; 7198fb6ad5dSRick Macklem exit(1); 720d11e3645SMatteo Riondato } 721d11e3645SMatteo Riondato 722d11e3645SMatteo Riondato switch (hints.ai_family) { 723d11e3645SMatteo Riondato case AF_INET: 724d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 725d11e3645SMatteo Riondato host_addr) == 1) { 7268fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 727d11e3645SMatteo Riondato } else { 728d11e3645SMatteo Riondato /* 729d11e3645SMatteo Riondato * Skip if we have an AF_INET6 address. 730d11e3645SMatteo Riondato */ 731d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 732d11e3645SMatteo Riondato host_addr) == 1) { 733d11e3645SMatteo Riondato close(fd); 734d11e3645SMatteo Riondato continue; 735d11e3645SMatteo Riondato } 736d11e3645SMatteo Riondato } 737d11e3645SMatteo Riondato break; 738d11e3645SMatteo Riondato case AF_INET6: 739d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 740d11e3645SMatteo Riondato host_addr) == 1) { 7418fb6ad5dSRick Macklem hints.ai_flags |= AI_NUMERICHOST; 742d11e3645SMatteo Riondato } else { 743d11e3645SMatteo Riondato /* 744d11e3645SMatteo Riondato * Skip if we have an AF_INET address. 745d11e3645SMatteo Riondato */ 746d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 747d11e3645SMatteo Riondato host_addr) == 1) { 748d11e3645SMatteo Riondato close(fd); 749d11e3645SMatteo Riondato continue; 750d11e3645SMatteo Riondato } 751d11e3645SMatteo Riondato } 752d11e3645SMatteo Riondato 753d11e3645SMatteo Riondato /* 754d11e3645SMatteo Riondato * We're doing host-based access checks here, so don't 755d11e3645SMatteo Riondato * allow v4-in-v6 to confuse things. The kernel will 756d11e3645SMatteo Riondato * disable it by default on NFS sockets too. 757d11e3645SMatteo Riondato */ 758d11e3645SMatteo Riondato if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 759d11e3645SMatteo Riondato sizeof one) < 0) { 760d11e3645SMatteo Riondato syslog(LOG_ERR, 761d11e3645SMatteo Riondato "can't disable v4-in-v6 on IPv6 socket"); 762d11e3645SMatteo Riondato exit(1); 763d11e3645SMatteo Riondato } 764d11e3645SMatteo Riondato break; 765d11e3645SMatteo Riondato default: 766d11e3645SMatteo Riondato break; 767d11e3645SMatteo Riondato } 768d11e3645SMatteo Riondato 769d11e3645SMatteo Riondato /* 770d11e3645SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY 771d11e3645SMatteo Riondato */ 772d11e3645SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) { 773d11e3645SMatteo Riondato if (svcport_str == NULL) { 774d11e3645SMatteo Riondato res = malloc(sizeof(struct addrinfo)); 775d11e3645SMatteo Riondato if (res == NULL) 776d11e3645SMatteo Riondato out_of_mem(); 7778fb6ad5dSRick Macklem mallocd_res = 1; 778d11e3645SMatteo Riondato res->ai_flags = hints.ai_flags; 779d11e3645SMatteo Riondato res->ai_family = hints.ai_family; 780d11e3645SMatteo Riondato res->ai_protocol = hints.ai_protocol; 781d11e3645SMatteo Riondato switch (res->ai_family) { 782d11e3645SMatteo Riondato case AF_INET: 783d11e3645SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in)); 784d11e3645SMatteo Riondato if (sin == NULL) 785d11e3645SMatteo Riondato out_of_mem(); 786d11e3645SMatteo Riondato sin->sin_family = AF_INET; 787d11e3645SMatteo Riondato sin->sin_port = htons(0); 788d11e3645SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY); 789d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin; 790d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 7918fb6ad5dSRick Macklem sizeof(struct sockaddr_in); 792d11e3645SMatteo Riondato break; 793d11e3645SMatteo Riondato case AF_INET6: 794d11e3645SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6)); 79589ca9145SSimon L. B. Nielsen if (sin6 == NULL) 796d11e3645SMatteo Riondato out_of_mem(); 797d11e3645SMatteo Riondato sin6->sin6_family = AF_INET6; 798d11e3645SMatteo Riondato sin6->sin6_port = htons(0); 799d11e3645SMatteo Riondato sin6->sin6_addr = in6addr_any; 800d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6; 801d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 8028fb6ad5dSRick Macklem sizeof(struct sockaddr_in6); 803d11e3645SMatteo Riondato break; 804d11e3645SMatteo Riondato default: 8058fb6ad5dSRick Macklem syslog(LOG_ERR, "bad addr fam %d", 8068fb6ad5dSRick Macklem res->ai_family); 8078fb6ad5dSRick Macklem exit(1); 808d11e3645SMatteo Riondato } 809d11e3645SMatteo Riondato } else { 810d11e3645SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str, 811d11e3645SMatteo Riondato &hints, &res)) != 0) { 812d11e3645SMatteo Riondato syslog(LOG_ERR, 813d11e3645SMatteo Riondato "cannot get local address for %s: %s", 814d11e3645SMatteo Riondato nconf->nc_netid, 815d11e3645SMatteo Riondato gai_strerror(aicode)); 8168fb6ad5dSRick Macklem close(fd); 817d11e3645SMatteo Riondato continue; 818d11e3645SMatteo Riondato } 819d11e3645SMatteo Riondato } 820d11e3645SMatteo Riondato } else { 821d11e3645SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 822d11e3645SMatteo Riondato &hints, &res)) != 0) { 823d11e3645SMatteo Riondato syslog(LOG_ERR, 824d11e3645SMatteo Riondato "cannot get local address for %s: %s", 825d11e3645SMatteo Riondato nconf->nc_netid, gai_strerror(aicode)); 8268fb6ad5dSRick Macklem close(fd); 827d11e3645SMatteo Riondato continue; 828d11e3645SMatteo Riondato } 829d11e3645SMatteo Riondato } 830d11e3645SMatteo Riondato 8318fb6ad5dSRick Macklem /* Store the fd. */ 8328fb6ad5dSRick Macklem sock_fd[sock_fdcnt - 1] = fd; 8338fb6ad5dSRick Macklem 8348fb6ad5dSRick Macklem /* Now, attempt the bind. */ 835d11e3645SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr); 836d11e3645SMatteo Riondato if (r != 0) { 8378fb6ad5dSRick Macklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 8388fb6ad5dSRick Macklem if (mallocd_res != 0) { 8398fb6ad5dSRick Macklem free(res->ai_addr); 8408fb6ad5dSRick Macklem free(res); 8418fb6ad5dSRick Macklem } else 8428fb6ad5dSRick Macklem freeaddrinfo(res); 8438fb6ad5dSRick Macklem return (-1); 8448fb6ad5dSRick Macklem } 845d11e3645SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m"); 846d11e3645SMatteo Riondato exit(1); 847d11e3645SMatteo Riondato } 848d11e3645SMatteo Riondato 8498fb6ad5dSRick Macklem if (svcport_str == NULL) { 8508fb6ad5dSRick Macklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 8518fb6ad5dSRick Macklem if (svcport_str == NULL) 8528fb6ad5dSRick Macklem out_of_mem(); 8538fb6ad5dSRick Macklem mallocd_svcport = 1; 8548fb6ad5dSRick Macklem 8558fb6ad5dSRick Macklem if (getnameinfo(res->ai_addr, 8568fb6ad5dSRick Macklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 8578fb6ad5dSRick Macklem svcport_str, NI_MAXSERV * sizeof(char), 8588fb6ad5dSRick Macklem NI_NUMERICHOST | NI_NUMERICSERV)) 8598fb6ad5dSRick Macklem errx(1, "Cannot get port number"); 8608fb6ad5dSRick Macklem } 8618fb6ad5dSRick Macklem if (mallocd_res != 0) { 8628fb6ad5dSRick Macklem free(res->ai_addr); 8638fb6ad5dSRick Macklem free(res); 8648fb6ad5dSRick Macklem } else 8658fb6ad5dSRick Macklem freeaddrinfo(res); 8668fb6ad5dSRick Macklem res = NULL; 8678fb6ad5dSRick Macklem } 8688fb6ad5dSRick Macklem return (0); 8698fb6ad5dSRick Macklem } 8708fb6ad5dSRick Macklem 8718fb6ad5dSRick Macklem /* 8728fb6ad5dSRick Macklem * Called after all the create_service() calls have succeeded, to complete 8738fb6ad5dSRick Macklem * the setup and registration. 8748fb6ad5dSRick Macklem */ 8758fb6ad5dSRick Macklem static void 8768fb6ad5dSRick Macklem complete_service(struct netconfig *nconf, char *port_str) 8778fb6ad5dSRick Macklem { 8788fb6ad5dSRick Macklem struct addrinfo hints, *res = NULL; 8798fb6ad5dSRick Macklem struct __rpc_sockinfo si; 8808fb6ad5dSRick Macklem struct netbuf servaddr; 8818fb6ad5dSRick Macklem SVCXPRT *transp = NULL; 8828fb6ad5dSRick Macklem int aicode, fd, nhostsbak; 8838fb6ad5dSRick Macklem int registered = 0; 8848fb6ad5dSRick Macklem 8858fb6ad5dSRick Macklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 8868fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS) && 8878fb6ad5dSRick Macklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 8888fb6ad5dSRick Macklem return; /* not my type */ 8898fb6ad5dSRick Macklem 8908fb6ad5dSRick Macklem /* 8918fb6ad5dSRick Macklem * XXX - using RPC library internal functions. 8928fb6ad5dSRick Macklem */ 8938fb6ad5dSRick Macklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 8948fb6ad5dSRick Macklem syslog(LOG_ERR, "cannot get information for %s", 8958fb6ad5dSRick Macklem nconf->nc_netid); 8968fb6ad5dSRick Macklem return; 8978fb6ad5dSRick Macklem } 8988fb6ad5dSRick Macklem 8998fb6ad5dSRick Macklem nhostsbak = nhosts; 9008fb6ad5dSRick Macklem while (nhostsbak > 0) { 9018fb6ad5dSRick Macklem --nhostsbak; 9028fb6ad5dSRick Macklem if (sock_fdpos >= sock_fdcnt) { 9038fb6ad5dSRick Macklem /* Should never happen. */ 9048fb6ad5dSRick Macklem syslog(LOG_ERR, "Ran out of socket fd's"); 9058fb6ad5dSRick Macklem return; 9068fb6ad5dSRick Macklem } 9078fb6ad5dSRick Macklem fd = sock_fd[sock_fdpos++]; 9088fb6ad5dSRick Macklem if (fd < 0) 9098fb6ad5dSRick Macklem continue; 9108fb6ad5dSRick Macklem 911*93840fdeSSean Eric Fagan /* 912*93840fdeSSean Eric Fagan * Using -1 tells listen(2) to use 913*93840fdeSSean Eric Fagan * kern.ipc.soacceptqueue for the backlog. 914*93840fdeSSean Eric Fagan */ 915d11e3645SMatteo Riondato if (nconf->nc_semantics != NC_TPI_CLTS) 916*93840fdeSSean Eric Fagan listen(fd, -1); 917d11e3645SMatteo Riondato 918d11e3645SMatteo Riondato if (nconf->nc_semantics == NC_TPI_CLTS ) 919d11e3645SMatteo Riondato transp = svc_dg_create(fd, 0, 0); 920d11e3645SMatteo Riondato else 921d11e3645SMatteo Riondato transp = svc_vc_create(fd, RPC_MAXDATASIZE, 922d11e3645SMatteo Riondato RPC_MAXDATASIZE); 923d11e3645SMatteo Riondato 924d11e3645SMatteo Riondato if (transp != (SVCXPRT *) NULL) { 9250775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 926d11e3645SMatteo Riondato NULL)) 927d11e3645SMatteo Riondato syslog(LOG_ERR, 9280775314bSDoug Rabson "can't register %s MOUNTVERS service", 929d11e3645SMatteo Riondato nconf->nc_netid); 930d11e3645SMatteo Riondato if (!force_v2) { 9310775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 932d11e3645SMatteo Riondato mntsrv, NULL)) 933d11e3645SMatteo Riondato syslog(LOG_ERR, 9340775314bSDoug Rabson "can't register %s MOUNTVERS3 service", 935d11e3645SMatteo Riondato nconf->nc_netid); 936d11e3645SMatteo Riondato } 937d11e3645SMatteo Riondato } else 938d11e3645SMatteo Riondato syslog(LOG_WARNING, "can't create %s services", 939d11e3645SMatteo Riondato nconf->nc_netid); 940d11e3645SMatteo Riondato 941d11e3645SMatteo Riondato if (registered == 0) { 942d11e3645SMatteo Riondato registered = 1; 943d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 944d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE; 945d11e3645SMatteo Riondato hints.ai_family = si.si_af; 946d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 947d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 948d11e3645SMatteo Riondato 9498fb6ad5dSRick Macklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 950d11e3645SMatteo Riondato &res)) != 0) { 951d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s", 952d11e3645SMatteo Riondato gai_strerror(aicode)); 953d11e3645SMatteo Riondato exit(1); 954d11e3645SMatteo Riondato } 955d11e3645SMatteo Riondato 956d11e3645SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen); 957d11e3645SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 958d11e3645SMatteo Riondato servaddr.len = res->ai_addrlen; 959d11e3645SMatteo Riondato 9600775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 9610775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 962d11e3645SMatteo Riondato 963d11e3645SMatteo Riondato xcreated++; 964d11e3645SMatteo Riondato freeaddrinfo(res); 965d11e3645SMatteo Riondato } 966d11e3645SMatteo Riondato } /* end while */ 967d11e3645SMatteo Riondato } 968d11e3645SMatteo Riondato 9698fb6ad5dSRick Macklem /* 9708fb6ad5dSRick Macklem * Clear out sockets after a failure to bind one of them, so that the 9718fb6ad5dSRick Macklem * cycle of socket creation/binding can start anew. 9728fb6ad5dSRick Macklem */ 9738fb6ad5dSRick Macklem static void 9748fb6ad5dSRick Macklem clearout_service(void) 9758fb6ad5dSRick Macklem { 9768fb6ad5dSRick Macklem int i; 9778fb6ad5dSRick Macklem 9788fb6ad5dSRick Macklem for (i = 0; i < sock_fdcnt; i++) { 9798fb6ad5dSRick Macklem if (sock_fd[i] >= 0) { 9808fb6ad5dSRick Macklem shutdown(sock_fd[i], SHUT_RDWR); 9818fb6ad5dSRick Macklem close(sock_fd[i]); 9828fb6ad5dSRick Macklem } 9838fb6ad5dSRick Macklem } 9848fb6ad5dSRick Macklem } 9858fb6ad5dSRick Macklem 98674853402SPhilippe Charnier static void 987a7a7d96cSPhilippe Charnier usage(void) 98874853402SPhilippe Charnier { 98974853402SPhilippe Charnier fprintf(stderr, 9902179ae1eSRick Macklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 991c548eb5cSRick Macklem "[-S] [-h <bindip>] [export_file ...]\n"); 9928fae3551SRodney W. Grimes exit(1); 9938fae3551SRodney W. Grimes } 9948fae3551SRodney W. Grimes 9958fae3551SRodney W. Grimes /* 9968fae3551SRodney W. Grimes * The mount rpc service 9978fae3551SRodney W. Grimes */ 9988fae3551SRodney W. Grimes void 999a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 10008fae3551SRodney W. Grimes { 10018fae3551SRodney W. Grimes struct exportlist *ep; 10028fae3551SRodney W. Grimes struct dirlist *dp; 1003a62dc406SDoug Rabson struct fhreturn fhr; 10048fae3551SRodney W. Grimes struct stat stb; 10058fae3551SRodney W. Grimes struct statfs fsb; 10068360efbdSAlfred Perlstein char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 10078360efbdSAlfred Perlstein int lookup_failed = 1; 10088360efbdSAlfred Perlstein struct sockaddr *saddr; 1009a62dc406SDoug Rabson u_short sport; 10100775314bSDoug Rabson char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 1011e90cdb54SGuido van Rooij int bad = 0, defset, hostset; 1012a62dc406SDoug Rabson sigset_t sighup_mask; 1013c3f86a25SRick Macklem int numsecflavors, *secflavorsp; 10148fae3551SRodney W. Grimes 1015a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1016a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 10178360efbdSAlfred Perlstein saddr = svc_getrpccaller(transp)->buf; 10188360efbdSAlfred Perlstein switch (saddr->sa_family) { 10198360efbdSAlfred Perlstein case AF_INET6: 102001709abfSIan Dowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 10218360efbdSAlfred Perlstein break; 10228360efbdSAlfred Perlstein case AF_INET: 102301709abfSIan Dowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 10248360efbdSAlfred Perlstein break; 10258360efbdSAlfred Perlstein default: 10268360efbdSAlfred Perlstein syslog(LOG_ERR, "request from unknown address family"); 10278360efbdSAlfred Perlstein return; 10288360efbdSAlfred Perlstein } 10298360efbdSAlfred Perlstein lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 10308360efbdSAlfred Perlstein NULL, 0, 0); 10318360efbdSAlfred Perlstein getnameinfo(saddr, saddr->sa_len, numerichost, 10328360efbdSAlfred Perlstein sizeof numerichost, NULL, 0, NI_NUMERICHOST); 10338fae3551SRodney W. Grimes switch (rqstp->rq_proc) { 10348fae3551SRodney W. Grimes case NULLPROC: 1035389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 103674853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 10378fae3551SRodney W. Grimes return; 10380775314bSDoug Rabson case MOUNTPROC_MNT: 1039a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1040f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1041f51631d7SGuido van Rooij "mount request from %s from unprivileged port", 10428360efbdSAlfred Perlstein numerichost); 10438fae3551SRodney W. Grimes svcerr_weakauth(transp); 10448fae3551SRodney W. Grimes return; 10458fae3551SRodney W. Grimes } 1046389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1047f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable mount request from %s", 10488360efbdSAlfred Perlstein numerichost); 10498fae3551SRodney W. Grimes svcerr_decode(transp); 10508fae3551SRodney W. Grimes return; 10518fae3551SRodney W. Grimes } 10528fae3551SRodney W. Grimes 10538fae3551SRodney W. Grimes /* 10548fae3551SRodney W. Grimes * Get the real pathname and make sure it is a directory 1055a62dc406SDoug Rabson * or a regular file if the -r option was specified 1056a62dc406SDoug Rabson * and it exists. 10578fae3551SRodney W. Grimes */ 1058cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL || 10598fae3551SRodney W. Grimes stat(dirpath, &stb) < 0 || 10608fae3551SRodney W. Grimes statfs(dirpath, &fsb) < 0) { 10618fae3551SRodney W. Grimes chdir("/"); /* Just in case realpath doesn't */ 1062f51631d7SGuido van Rooij syslog(LOG_NOTICE, 106374853402SPhilippe Charnier "mount request from %s for non existent path %s", 10648360efbdSAlfred Perlstein numerichost, dirpath); 10658fae3551SRodney W. Grimes if (debug) 106674853402SPhilippe Charnier warnx("stat failed on %s", dirpath); 1067e90cdb54SGuido van Rooij bad = ENOENT; /* We will send error reply later */ 10688fae3551SRodney W. Grimes } 1069b235f015SRavi Pokala if (!bad && 1070b235f015SRavi Pokala !S_ISDIR(stb.st_mode) && 1071b235f015SRavi Pokala (dir_only || !S_ISREG(stb.st_mode))) { 1072b235f015SRavi Pokala syslog(LOG_NOTICE, 1073b235f015SRavi Pokala "mount request from %s for non-directory path %s", 1074b235f015SRavi Pokala numerichost, dirpath); 1075b235f015SRavi Pokala if (debug) 1076b235f015SRavi Pokala warnx("mounting non-directory %s", dirpath); 1077b235f015SRavi Pokala bad = ENOTDIR; /* We will send error reply later */ 1078b235f015SRavi Pokala } 10798fae3551SRodney W. Grimes 10808fae3551SRodney W. Grimes /* Check in the exports list */ 1081a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1082b235f015SRavi Pokala if (bad) 1083b235f015SRavi Pokala ep = NULL; 1084b235f015SRavi Pokala else 10858fae3551SRodney W. Grimes ep = ex_search(&fsb.f_fsid); 1086a62dc406SDoug Rabson hostset = defset = 0; 1087c3f86a25SRick Macklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1088c3f86a25SRick Macklem &numsecflavors, &secflavorsp) || 10898fae3551SRodney W. Grimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1090c3f86a25SRick Macklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1091c3f86a25SRick Macklem &secflavorsp)) || 10928fae3551SRodney W. Grimes (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 10938fae3551SRodney W. Grimes scan_tree(ep->ex_dirl, saddr) == 0))) { 1094e90cdb54SGuido van Rooij if (bad) { 1095389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 1096e90cdb54SGuido van Rooij (caddr_t)&bad)) 109774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1098e90cdb54SGuido van Rooij sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1099e90cdb54SGuido van Rooij return; 1100e90cdb54SGuido van Rooij } 1101c3f86a25SRick Macklem if (hostset & DP_HOSTSET) { 1102a62dc406SDoug Rabson fhr.fhr_flag = hostset; 1103c3f86a25SRick Macklem fhr.fhr_numsecflavors = numsecflavors; 1104c3f86a25SRick Macklem fhr.fhr_secflavors = secflavorsp; 1105c3f86a25SRick Macklem } else { 1106a62dc406SDoug Rabson fhr.fhr_flag = defset; 1107c3f86a25SRick Macklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1108c3f86a25SRick Macklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1109c3f86a25SRick Macklem } 1110a62dc406SDoug Rabson fhr.fhr_vers = rqstp->rq_vers; 11118fae3551SRodney W. Grimes /* Get the file handle */ 111287564113SPeter Wemm memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 1113a62dc406SDoug Rabson if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 11148fae3551SRodney W. Grimes bad = errno; 111574853402SPhilippe Charnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1116389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 11178fae3551SRodney W. Grimes (caddr_t)&bad)) 111874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1119a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11208fae3551SRodney W. Grimes return; 11218fae3551SRodney W. Grimes } 1122389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1123389b8446SPeter Wemm (caddr_t)&fhr)) 112474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 11258360efbdSAlfred Perlstein if (!lookup_failed) 11268360efbdSAlfred Perlstein add_mlist(host, dirpath); 11278fae3551SRodney W. Grimes else 11288360efbdSAlfred Perlstein add_mlist(numerichost, dirpath); 11298fae3551SRodney W. Grimes if (debug) 113074853402SPhilippe Charnier warnx("mount successful"); 1131c903443aSPeter Wemm if (dolog) 1132f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1133f51631d7SGuido van Rooij "mount request succeeded from %s for %s", 11348360efbdSAlfred Perlstein numerichost, dirpath); 1135f51631d7SGuido van Rooij } else { 1136b235f015SRavi Pokala if (!bad) 11378fae3551SRodney W. Grimes bad = EACCES; 1138f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1139f51631d7SGuido van Rooij "mount request denied from %s for %s", 11408360efbdSAlfred Perlstein numerichost, dirpath); 1141f51631d7SGuido van Rooij } 1142e90cdb54SGuido van Rooij 1143389b8446SPeter Wemm if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1144389b8446SPeter Wemm (caddr_t)&bad)) 114574853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1146a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11478fae3551SRodney W. Grimes return; 11480775314bSDoug Rabson case MOUNTPROC_DUMP: 1149389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 115074853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1151c903443aSPeter Wemm else if (dolog) 1152f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1153f51631d7SGuido van Rooij "dump request succeeded from %s", 11548360efbdSAlfred Perlstein numerichost); 11558fae3551SRodney W. Grimes return; 11560775314bSDoug Rabson case MOUNTPROC_UMNT: 1157a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1158f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1159f51631d7SGuido van Rooij "umount request from %s from unprivileged port", 11608360efbdSAlfred Perlstein numerichost); 11618fae3551SRodney W. Grimes svcerr_weakauth(transp); 11628fae3551SRodney W. Grimes return; 11638fae3551SRodney W. Grimes } 1164389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 1165f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable umount request from %s", 11668360efbdSAlfred Perlstein numerichost); 11678fae3551SRodney W. Grimes svcerr_decode(transp); 11688fae3551SRodney W. Grimes return; 11698fae3551SRodney W. Grimes } 1170cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL) { 1171cb479b11SAlfred Perlstein syslog(LOG_NOTICE, "umount request from %s " 1172cb479b11SAlfred Perlstein "for non existent path %s", 11738360efbdSAlfred Perlstein numerichost, dirpath); 1174cb479b11SAlfred Perlstein } 1175389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 117674853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 11778360efbdSAlfred Perlstein if (!lookup_failed) 117801709abfSIan Dowse del_mlist(host, dirpath); 117901709abfSIan Dowse del_mlist(numerichost, dirpath); 1180c903443aSPeter Wemm if (dolog) 1181f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1182f51631d7SGuido van Rooij "umount request succeeded from %s for %s", 11838360efbdSAlfred Perlstein numerichost, dirpath); 11848fae3551SRodney W. Grimes return; 11850775314bSDoug Rabson case MOUNTPROC_UMNTALL: 1186a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 1187f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1188f51631d7SGuido van Rooij "umountall request from %s from unprivileged port", 11898360efbdSAlfred Perlstein numerichost); 11908fae3551SRodney W. Grimes svcerr_weakauth(transp); 11918fae3551SRodney W. Grimes return; 11928fae3551SRodney W. Grimes } 1193389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 119474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 11958360efbdSAlfred Perlstein if (!lookup_failed) 119601709abfSIan Dowse del_mlist(host, NULL); 119701709abfSIan Dowse del_mlist(numerichost, NULL); 1198c903443aSPeter Wemm if (dolog) 1199f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1200f51631d7SGuido van Rooij "umountall request succeeded from %s", 12018360efbdSAlfred Perlstein numerichost); 12028fae3551SRodney W. Grimes return; 12030775314bSDoug Rabson case MOUNTPROC_EXPORT: 1204389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1205389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1206389b8446SPeter Wemm (caddr_t)NULL)) 120774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 1208c903443aSPeter Wemm if (dolog) 1209f51631d7SGuido van Rooij syslog(LOG_NOTICE, 1210f51631d7SGuido van Rooij "export request succeeded from %s", 12118360efbdSAlfred Perlstein numerichost); 12128fae3551SRodney W. Grimes return; 12138fae3551SRodney W. Grimes default: 12148fae3551SRodney W. Grimes svcerr_noproc(transp); 12158fae3551SRodney W. Grimes return; 12168fae3551SRodney W. Grimes } 12178fae3551SRodney W. Grimes } 12188fae3551SRodney W. Grimes 12198fae3551SRodney W. Grimes /* 12208fae3551SRodney W. Grimes * Xdr conversion for a dirpath string 12218fae3551SRodney W. Grimes */ 122219c46d8cSEdward Tomasz Napierala static int 1223a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp) 12248fae3551SRodney W. Grimes { 12250775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 12268fae3551SRodney W. Grimes } 12278fae3551SRodney W. Grimes 12288fae3551SRodney W. Grimes /* 1229a62dc406SDoug Rabson * Xdr routine to generate file handle reply 12308fae3551SRodney W. Grimes */ 123119c46d8cSEdward Tomasz Napierala static int 1232a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp) 12338fae3551SRodney W. Grimes { 12343d438ad6SDavid E. O'Brien struct fhreturn *fhrp = (struct fhreturn *)cp; 1235a62dc406SDoug Rabson u_long ok = 0, len, auth; 1236a9148abdSDoug Rabson int i; 12378fae3551SRodney W. Grimes 12388fae3551SRodney W. Grimes if (!xdr_long(xdrsp, &ok)) 12398fae3551SRodney W. Grimes return (0); 1240a62dc406SDoug Rabson switch (fhrp->fhr_vers) { 1241a62dc406SDoug Rabson case 1: 1242a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 1243a62dc406SDoug Rabson case 3: 1244a62dc406SDoug Rabson len = NFSX_V3FH; 1245a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1246a62dc406SDoug Rabson return (0); 1247a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 1248a62dc406SDoug Rabson return (0); 1249a9148abdSDoug Rabson if (fhrp->fhr_numsecflavors) { 1250a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1251a9148abdSDoug Rabson return (0); 1252a9148abdSDoug Rabson for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1253a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1254a9148abdSDoug Rabson return (0); 1255a9148abdSDoug Rabson return (1); 1256a9148abdSDoug Rabson } else { 1257a9148abdSDoug Rabson auth = AUTH_SYS; 1258a62dc406SDoug Rabson len = 1; 1259a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 1260a62dc406SDoug Rabson return (0); 1261a62dc406SDoug Rabson return (xdr_long(xdrsp, &auth)); 1262a9148abdSDoug Rabson } 126380c7cc1cSPedro F. Giffuni } 1264a62dc406SDoug Rabson return (0); 12658fae3551SRodney W. Grimes } 12668fae3551SRodney W. Grimes 126719c46d8cSEdward Tomasz Napierala static int 1268a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused) 12698fae3551SRodney W. Grimes { 12708fae3551SRodney W. Grimes struct mountlist *mlp; 12718fae3551SRodney W. Grimes int true = 1; 12728fae3551SRodney W. Grimes int false = 0; 12738fae3551SRodney W. Grimes char *strp; 12748fae3551SRodney W. Grimes 12751da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 12768fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 12778fae3551SRodney W. Grimes return (0); 12788fae3551SRodney W. Grimes strp = &mlp->ml_host[0]; 12790775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 12808fae3551SRodney W. Grimes return (0); 12818fae3551SRodney W. Grimes strp = &mlp->ml_dirp[0]; 12820775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12838fae3551SRodney W. Grimes return (0); 12848fae3551SRodney W. Grimes } 12858fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 12868fae3551SRodney W. Grimes return (0); 12878fae3551SRodney W. Grimes return (1); 12888fae3551SRodney W. Grimes } 12898fae3551SRodney W. Grimes 12908fae3551SRodney W. Grimes /* 12918fae3551SRodney W. Grimes * Xdr conversion for export list 12928fae3551SRodney W. Grimes */ 129319c46d8cSEdward Tomasz Napierala static int 1294a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 12958fae3551SRodney W. Grimes { 12968fae3551SRodney W. Grimes struct exportlist *ep; 12978fae3551SRodney W. Grimes int false = 0; 1298a62dc406SDoug Rabson int putdef; 1299a62dc406SDoug Rabson sigset_t sighup_mask; 13008fae3551SRodney W. Grimes 1301a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1302a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 1303a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1304c9ac0f71SEmmanuel Vadot 1305c9ac0f71SEmmanuel Vadot SLIST_FOREACH(ep, &exphead, entries) { 13068fae3551SRodney W. Grimes putdef = 0; 130791acb349SAlfred Perlstein if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 130891acb349SAlfred Perlstein &putdef, brief)) 13098fae3551SRodney W. Grimes goto errout; 13108fae3551SRodney W. Grimes if (ep->ex_defdir && putdef == 0 && 13118fae3551SRodney W. Grimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 131291acb349SAlfred Perlstein &putdef, brief)) 13138fae3551SRodney W. Grimes goto errout; 13148fae3551SRodney W. Grimes } 1315a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13168fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 13178fae3551SRodney W. Grimes return (0); 13188fae3551SRodney W. Grimes return (1); 13198fae3551SRodney W. Grimes errout: 1320a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13218fae3551SRodney W. Grimes return (0); 13228fae3551SRodney W. Grimes } 13238fae3551SRodney W. Grimes 13248fae3551SRodney W. Grimes /* 13258fae3551SRodney W. Grimes * Called from xdr_explist() to traverse the tree and export the 13268fae3551SRodney W. Grimes * directory paths. 13278fae3551SRodney W. Grimes */ 132819c46d8cSEdward Tomasz Napierala static int 1329a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1330a7a7d96cSPhilippe Charnier int brief) 13318fae3551SRodney W. Grimes { 13328fae3551SRodney W. Grimes struct grouplist *grp; 13338fae3551SRodney W. Grimes struct hostlist *hp; 13348fae3551SRodney W. Grimes int true = 1; 13358fae3551SRodney W. Grimes int false = 0; 13368fae3551SRodney W. Grimes int gotalldir = 0; 13378fae3551SRodney W. Grimes char *strp; 13388fae3551SRodney W. Grimes 13398fae3551SRodney W. Grimes if (dp) { 134091acb349SAlfred Perlstein if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 13418fae3551SRodney W. Grimes return (1); 13428fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 13438fae3551SRodney W. Grimes return (1); 13448fae3551SRodney W. Grimes strp = dp->dp_dirp; 13450775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 13468fae3551SRodney W. Grimes return (1); 13478fae3551SRodney W. Grimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 13488fae3551SRodney W. Grimes gotalldir = 1; 13498fae3551SRodney W. Grimes *putdefp = 1; 13508fae3551SRodney W. Grimes } 135191acb349SAlfred Perlstein if (brief) { 135291acb349SAlfred Perlstein if (!xdr_bool(xdrsp, &true)) 135391acb349SAlfred Perlstein return (1); 135491acb349SAlfred Perlstein strp = "(...)"; 13550775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 135691acb349SAlfred Perlstein return (1); 135791acb349SAlfred Perlstein } else if ((dp->dp_flag & DP_DEFSET) == 0 && 13588fae3551SRodney W. Grimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 13598fae3551SRodney W. Grimes hp = dp->dp_hosts; 13608fae3551SRodney W. Grimes while (hp) { 13618fae3551SRodney W. Grimes grp = hp->ht_grp; 13628fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 13638fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 13648fae3551SRodney W. Grimes return (1); 13658360efbdSAlfred Perlstein strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 13668fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 13670775314bSDoug Rabson MNTNAMLEN)) 13688fae3551SRodney W. Grimes return (1); 13698fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 13708fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 13718fae3551SRodney W. Grimes return (1); 13728fae3551SRodney W. Grimes strp = grp->gr_ptr.gt_net.nt_name; 13738fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 13740775314bSDoug Rabson MNTNAMLEN)) 13758fae3551SRodney W. Grimes return (1); 13768fae3551SRodney W. Grimes } 13778fae3551SRodney W. Grimes hp = hp->ht_next; 13788fae3551SRodney W. Grimes if (gotalldir && hp == (struct hostlist *)NULL) { 13798fae3551SRodney W. Grimes hp = adp->dp_hosts; 13808fae3551SRodney W. Grimes gotalldir = 0; 13818fae3551SRodney W. Grimes } 13828fae3551SRodney W. Grimes } 13838fae3551SRodney W. Grimes } 13848fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 13858fae3551SRodney W. Grimes return (1); 138691acb349SAlfred Perlstein if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 13878fae3551SRodney W. Grimes return (1); 13888fae3551SRodney W. Grimes } 13898fae3551SRodney W. Grimes return (0); 13908fae3551SRodney W. Grimes } 13918fae3551SRodney W. Grimes 139219c46d8cSEdward Tomasz Napierala static int 1393a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp) 139491acb349SAlfred Perlstein { 139591acb349SAlfred Perlstein 139691acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 0); 139791acb349SAlfred Perlstein } 139891acb349SAlfred Perlstein 139919c46d8cSEdward Tomasz Napierala static int 1400a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp) 140191acb349SAlfred Perlstein { 140291acb349SAlfred Perlstein 140391acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 1); 140491acb349SAlfred Perlstein } 140591acb349SAlfred Perlstein 140619c46d8cSEdward Tomasz Napierala static char *line; 140719c46d8cSEdward Tomasz Napierala static size_t linesize; 140819c46d8cSEdward Tomasz Napierala static FILE *exp_file; 14098fae3551SRodney W. Grimes 14108fae3551SRodney W. Grimes /* 141196968c22SPawel Jakub Dawidek * Get the export list from one, currently open file 14128fae3551SRodney W. Grimes */ 141396968c22SPawel Jakub Dawidek static void 1414a7a7d96cSPhilippe Charnier get_exportlist_one(void) 14158fae3551SRodney W. Grimes { 1416c9ac0f71SEmmanuel Vadot struct exportlist *ep; 14178fae3551SRodney W. Grimes struct grouplist *grp, *tgrp; 14188fae3551SRodney W. Grimes struct dirlist *dirhead; 141996968c22SPawel Jakub Dawidek struct statfs fsb; 1420c0511d3bSBrian Feldman struct xucred anon; 14218fae3551SRodney W. Grimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 142296968c22SPawel Jakub Dawidek int len, has_host, exflags, got_nondir, dirplen, netgrp; 14238fae3551SRodney W. Grimes 1424bcc1d071SRick Macklem v4root_phase = 0; 14258fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 14268fae3551SRodney W. Grimes while (get_line()) { 14278fae3551SRodney W. Grimes if (debug) 142874853402SPhilippe Charnier warnx("got line %s", line); 14298fae3551SRodney W. Grimes cp = line; 14308fae3551SRodney W. Grimes nextfield(&cp, &endcp); 14318fae3551SRodney W. Grimes if (*cp == '#') 14328fae3551SRodney W. Grimes goto nextline; 14338fae3551SRodney W. Grimes 14348fae3551SRodney W. Grimes /* 14358fae3551SRodney W. Grimes * Set defaults. 14368fae3551SRodney W. Grimes */ 14378fae3551SRodney W. Grimes has_host = FALSE; 14388fae3551SRodney W. Grimes anon = def_anon; 14398fae3551SRodney W. Grimes exflags = MNT_EXPORTED; 14408fae3551SRodney W. Grimes got_nondir = 0; 14418fae3551SRodney W. Grimes opt_flags = 0; 14428fae3551SRodney W. Grimes ep = (struct exportlist *)NULL; 1443bcc1d071SRick Macklem dirp = NULL; 1444bcc1d071SRick Macklem 1445bcc1d071SRick Macklem /* 1446bcc1d071SRick Macklem * Handle the V4 root dir. 1447bcc1d071SRick Macklem */ 1448bcc1d071SRick Macklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1449bcc1d071SRick Macklem /* 1450bcc1d071SRick Macklem * V4: just indicates that it is the v4 root point, 1451bcc1d071SRick Macklem * so skip over that and set v4root_phase. 1452bcc1d071SRick Macklem */ 1453bcc1d071SRick Macklem if (v4root_phase > 0) { 1454bcc1d071SRick Macklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1455bcc1d071SRick Macklem goto nextline; 1456bcc1d071SRick Macklem } 1457bcc1d071SRick Macklem v4root_phase = 1; 1458bcc1d071SRick Macklem cp += 3; 1459bcc1d071SRick Macklem nextfield(&cp, &endcp); 1460bcc1d071SRick Macklem } 14618fae3551SRodney W. Grimes 14628fae3551SRodney W. Grimes /* 14638fae3551SRodney W. Grimes * Create new exports list entry 14648fae3551SRodney W. Grimes */ 14658fae3551SRodney W. Grimes len = endcp-cp; 14668fae3551SRodney W. Grimes tgrp = grp = get_grp(); 14678fae3551SRodney W. Grimes while (len > 0) { 14680775314bSDoug Rabson if (len > MNTNAMLEN) { 1469354fce28SConrad Meyer getexp_err(ep, tgrp, "mountpoint too long"); 14708fae3551SRodney W. Grimes goto nextline; 14718fae3551SRodney W. Grimes } 14728fae3551SRodney W. Grimes if (*cp == '-') { 14738fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1474354fce28SConrad Meyer getexp_err(ep, tgrp, 1475354fce28SConrad Meyer "flag before export path definition"); 14768fae3551SRodney W. Grimes goto nextline; 14778fae3551SRodney W. Grimes } 14788fae3551SRodney W. Grimes if (debug) 147974853402SPhilippe Charnier warnx("doing opt %s", cp); 14808fae3551SRodney W. Grimes got_nondir = 1; 14818fae3551SRodney W. Grimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 14828fae3551SRodney W. Grimes &exflags, &anon)) { 1483354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 14848fae3551SRodney W. Grimes goto nextline; 14858fae3551SRodney W. Grimes } 14868fae3551SRodney W. Grimes } else if (*cp == '/') { 14878fae3551SRodney W. Grimes savedc = *endcp; 14888fae3551SRodney W. Grimes *endcp = '\0'; 1489bcc1d071SRick Macklem if (v4root_phase > 1) { 1490bcc1d071SRick Macklem if (dirp != NULL) { 1491354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1492bcc1d071SRick Macklem goto nextline; 1493bcc1d071SRick Macklem } 1494bcc1d071SRick Macklem } 14958fae3551SRodney W. Grimes if (check_dirpath(cp) && 14968fae3551SRodney W. Grimes statfs(cp, &fsb) >= 0) { 14979896584aSRick Macklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 14989896584aSRick Macklem syslog(LOG_ERR, "Warning: exporting of " 14999896584aSRick Macklem "automounted fs %s not supported", cp); 15008fae3551SRodney W. Grimes if (got_nondir) { 1501354fce28SConrad Meyer getexp_err(ep, tgrp, "dirs must be first"); 15028fae3551SRodney W. Grimes goto nextline; 15038fae3551SRodney W. Grimes } 1504bcc1d071SRick Macklem if (v4root_phase == 1) { 1505bcc1d071SRick Macklem if (dirp != NULL) { 1506354fce28SConrad Meyer getexp_err(ep, tgrp, "Multiple V4 dirs"); 1507bcc1d071SRick Macklem goto nextline; 1508bcc1d071SRick Macklem } 1509bcc1d071SRick Macklem if (strlen(v4root_dirpath) == 0) { 1510bcc1d071SRick Macklem strlcpy(v4root_dirpath, cp, 1511bcc1d071SRick Macklem sizeof (v4root_dirpath)); 1512bcc1d071SRick Macklem } else if (strcmp(v4root_dirpath, cp) 1513bcc1d071SRick Macklem != 0) { 1514bcc1d071SRick Macklem syslog(LOG_ERR, 1515bcc1d071SRick Macklem "different V4 dirpath %s", cp); 1516354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 1517bcc1d071SRick Macklem goto nextline; 1518bcc1d071SRick Macklem } 1519bcc1d071SRick Macklem dirp = cp; 1520bcc1d071SRick Macklem v4root_phase = 2; 1521bcc1d071SRick Macklem got_nondir = 1; 1522bcc1d071SRick Macklem ep = get_exp(); 1523bcc1d071SRick Macklem } else { 15248fae3551SRodney W. Grimes if (ep) { 1525bcc1d071SRick Macklem if (ep->ex_fs.val[0] != 1526bcc1d071SRick Macklem fsb.f_fsid.val[0] || 1527bcc1d071SRick Macklem ep->ex_fs.val[1] != 1528bcc1d071SRick Macklem fsb.f_fsid.val[1]) { 1529354fce28SConrad Meyer getexp_err(ep, tgrp, 1530354fce28SConrad Meyer "fsid mismatch"); 15318fae3551SRodney W. Grimes goto nextline; 15328fae3551SRodney W. Grimes } 15338fae3551SRodney W. Grimes } else { 15348fae3551SRodney W. Grimes /* 15358fae3551SRodney W. Grimes * See if this directory is already 15368fae3551SRodney W. Grimes * in the list. 15378fae3551SRodney W. Grimes */ 15388fae3551SRodney W. Grimes ep = ex_search(&fsb.f_fsid); 15398fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 15408fae3551SRodney W. Grimes ep = get_exp(); 15418fae3551SRodney W. Grimes ep->ex_fs = fsb.f_fsid; 1542380a3fcdSEmmanuel Vadot ep->ex_fsdir = strdup(fsb.f_mntonname); 1543380a3fcdSEmmanuel Vadot if (ep->ex_fsdir == NULL) 15448fae3551SRodney W. Grimes out_of_mem(); 15458fae3551SRodney W. Grimes if (debug) 1546bcc1d071SRick Macklem warnx( 1547bcc1d071SRick Macklem "making new ep fs=0x%x,0x%x", 15488fae3551SRodney W. Grimes fsb.f_fsid.val[0], 15498fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 15508fae3551SRodney W. Grimes } else if (debug) 155174853402SPhilippe Charnier warnx("found ep fs=0x%x,0x%x", 15528fae3551SRodney W. Grimes fsb.f_fsid.val[0], 15538fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 15548fae3551SRodney W. Grimes } 15558fae3551SRodney W. Grimes 15568fae3551SRodney W. Grimes /* 15578fae3551SRodney W. Grimes * Add dirpath to export mount point. 15588fae3551SRodney W. Grimes */ 15598fae3551SRodney W. Grimes dirp = add_expdir(&dirhead, cp, len); 15608fae3551SRodney W. Grimes dirplen = len; 1561bcc1d071SRick Macklem } 15628fae3551SRodney W. Grimes } else { 1563354fce28SConrad Meyer getexp_err(ep, tgrp, 1564354fce28SConrad Meyer "symbolic link in export path or statfs failed"); 15658fae3551SRodney W. Grimes goto nextline; 15668fae3551SRodney W. Grimes } 15678fae3551SRodney W. Grimes *endcp = savedc; 15688fae3551SRodney W. Grimes } else { 15698fae3551SRodney W. Grimes savedc = *endcp; 15708fae3551SRodney W. Grimes *endcp = '\0'; 15718fae3551SRodney W. Grimes got_nondir = 1; 15728fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 1573354fce28SConrad Meyer getexp_err(ep, tgrp, 1574354fce28SConrad Meyer "host(s) before export path definition"); 15758fae3551SRodney W. Grimes goto nextline; 15768fae3551SRodney W. Grimes } 15778fae3551SRodney W. Grimes 15788fae3551SRodney W. Grimes /* 15798fae3551SRodney W. Grimes * Get the host or netgroup. 15808fae3551SRodney W. Grimes */ 15818fae3551SRodney W. Grimes setnetgrent(cp); 15828fae3551SRodney W. Grimes netgrp = getnetgrent(&hst, &usr, &dom); 15838fae3551SRodney W. Grimes do { 15848fae3551SRodney W. Grimes if (has_host) { 15858fae3551SRodney W. Grimes grp->gr_next = get_grp(); 15868fae3551SRodney W. Grimes grp = grp->gr_next; 15878fae3551SRodney W. Grimes } 15888fae3551SRodney W. Grimes if (netgrp) { 15899d70a156SJoerg Wunsch if (hst == 0) { 159074853402SPhilippe Charnier syslog(LOG_ERR, 159174853402SPhilippe Charnier "null hostname in netgroup %s, skipping", cp); 159201d48801SJoerg Wunsch grp->gr_type = GT_IGNORE; 15939d70a156SJoerg Wunsch } else if (get_host(hst, grp, tgrp)) { 159474853402SPhilippe Charnier syslog(LOG_ERR, 159574853402SPhilippe Charnier "bad host %s in netgroup %s, skipping", hst, cp); 1596a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 15978fae3551SRodney W. Grimes } 15988b5a6d67SBill Paul } else if (get_host(cp, grp, tgrp)) { 159974853402SPhilippe Charnier syslog(LOG_ERR, "bad host %s, skipping", cp); 1600a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 16018fae3551SRodney W. Grimes } 16028fae3551SRodney W. Grimes has_host = TRUE; 16038fae3551SRodney W. Grimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 16048fae3551SRodney W. Grimes endnetgrent(); 16058fae3551SRodney W. Grimes *endcp = savedc; 16068fae3551SRodney W. Grimes } 16078fae3551SRodney W. Grimes cp = endcp; 16088fae3551SRodney W. Grimes nextfield(&cp, &endcp); 16098fae3551SRodney W. Grimes len = endcp - cp; 16108fae3551SRodney W. Grimes } 16118fae3551SRodney W. Grimes if (check_options(dirhead)) { 1612354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 16138fae3551SRodney W. Grimes goto nextline; 16148fae3551SRodney W. Grimes } 16158fae3551SRodney W. Grimes if (!has_host) { 16166d359f31SIan Dowse grp->gr_type = GT_DEFAULT; 16178fae3551SRodney W. Grimes if (debug) 161874853402SPhilippe Charnier warnx("adding a default entry"); 16198fae3551SRodney W. Grimes 16208fae3551SRodney W. Grimes /* 16218fae3551SRodney W. Grimes * Don't allow a network export coincide with a list of 16228fae3551SRodney W. Grimes * host(s) on the same line. 16238fae3551SRodney W. Grimes */ 16248fae3551SRodney W. Grimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1625354fce28SConrad Meyer getexp_err(ep, tgrp, "network/host conflict"); 16268fae3551SRodney W. Grimes goto nextline; 1627a968cfd8SJonathan Lemon 1628a968cfd8SJonathan Lemon /* 1629a968cfd8SJonathan Lemon * If an export list was specified on this line, make sure 1630a968cfd8SJonathan Lemon * that we have at least one valid entry, otherwise skip it. 1631a968cfd8SJonathan Lemon */ 1632a968cfd8SJonathan Lemon } else { 1633a968cfd8SJonathan Lemon grp = tgrp; 1634a968cfd8SJonathan Lemon while (grp && grp->gr_type == GT_IGNORE) 1635a968cfd8SJonathan Lemon grp = grp->gr_next; 1636a968cfd8SJonathan Lemon if (! grp) { 1637354fce28SConrad Meyer getexp_err(ep, tgrp, "no valid entries"); 1638a968cfd8SJonathan Lemon goto nextline; 1639a968cfd8SJonathan Lemon } 16408fae3551SRodney W. Grimes } 16418fae3551SRodney W. Grimes 1642bcc1d071SRick Macklem if (v4root_phase == 1) { 1643354fce28SConrad Meyer getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); 1644bcc1d071SRick Macklem goto nextline; 1645bcc1d071SRick Macklem } 1646bcc1d071SRick Macklem 16478fae3551SRodney W. Grimes /* 16488fae3551SRodney W. Grimes * Loop through hosts, pushing the exports into the kernel. 16498fae3551SRodney W. Grimes * After loop, tgrp points to the start of the list and 16508fae3551SRodney W. Grimes * grp points to the last entry in the list. 16518fae3551SRodney W. Grimes */ 16528fae3551SRodney W. Grimes grp = tgrp; 16538fae3551SRodney W. Grimes do { 165401709abfSIan Dowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 165501709abfSIan Dowse &fsb)) { 1656354fce28SConrad Meyer getexp_err(ep, tgrp, NULL); 16578fae3551SRodney W. Grimes goto nextline; 16588fae3551SRodney W. Grimes } 16598fae3551SRodney W. Grimes } while (grp->gr_next && (grp = grp->gr_next)); 16608fae3551SRodney W. Grimes 16618fae3551SRodney W. Grimes /* 1662bcc1d071SRick Macklem * For V4: don't enter in mount lists. 1663bcc1d071SRick Macklem */ 166473f4ccbdSRick Macklem if (v4root_phase > 0 && v4root_phase <= 2) { 166573f4ccbdSRick Macklem /* 166673f4ccbdSRick Macklem * Since these structures aren't used by mountd, 166773f4ccbdSRick Macklem * free them up now. 166873f4ccbdSRick Macklem */ 166973f4ccbdSRick Macklem if (ep != NULL) 167073f4ccbdSRick Macklem free_exp(ep); 167173f4ccbdSRick Macklem while (tgrp != NULL) { 167273f4ccbdSRick Macklem grp = tgrp; 167373f4ccbdSRick Macklem tgrp = tgrp->gr_next; 167473f4ccbdSRick Macklem free_grp(grp); 167573f4ccbdSRick Macklem } 1676bcc1d071SRick Macklem goto nextline; 167773f4ccbdSRick Macklem } 1678bcc1d071SRick Macklem 1679bcc1d071SRick Macklem /* 16808fae3551SRodney W. Grimes * Success. Update the data structures. 16818fae3551SRodney W. Grimes */ 16828fae3551SRodney W. Grimes if (has_host) { 1683a62dc406SDoug Rabson hang_dirp(dirhead, tgrp, ep, opt_flags); 16848fae3551SRodney W. Grimes grp->gr_next = grphead; 16858fae3551SRodney W. Grimes grphead = tgrp; 16868fae3551SRodney W. Grimes } else { 16878fae3551SRodney W. Grimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1688a62dc406SDoug Rabson opt_flags); 16898fae3551SRodney W. Grimes free_grp(grp); 16908fae3551SRodney W. Grimes } 16918fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 16928fae3551SRodney W. Grimes if ((ep->ex_flag & EX_LINKED) == 0) { 1693c9ac0f71SEmmanuel Vadot SLIST_INSERT_HEAD(&exphead, ep, entries); 16948fae3551SRodney W. Grimes 16958fae3551SRodney W. Grimes ep->ex_flag |= EX_LINKED; 16968fae3551SRodney W. Grimes } 16978fae3551SRodney W. Grimes nextline: 1698bcc1d071SRick Macklem v4root_phase = 0; 16998fae3551SRodney W. Grimes if (dirhead) { 17008fae3551SRodney W. Grimes free_dir(dirhead); 17018fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 17028fae3551SRodney W. Grimes } 17038fae3551SRodney W. Grimes } 170496968c22SPawel Jakub Dawidek } 170596968c22SPawel Jakub Dawidek 170696968c22SPawel Jakub Dawidek /* 170796968c22SPawel Jakub Dawidek * Get the export list from all specified files 170896968c22SPawel Jakub Dawidek */ 170919c46d8cSEdward Tomasz Napierala static void 1710a7a7d96cSPhilippe Charnier get_exportlist(void) 171196968c22SPawel Jakub Dawidek { 171296968c22SPawel Jakub Dawidek struct exportlist *ep, *ep2; 171396968c22SPawel Jakub Dawidek struct grouplist *grp, *tgrp; 171496968c22SPawel Jakub Dawidek struct export_args export; 171596968c22SPawel Jakub Dawidek struct iovec *iov; 171696968c22SPawel Jakub Dawidek struct statfs *fsp, *mntbufp; 171796968c22SPawel Jakub Dawidek struct xvfsconf vfc; 171896968c22SPawel Jakub Dawidek char errmsg[255]; 1719e0bcf086SEitan Adler int num, i; 172096968c22SPawel Jakub Dawidek int iovlen; 17216c90092bSPawel Jakub Dawidek int done; 1722bcc1d071SRick Macklem struct nfsex_args eargs; 172396968c22SPawel Jakub Dawidek 1724c548eb5cSRick Macklem if (suspend_nfsd != 0) 1725c548eb5cSRick Macklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 1726bcc1d071SRick Macklem v4root_dirpath[0] = '\0'; 172796968c22SPawel Jakub Dawidek bzero(&export, sizeof(export)); 172896968c22SPawel Jakub Dawidek export.ex_flags = MNT_DELEXPORT; 172996968c22SPawel Jakub Dawidek iov = NULL; 173096968c22SPawel Jakub Dawidek iovlen = 0; 173196968c22SPawel Jakub Dawidek bzero(errmsg, sizeof(errmsg)); 173296968c22SPawel Jakub Dawidek 173396968c22SPawel Jakub Dawidek /* 173496968c22SPawel Jakub Dawidek * First, get rid of the old list 173596968c22SPawel Jakub Dawidek */ 1736c9ac0f71SEmmanuel Vadot SLIST_FOREACH_SAFE(ep, &exphead, entries, ep2) { 1737c9ac0f71SEmmanuel Vadot SLIST_REMOVE(&exphead, ep, exportlist, entries); 1738c9ac0f71SEmmanuel Vadot free_exp(ep); 173996968c22SPawel Jakub Dawidek } 174096968c22SPawel Jakub Dawidek 174196968c22SPawel Jakub Dawidek grp = grphead; 174296968c22SPawel Jakub Dawidek while (grp) { 174396968c22SPawel Jakub Dawidek tgrp = grp; 174496968c22SPawel Jakub Dawidek grp = grp->gr_next; 174596968c22SPawel Jakub Dawidek free_grp(tgrp); 174696968c22SPawel Jakub Dawidek } 174796968c22SPawel Jakub Dawidek grphead = (struct grouplist *)NULL; 174896968c22SPawel Jakub Dawidek 174996968c22SPawel Jakub Dawidek /* 1750bcc1d071SRick Macklem * and the old V4 root dir. 1751bcc1d071SRick Macklem */ 1752bcc1d071SRick Macklem bzero(&eargs, sizeof (eargs)); 1753bcc1d071SRick Macklem eargs.export.ex_flags = MNT_DELEXPORT; 175479b86807SEdward Tomasz Napierala if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1755bcc1d071SRick Macklem errno != ENOENT) 1756bcc1d071SRick Macklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1757bcc1d071SRick Macklem 1758bcc1d071SRick Macklem /* 1759bcc1d071SRick Macklem * and clear flag that notes if a public fh has been exported. 1760bcc1d071SRick Macklem */ 1761bcc1d071SRick Macklem has_publicfh = 0; 1762bcc1d071SRick Macklem 1763bcc1d071SRick Macklem /* 176496968c22SPawel Jakub Dawidek * And delete exports that are in the kernel for all local 176596968c22SPawel Jakub Dawidek * filesystems. 176696968c22SPawel Jakub Dawidek * XXX: Should know how to handle all local exportable filesystems. 176796968c22SPawel Jakub Dawidek */ 176896968c22SPawel Jakub Dawidek num = getmntinfo(&mntbufp, MNT_NOWAIT); 176996968c22SPawel Jakub Dawidek 177096968c22SPawel Jakub Dawidek if (num > 0) { 177196968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "fstype", NULL, 0); 177296968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "fspath", NULL, 0); 177396968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "from", NULL, 0); 177496968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "update", NULL, 0); 177596968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 177696968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 177796968c22SPawel Jakub Dawidek } 177896968c22SPawel Jakub Dawidek 177996968c22SPawel Jakub Dawidek for (i = 0; i < num; i++) { 178096968c22SPawel Jakub Dawidek fsp = &mntbufp[i]; 178196968c22SPawel Jakub Dawidek if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 178296968c22SPawel Jakub Dawidek syslog(LOG_ERR, "getvfsbyname() failed for %s", 178396968c22SPawel Jakub Dawidek fsp->f_fstypename); 178496968c22SPawel Jakub Dawidek continue; 178596968c22SPawel Jakub Dawidek } 178696968c22SPawel Jakub Dawidek 178796968c22SPawel Jakub Dawidek /* 17882ef26470SSimon J. Gerraty * We do not need to delete "export" flag from 17892ef26470SSimon J. Gerraty * filesystems that do not have it set. 17902ef26470SSimon J. Gerraty */ 17912ef26470SSimon J. Gerraty if (!(fsp->f_flags & MNT_EXPORTED)) 17922ef26470SSimon J. Gerraty continue; 17932ef26470SSimon J. Gerraty /* 179496968c22SPawel Jakub Dawidek * Do not delete export for network filesystem by 179596968c22SPawel Jakub Dawidek * passing "export" arg to nmount(). 179696968c22SPawel Jakub Dawidek * It only makes sense to do this for local filesystems. 179796968c22SPawel Jakub Dawidek */ 179896968c22SPawel Jakub Dawidek if (vfc.vfc_flags & VFCF_NETWORK) 179996968c22SPawel Jakub Dawidek continue; 180096968c22SPawel Jakub Dawidek 180196968c22SPawel Jakub Dawidek iov[1].iov_base = fsp->f_fstypename; 180296968c22SPawel Jakub Dawidek iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 180396968c22SPawel Jakub Dawidek iov[3].iov_base = fsp->f_mntonname; 180496968c22SPawel Jakub Dawidek iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 180596968c22SPawel Jakub Dawidek iov[5].iov_base = fsp->f_mntfromname; 180696968c22SPawel Jakub Dawidek iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 18074a185fa6SBryan Drewery errmsg[0] = '\0'; 180896968c22SPawel Jakub Dawidek 18095d6f5b24SKonstantin Belousov /* 18105d6f5b24SKonstantin Belousov * EXDEV is returned when path exists but is not a 18115d6f5b24SKonstantin Belousov * mount point. May happens if raced with unmount. 18125d6f5b24SKonstantin Belousov */ 181396968c22SPawel Jakub Dawidek if (nmount(iov, iovlen, fsp->f_flags) < 0 && 18145d6f5b24SKonstantin Belousov errno != ENOENT && errno != ENOTSUP && errno != EXDEV) { 181596968c22SPawel Jakub Dawidek syslog(LOG_ERR, 181696968c22SPawel Jakub Dawidek "can't delete exports for %s: %m %s", 181796968c22SPawel Jakub Dawidek fsp->f_mntonname, errmsg); 181896968c22SPawel Jakub Dawidek } 181996968c22SPawel Jakub Dawidek } 182096968c22SPawel Jakub Dawidek 182196968c22SPawel Jakub Dawidek if (iov != NULL) { 182296968c22SPawel Jakub Dawidek /* Free strings allocated by strdup() in getmntopts.c */ 182396968c22SPawel Jakub Dawidek free(iov[0].iov_base); /* fstype */ 182496968c22SPawel Jakub Dawidek free(iov[2].iov_base); /* fspath */ 182596968c22SPawel Jakub Dawidek free(iov[4].iov_base); /* from */ 182696968c22SPawel Jakub Dawidek free(iov[6].iov_base); /* update */ 182796968c22SPawel Jakub Dawidek free(iov[8].iov_base); /* export */ 182896968c22SPawel Jakub Dawidek free(iov[10].iov_base); /* errmsg */ 182996968c22SPawel Jakub Dawidek 183096968c22SPawel Jakub Dawidek /* free iov, allocated by realloc() */ 183196968c22SPawel Jakub Dawidek free(iov); 183296968c22SPawel Jakub Dawidek iovlen = 0; 183396968c22SPawel Jakub Dawidek } 183496968c22SPawel Jakub Dawidek 183596968c22SPawel Jakub Dawidek /* 183696968c22SPawel Jakub Dawidek * Read in the exports file and build the list, calling 183796968c22SPawel Jakub Dawidek * nmount() as we go along to push the export rules into the kernel. 183896968c22SPawel Jakub Dawidek */ 18396c90092bSPawel Jakub Dawidek done = 0; 184096968c22SPawel Jakub Dawidek for (i = 0; exnames[i] != NULL; i++) { 184196968c22SPawel Jakub Dawidek if (debug) 184296968c22SPawel Jakub Dawidek warnx("reading exports from %s", exnames[i]); 184396968c22SPawel Jakub Dawidek if ((exp_file = fopen(exnames[i], "r")) == NULL) { 18446c90092bSPawel Jakub Dawidek syslog(LOG_WARNING, "can't open %s", exnames[i]); 18456c90092bSPawel Jakub Dawidek continue; 184696968c22SPawel Jakub Dawidek } 184796968c22SPawel Jakub Dawidek get_exportlist_one(); 18488fae3551SRodney W. Grimes fclose(exp_file); 18496c90092bSPawel Jakub Dawidek done++; 18506c90092bSPawel Jakub Dawidek } 18516c90092bSPawel Jakub Dawidek if (done == 0) { 18526c90092bSPawel Jakub Dawidek syslog(LOG_ERR, "can't open any exports file"); 18536c90092bSPawel Jakub Dawidek exit(2); 18548fae3551SRodney W. Grimes } 1855bcc1d071SRick Macklem 1856bcc1d071SRick Macklem /* 1857bcc1d071SRick Macklem * If there was no public fh, clear any previous one set. 1858bcc1d071SRick Macklem */ 185979b86807SEdward Tomasz Napierala if (has_publicfh == 0) 1860bcc1d071SRick Macklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1861c548eb5cSRick Macklem 1862c548eb5cSRick Macklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1863c548eb5cSRick Macklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 186496968c22SPawel Jakub Dawidek } 18658fae3551SRodney W. Grimes 18668fae3551SRodney W. Grimes /* 18678fae3551SRodney W. Grimes * Allocate an export list element 18688fae3551SRodney W. Grimes */ 186919c46d8cSEdward Tomasz Napierala static struct exportlist * 1870a7a7d96cSPhilippe Charnier get_exp(void) 18718fae3551SRodney W. Grimes { 18728fae3551SRodney W. Grimes struct exportlist *ep; 18738fae3551SRodney W. Grimes 187453750151SXin LI ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 18758fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) 18768fae3551SRodney W. Grimes out_of_mem(); 18778fae3551SRodney W. Grimes return (ep); 18788fae3551SRodney W. Grimes } 18798fae3551SRodney W. Grimes 18808fae3551SRodney W. Grimes /* 18818fae3551SRodney W. Grimes * Allocate a group list element 18828fae3551SRodney W. Grimes */ 188319c46d8cSEdward Tomasz Napierala static struct grouplist * 1884a7a7d96cSPhilippe Charnier get_grp(void) 18858fae3551SRodney W. Grimes { 18868fae3551SRodney W. Grimes struct grouplist *gp; 18878fae3551SRodney W. Grimes 188853750151SXin LI gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 18898fae3551SRodney W. Grimes if (gp == (struct grouplist *)NULL) 18908fae3551SRodney W. Grimes out_of_mem(); 18918fae3551SRodney W. Grimes return (gp); 18928fae3551SRodney W. Grimes } 18938fae3551SRodney W. Grimes 18948fae3551SRodney W. Grimes /* 18958fae3551SRodney W. Grimes * Clean up upon an error in get_exportlist(). 18968fae3551SRodney W. Grimes */ 189719c46d8cSEdward Tomasz Napierala static void 1898354fce28SConrad Meyer getexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason) 18998fae3551SRodney W. Grimes { 19008fae3551SRodney W. Grimes struct grouplist *tgrp; 19018fae3551SRodney W. Grimes 1902354fce28SConrad Meyer if (!(opt_flags & OP_QUIET)) { 1903354fce28SConrad Meyer if (reason != NULL) 1904354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s': %s", line, 1905354fce28SConrad Meyer reason); 1906354fce28SConrad Meyer else 1907354fce28SConrad Meyer syslog(LOG_ERR, "bad exports list line '%s'", line); 1908354fce28SConrad Meyer } 19098fae3551SRodney W. Grimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 19108fae3551SRodney W. Grimes free_exp(ep); 19118fae3551SRodney W. Grimes while (grp) { 19128fae3551SRodney W. Grimes tgrp = grp; 19138fae3551SRodney W. Grimes grp = grp->gr_next; 19148fae3551SRodney W. Grimes free_grp(tgrp); 19158fae3551SRodney W. Grimes } 19168fae3551SRodney W. Grimes } 19178fae3551SRodney W. Grimes 19188fae3551SRodney W. Grimes /* 19198fae3551SRodney W. Grimes * Search the export list for a matching fs. 19208fae3551SRodney W. Grimes */ 192119c46d8cSEdward Tomasz Napierala static struct exportlist * 1922a7a7d96cSPhilippe Charnier ex_search(fsid_t *fsid) 19238fae3551SRodney W. Grimes { 19248fae3551SRodney W. Grimes struct exportlist *ep; 19258fae3551SRodney W. Grimes 1926c9ac0f71SEmmanuel Vadot SLIST_FOREACH(ep, &exphead, entries) { 19278fae3551SRodney W. Grimes if (ep->ex_fs.val[0] == fsid->val[0] && 19288fae3551SRodney W. Grimes ep->ex_fs.val[1] == fsid->val[1]) 19298fae3551SRodney W. Grimes return (ep); 19308fae3551SRodney W. Grimes } 1931c9ac0f71SEmmanuel Vadot 19328fae3551SRodney W. Grimes return (ep); 19338fae3551SRodney W. Grimes } 19348fae3551SRodney W. Grimes 19358fae3551SRodney W. Grimes /* 19368fae3551SRodney W. Grimes * Add a directory path to the list. 19378fae3551SRodney W. Grimes */ 193819c46d8cSEdward Tomasz Napierala static char * 1939a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len) 19408fae3551SRodney W. Grimes { 19418fae3551SRodney W. Grimes struct dirlist *dp; 19428fae3551SRodney W. Grimes 194389b859e3SEmmanuel Vadot dp = malloc(sizeof (struct dirlist)); 194474853402SPhilippe Charnier if (dp == (struct dirlist *)NULL) 194574853402SPhilippe Charnier out_of_mem(); 19468fae3551SRodney W. Grimes dp->dp_left = *dpp; 19478fae3551SRodney W. Grimes dp->dp_right = (struct dirlist *)NULL; 19488fae3551SRodney W. Grimes dp->dp_flag = 0; 19498fae3551SRodney W. Grimes dp->dp_hosts = (struct hostlist *)NULL; 1950380a3fcdSEmmanuel Vadot dp->dp_dirp = strndup(cp, len); 1951380a3fcdSEmmanuel Vadot if (dp->dp_dirp == NULL) 1952380a3fcdSEmmanuel Vadot out_of_mem(); 19538fae3551SRodney W. Grimes *dpp = dp; 19548fae3551SRodney W. Grimes return (dp->dp_dirp); 19558fae3551SRodney W. Grimes } 19568fae3551SRodney W. Grimes 19578fae3551SRodney W. Grimes /* 19588fae3551SRodney W. Grimes * Hang the dir list element off the dirpath binary tree as required 19598fae3551SRodney W. Grimes * and update the entry for host. 19608fae3551SRodney W. Grimes */ 196119c46d8cSEdward Tomasz Napierala static void 1962a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1963a7a7d96cSPhilippe Charnier int flags) 19648fae3551SRodney W. Grimes { 19658fae3551SRodney W. Grimes struct hostlist *hp; 19668fae3551SRodney W. Grimes struct dirlist *dp2; 19678fae3551SRodney W. Grimes 1968a62dc406SDoug Rabson if (flags & OP_ALLDIRS) { 19698fae3551SRodney W. Grimes if (ep->ex_defdir) 19708fae3551SRodney W. Grimes free((caddr_t)dp); 19718fae3551SRodney W. Grimes else 19728fae3551SRodney W. Grimes ep->ex_defdir = dp; 1973a62dc406SDoug Rabson if (grp == (struct grouplist *)NULL) { 19748fae3551SRodney W. Grimes ep->ex_defdir->dp_flag |= DP_DEFSET; 1975c3f86a25SRick Macklem /* Save the default security flavors list. */ 1976c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 1977c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 1978c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 1979c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 1980a62dc406SDoug Rabson } else while (grp) { 19818fae3551SRodney W. Grimes hp = get_ht(); 19828fae3551SRodney W. Grimes hp->ht_grp = grp; 19838fae3551SRodney W. Grimes hp->ht_next = ep->ex_defdir->dp_hosts; 19848fae3551SRodney W. Grimes ep->ex_defdir->dp_hosts = hp; 1985c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 1986c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 1987c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 1988c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 1989c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 19908fae3551SRodney W. Grimes grp = grp->gr_next; 19918fae3551SRodney W. Grimes } 19928fae3551SRodney W. Grimes } else { 19938fae3551SRodney W. Grimes 19948fae3551SRodney W. Grimes /* 199574853402SPhilippe Charnier * Loop through the directories adding them to the tree. 19968fae3551SRodney W. Grimes */ 19978fae3551SRodney W. Grimes while (dp) { 19988fae3551SRodney W. Grimes dp2 = dp->dp_left; 1999c3f86a25SRick Macklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep); 20008fae3551SRodney W. Grimes dp = dp2; 20018fae3551SRodney W. Grimes } 20028fae3551SRodney W. Grimes } 20038fae3551SRodney W. Grimes } 20048fae3551SRodney W. Grimes 20058fae3551SRodney W. Grimes /* 20068fae3551SRodney W. Grimes * Traverse the binary tree either updating a node that is already there 20078fae3551SRodney W. Grimes * for the new directory or adding the new node. 20088fae3551SRodney W. Grimes */ 200919c46d8cSEdward Tomasz Napierala static void 2010a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2011c3f86a25SRick Macklem int flags, struct exportlist *ep) 20128fae3551SRodney W. Grimes { 20138fae3551SRodney W. Grimes struct dirlist *dp; 20148fae3551SRodney W. Grimes struct hostlist *hp; 20158fae3551SRodney W. Grimes int cmp; 20168fae3551SRodney W. Grimes 20178fae3551SRodney W. Grimes dp = *dpp; 20188fae3551SRodney W. Grimes if (dp) { 20198fae3551SRodney W. Grimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 20208fae3551SRodney W. Grimes if (cmp > 0) { 2021c3f86a25SRick Macklem add_dlist(&dp->dp_left, newdp, grp, flags, ep); 20228fae3551SRodney W. Grimes return; 20238fae3551SRodney W. Grimes } else if (cmp < 0) { 2024c3f86a25SRick Macklem add_dlist(&dp->dp_right, newdp, grp, flags, ep); 20258fae3551SRodney W. Grimes return; 20268fae3551SRodney W. Grimes } else 20278fae3551SRodney W. Grimes free((caddr_t)newdp); 20288fae3551SRodney W. Grimes } else { 20298fae3551SRodney W. Grimes dp = newdp; 20308fae3551SRodney W. Grimes dp->dp_left = (struct dirlist *)NULL; 20318fae3551SRodney W. Grimes *dpp = dp; 20328fae3551SRodney W. Grimes } 20338fae3551SRodney W. Grimes if (grp) { 20348fae3551SRodney W. Grimes 20358fae3551SRodney W. Grimes /* 20368fae3551SRodney W. Grimes * Hang all of the host(s) off of the directory point. 20378fae3551SRodney W. Grimes */ 20388fae3551SRodney W. Grimes do { 20398fae3551SRodney W. Grimes hp = get_ht(); 20408fae3551SRodney W. Grimes hp->ht_grp = grp; 20418fae3551SRodney W. Grimes hp->ht_next = dp->dp_hosts; 20428fae3551SRodney W. Grimes dp->dp_hosts = hp; 2043c3f86a25SRick Macklem /* Save the security flavors list for this host set. */ 2044c3f86a25SRick Macklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2045c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2046c3f86a25SRick Macklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2047c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 20488fae3551SRodney W. Grimes grp = grp->gr_next; 20498fae3551SRodney W. Grimes } while (grp); 2050a62dc406SDoug Rabson } else { 20518fae3551SRodney W. Grimes dp->dp_flag |= DP_DEFSET; 2052c3f86a25SRick Macklem /* Save the default security flavors list. */ 2053c3f86a25SRick Macklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2054c3f86a25SRick Macklem if (ep->ex_numsecflavors > 0) 2055c3f86a25SRick Macklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2056c3f86a25SRick Macklem sizeof(ep->ex_secflavors)); 2057a62dc406SDoug Rabson } 20588fae3551SRodney W. Grimes } 20598fae3551SRodney W. Grimes 20608fae3551SRodney W. Grimes /* 20618fae3551SRodney W. Grimes * Search for a dirpath on the export point. 20628fae3551SRodney W. Grimes */ 206319c46d8cSEdward Tomasz Napierala static struct dirlist * 2064a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp) 20658fae3551SRodney W. Grimes { 20668fae3551SRodney W. Grimes int cmp; 20678fae3551SRodney W. Grimes 20688fae3551SRodney W. Grimes if (dp) { 20698360efbdSAlfred Perlstein cmp = strcmp(dp->dp_dirp, dirp); 20708fae3551SRodney W. Grimes if (cmp > 0) 20718360efbdSAlfred Perlstein return (dirp_search(dp->dp_left, dirp)); 20728fae3551SRodney W. Grimes else if (cmp < 0) 20738360efbdSAlfred Perlstein return (dirp_search(dp->dp_right, dirp)); 20748fae3551SRodney W. Grimes else 20758fae3551SRodney W. Grimes return (dp); 20768fae3551SRodney W. Grimes } 20778fae3551SRodney W. Grimes return (dp); 20788fae3551SRodney W. Grimes } 20798fae3551SRodney W. Grimes 20808fae3551SRodney W. Grimes /* 20818fae3551SRodney W. Grimes * Scan for a host match in a directory tree. 20828fae3551SRodney W. Grimes */ 208319c46d8cSEdward Tomasz Napierala static int 2084a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2085c3f86a25SRick Macklem int *hostsetp, int *numsecflavors, int **secflavorsp) 20868fae3551SRodney W. Grimes { 20878fae3551SRodney W. Grimes struct hostlist *hp; 20888fae3551SRodney W. Grimes struct grouplist *grp; 20898360efbdSAlfred Perlstein struct addrinfo *ai; 20908fae3551SRodney W. Grimes 20918fae3551SRodney W. Grimes if (dp) { 20928fae3551SRodney W. Grimes if (dp->dp_flag & DP_DEFSET) 2093a62dc406SDoug Rabson *defsetp = dp->dp_flag; 20948fae3551SRodney W. Grimes hp = dp->dp_hosts; 20958fae3551SRodney W. Grimes while (hp) { 20968fae3551SRodney W. Grimes grp = hp->ht_grp; 20978fae3551SRodney W. Grimes switch (grp->gr_type) { 20988fae3551SRodney W. Grimes case GT_HOST: 20998360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 21008360efbdSAlfred Perlstein for (; ai; ai = ai->ai_next) { 210160caaee2SIan Dowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 21028360efbdSAlfred Perlstein *hostsetp = 21038360efbdSAlfred Perlstein (hp->ht_flag | DP_HOSTSET); 2104c3f86a25SRick Macklem if (numsecflavors != NULL) { 2105c3f86a25SRick Macklem *numsecflavors = 2106c3f86a25SRick Macklem grp->gr_numsecflavors; 2107c3f86a25SRick Macklem *secflavorsp = 2108c3f86a25SRick Macklem grp->gr_secflavors; 2109c3f86a25SRick Macklem } 21108fae3551SRodney W. Grimes return (1); 2111a62dc406SDoug Rabson } 21128fae3551SRodney W. Grimes } 21138fae3551SRodney W. Grimes break; 21148fae3551SRodney W. Grimes case GT_NET: 211560caaee2SIan Dowse if (!sacmp(saddr, (struct sockaddr *) 211660caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_net, 211760caaee2SIan Dowse (struct sockaddr *) 211860caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_mask)) { 2119a62dc406SDoug Rabson *hostsetp = (hp->ht_flag | DP_HOSTSET); 2120c3f86a25SRick Macklem if (numsecflavors != NULL) { 2121c3f86a25SRick Macklem *numsecflavors = 2122c3f86a25SRick Macklem grp->gr_numsecflavors; 2123c3f86a25SRick Macklem *secflavorsp = 2124c3f86a25SRick Macklem grp->gr_secflavors; 2125c3f86a25SRick Macklem } 21268fae3551SRodney W. Grimes return (1); 2127a62dc406SDoug Rabson } 21288fae3551SRodney W. Grimes break; 212960caaee2SIan Dowse } 21308fae3551SRodney W. Grimes hp = hp->ht_next; 21318fae3551SRodney W. Grimes } 21328fae3551SRodney W. Grimes } 21338fae3551SRodney W. Grimes return (0); 21348fae3551SRodney W. Grimes } 21358fae3551SRodney W. Grimes 21368fae3551SRodney W. Grimes /* 21378fae3551SRodney W. Grimes * Scan tree for a host that matches the address. 21388fae3551SRodney W. Grimes */ 213919c46d8cSEdward Tomasz Napierala static int 2140a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr) 21418fae3551SRodney W. Grimes { 2142a62dc406SDoug Rabson int defset, hostset; 21438fae3551SRodney W. Grimes 21448fae3551SRodney W. Grimes if (dp) { 21458fae3551SRodney W. Grimes if (scan_tree(dp->dp_left, saddr)) 21468fae3551SRodney W. Grimes return (1); 2147c3f86a25SRick Macklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 21488fae3551SRodney W. Grimes return (1); 21498fae3551SRodney W. Grimes if (scan_tree(dp->dp_right, saddr)) 21508fae3551SRodney W. Grimes return (1); 21518fae3551SRodney W. Grimes } 21528fae3551SRodney W. Grimes return (0); 21538fae3551SRodney W. Grimes } 21548fae3551SRodney W. Grimes 21558fae3551SRodney W. Grimes /* 21568fae3551SRodney W. Grimes * Traverse the dirlist tree and free it up. 21578fae3551SRodney W. Grimes */ 215819c46d8cSEdward Tomasz Napierala static void 2159a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp) 21608fae3551SRodney W. Grimes { 21618fae3551SRodney W. Grimes 21628fae3551SRodney W. Grimes if (dp) { 21638fae3551SRodney W. Grimes free_dir(dp->dp_left); 21648fae3551SRodney W. Grimes free_dir(dp->dp_right); 21658fae3551SRodney W. Grimes free_host(dp->dp_hosts); 216692e73cccSEmmanuel Vadot free(dp->dp_dirp); 216792e73cccSEmmanuel Vadot free(dp); 21688fae3551SRodney W. Grimes } 21698fae3551SRodney W. Grimes } 21708fae3551SRodney W. Grimes 21718fae3551SRodney W. Grimes /* 2172a9148abdSDoug Rabson * Parse a colon separated list of security flavors 2173a9148abdSDoug Rabson */ 217419c46d8cSEdward Tomasz Napierala static int 2175a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep) 2176a9148abdSDoug Rabson { 2177a9148abdSDoug Rabson char *cp, savedc; 2178a9148abdSDoug Rabson int flavor; 2179a9148abdSDoug Rabson 2180a9148abdSDoug Rabson ep->ex_numsecflavors = 0; 2181a9148abdSDoug Rabson for (;;) { 2182a9148abdSDoug Rabson cp = strchr(seclist, ':'); 2183a9148abdSDoug Rabson if (cp) { 2184a9148abdSDoug Rabson savedc = *cp; 2185a9148abdSDoug Rabson *cp = '\0'; 2186a9148abdSDoug Rabson } 2187a9148abdSDoug Rabson 2188a9148abdSDoug Rabson if (!strcmp(seclist, "sys")) 2189a9148abdSDoug Rabson flavor = AUTH_SYS; 2190a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5")) 2191a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5; 2192a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5i")) 2193a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5I; 2194a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5p")) 2195a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5P; 2196a9148abdSDoug Rabson else { 2197a9148abdSDoug Rabson if (cp) 2198a9148abdSDoug Rabson *cp = savedc; 2199a9148abdSDoug Rabson syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2200a9148abdSDoug Rabson return (1); 2201a9148abdSDoug Rabson } 2202a9148abdSDoug Rabson if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2203a9148abdSDoug Rabson if (cp) 2204a9148abdSDoug Rabson *cp = savedc; 2205a9148abdSDoug Rabson syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2206a9148abdSDoug Rabson return (1); 2207a9148abdSDoug Rabson } 2208a9148abdSDoug Rabson ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2209a9148abdSDoug Rabson ep->ex_numsecflavors++; 2210a9148abdSDoug Rabson if (cp) { 2211a9148abdSDoug Rabson *cp = savedc; 2212a9148abdSDoug Rabson seclist = cp + 1; 2213a9148abdSDoug Rabson } else { 2214a9148abdSDoug Rabson break; 2215a9148abdSDoug Rabson } 2216a9148abdSDoug Rabson } 2217a9148abdSDoug Rabson return (0); 2218a9148abdSDoug Rabson } 2219a9148abdSDoug Rabson 2220a9148abdSDoug Rabson /* 22218fae3551SRodney W. Grimes * Parse the option string and update fields. 22228fae3551SRodney W. Grimes * Option arguments may either be -<option>=<value> or 22238fae3551SRodney W. Grimes * -<option> <value> 22248fae3551SRodney W. Grimes */ 222519c46d8cSEdward Tomasz Napierala static int 2226a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2227a7a7d96cSPhilippe Charnier int *has_hostp, int *exflagsp, struct xucred *cr) 22288fae3551SRodney W. Grimes { 22298fae3551SRodney W. Grimes char *cpoptarg, *cpoptend; 22308fae3551SRodney W. Grimes char *cp, *endcp, *cpopt, savedc, savedc2; 22318fae3551SRodney W. Grimes int allflag, usedarg; 22328fae3551SRodney W. Grimes 2233cb479b11SAlfred Perlstein savedc2 = '\0'; 22348fae3551SRodney W. Grimes cpopt = *cpp; 22358fae3551SRodney W. Grimes cpopt++; 22368fae3551SRodney W. Grimes cp = *endcpp; 22378fae3551SRodney W. Grimes savedc = *cp; 22388fae3551SRodney W. Grimes *cp = '\0'; 22398fae3551SRodney W. Grimes while (cpopt && *cpopt) { 22408fae3551SRodney W. Grimes allflag = 1; 22418fae3551SRodney W. Grimes usedarg = -2; 224274853402SPhilippe Charnier if ((cpoptend = strchr(cpopt, ','))) { 22438fae3551SRodney W. Grimes *cpoptend++ = '\0'; 224474853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 22458fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 22468fae3551SRodney W. Grimes } else { 224774853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 22488fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 22498fae3551SRodney W. Grimes else { 22508fae3551SRodney W. Grimes *cp = savedc; 22518fae3551SRodney W. Grimes nextfield(&cp, &endcp); 22528fae3551SRodney W. Grimes **endcpp = '\0'; 22538fae3551SRodney W. Grimes if (endcp > cp && *cp != '-') { 22548fae3551SRodney W. Grimes cpoptarg = cp; 22558fae3551SRodney W. Grimes savedc2 = *endcp; 22568fae3551SRodney W. Grimes *endcp = '\0'; 22578fae3551SRodney W. Grimes usedarg = 0; 22588fae3551SRodney W. Grimes } 22598fae3551SRodney W. Grimes } 22608fae3551SRodney W. Grimes } 22618fae3551SRodney W. Grimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 22628fae3551SRodney W. Grimes *exflagsp |= MNT_EXRDONLY; 22638fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 22648fae3551SRodney W. Grimes !(allflag = strcmp(cpopt, "mapall")) || 22658fae3551SRodney W. Grimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 22668fae3551SRodney W. Grimes usedarg++; 22678fae3551SRodney W. Grimes parsecred(cpoptarg, cr); 22688fae3551SRodney W. Grimes if (allflag == 0) { 22698fae3551SRodney W. Grimes *exflagsp |= MNT_EXPORTANON; 22708fae3551SRodney W. Grimes opt_flags |= OP_MAPALL; 22718fae3551SRodney W. Grimes } else 22728fae3551SRodney W. Grimes opt_flags |= OP_MAPROOT; 22738fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 22748fae3551SRodney W. Grimes !strcmp(cpopt, "m"))) { 22758fae3551SRodney W. Grimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 227674853402SPhilippe Charnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 22778fae3551SRodney W. Grimes return (1); 22788fae3551SRodney W. Grimes } 22798fae3551SRodney W. Grimes usedarg++; 22808fae3551SRodney W. Grimes opt_flags |= OP_MASK; 22818fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 22828fae3551SRodney W. Grimes !strcmp(cpopt, "n"))) { 22838360efbdSAlfred Perlstein if (strchr(cpoptarg, '/') != NULL) { 22848360efbdSAlfred Perlstein if (debug) 22858360efbdSAlfred Perlstein fprintf(stderr, "setting OP_MASKLEN\n"); 22868360efbdSAlfred Perlstein opt_flags |= OP_MASKLEN; 22878360efbdSAlfred Perlstein } 22888fae3551SRodney W. Grimes if (grp->gr_type != GT_NULL) { 228974853402SPhilippe Charnier syslog(LOG_ERR, "network/host conflict"); 22908fae3551SRodney W. Grimes return (1); 22918fae3551SRodney W. Grimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 229274853402SPhilippe Charnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 22938fae3551SRodney W. Grimes return (1); 22948fae3551SRodney W. Grimes } 22958fae3551SRodney W. Grimes grp->gr_type = GT_NET; 22968fae3551SRodney W. Grimes *has_hostp = 1; 22978fae3551SRodney W. Grimes usedarg++; 22988fae3551SRodney W. Grimes opt_flags |= OP_NET; 22998fae3551SRodney W. Grimes } else if (!strcmp(cpopt, "alldirs")) { 23008fae3551SRodney W. Grimes opt_flags |= OP_ALLDIRS; 2301cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "public")) { 2302cb3923e0SDoug Rabson *exflagsp |= MNT_EXPUBLIC; 2303cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "webnfs")) { 2304cb3923e0SDoug Rabson *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2305cb3923e0SDoug Rabson opt_flags |= OP_MAPALL; 2306cb3923e0SDoug Rabson } else if (cpoptarg && !strcmp(cpopt, "index")) { 2307cb3923e0SDoug Rabson ep->ex_indexfile = strdup(cpoptarg); 2308288fa14aSJoerg Wunsch } else if (!strcmp(cpopt, "quiet")) { 2309288fa14aSJoerg Wunsch opt_flags |= OP_QUIET; 2310dcdc127bSSergey Kandaurov } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2311a9148abdSDoug Rabson if (parsesec(cpoptarg, ep)) 2312a9148abdSDoug Rabson return (1); 2313a9148abdSDoug Rabson opt_flags |= OP_SEC; 2314a9148abdSDoug Rabson usedarg++; 23158fae3551SRodney W. Grimes } else { 231674853402SPhilippe Charnier syslog(LOG_ERR, "bad opt %s", cpopt); 23178fae3551SRodney W. Grimes return (1); 23188fae3551SRodney W. Grimes } 23198fae3551SRodney W. Grimes if (usedarg >= 0) { 23208fae3551SRodney W. Grimes *endcp = savedc2; 23218fae3551SRodney W. Grimes **endcpp = savedc; 23228fae3551SRodney W. Grimes if (usedarg > 0) { 23238fae3551SRodney W. Grimes *cpp = cp; 23248fae3551SRodney W. Grimes *endcpp = endcp; 23258fae3551SRodney W. Grimes } 23268fae3551SRodney W. Grimes return (0); 23278fae3551SRodney W. Grimes } 23288fae3551SRodney W. Grimes cpopt = cpoptend; 23298fae3551SRodney W. Grimes } 23308fae3551SRodney W. Grimes **endcpp = savedc; 23318fae3551SRodney W. Grimes return (0); 23328fae3551SRodney W. Grimes } 23338fae3551SRodney W. Grimes 23348fae3551SRodney W. Grimes /* 23358fae3551SRodney W. Grimes * Translate a character string to the corresponding list of network 23368fae3551SRodney W. Grimes * addresses for a hostname. 23378fae3551SRodney W. Grimes */ 233819c46d8cSEdward Tomasz Napierala static int 2339a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 23408fae3551SRodney W. Grimes { 23418b5a6d67SBill Paul struct grouplist *checkgrp; 234201709abfSIan Dowse struct addrinfo *ai, *tai, hints; 23438360efbdSAlfred Perlstein int ecode; 23448360efbdSAlfred Perlstein char host[NI_MAXHOST]; 23458fae3551SRodney W. Grimes 23468360efbdSAlfred Perlstein if (grp->gr_type != GT_NULL) { 23478360efbdSAlfred Perlstein syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 23488fae3551SRodney W. Grimes return (1); 23498fae3551SRodney W. Grimes } 23508360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 23518360efbdSAlfred Perlstein hints.ai_flags = AI_CANONNAME; 23528360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 23538360efbdSAlfred Perlstein ecode = getaddrinfo(cp, NULL, &hints, &ai); 23548360efbdSAlfred Perlstein if (ecode != 0) { 235501709abfSIan Dowse syslog(LOG_ERR,"can't get address info for host %s", cp); 23568360efbdSAlfred Perlstein return 1; 23578fae3551SRodney W. Grimes } 23588360efbdSAlfred Perlstein grp->gr_ptr.gt_addrinfo = ai; 23598360efbdSAlfred Perlstein while (ai != NULL) { 23608360efbdSAlfred Perlstein if (ai->ai_canonname == NULL) { 23618360efbdSAlfred Perlstein if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 23624f101318SHajimu UMEMOTO sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 23638360efbdSAlfred Perlstein strlcpy(host, "?", sizeof(host)); 23648360efbdSAlfred Perlstein ai->ai_canonname = strdup(host); 23658360efbdSAlfred Perlstein ai->ai_flags |= AI_CANONNAME; 23666d359f31SIan Dowse } 23678fae3551SRodney W. Grimes if (debug) 236801709abfSIan Dowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 236901709abfSIan Dowse /* 237001709abfSIan Dowse * Sanity check: make sure we don't already have an entry 237101709abfSIan Dowse * for this host in the grouplist. 237201709abfSIan Dowse */ 237301709abfSIan Dowse for (checkgrp = tgrp; checkgrp != NULL; 237401709abfSIan Dowse checkgrp = checkgrp->gr_next) { 237501709abfSIan Dowse if (checkgrp->gr_type != GT_HOST) 237601709abfSIan Dowse continue; 237701709abfSIan Dowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 237801709abfSIan Dowse tai = tai->ai_next) { 237960caaee2SIan Dowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 238001709abfSIan Dowse continue; 238101709abfSIan Dowse if (debug) 238201709abfSIan Dowse fprintf(stderr, 238301709abfSIan Dowse "ignoring duplicate host %s\n", 238401709abfSIan Dowse ai->ai_canonname); 238501709abfSIan Dowse grp->gr_type = GT_IGNORE; 238601709abfSIan Dowse return (0); 238701709abfSIan Dowse } 238801709abfSIan Dowse } 23898360efbdSAlfred Perlstein ai = ai->ai_next; 23908360efbdSAlfred Perlstein } 239101709abfSIan Dowse grp->gr_type = GT_HOST; 23928fae3551SRodney W. Grimes return (0); 23938fae3551SRodney W. Grimes } 23948fae3551SRodney W. Grimes 23958fae3551SRodney W. Grimes /* 23968fae3551SRodney W. Grimes * Free up an exports list component 23978fae3551SRodney W. Grimes */ 239819c46d8cSEdward Tomasz Napierala static void 2399a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep) 24008fae3551SRodney W. Grimes { 24018fae3551SRodney W. Grimes 24028fae3551SRodney W. Grimes if (ep->ex_defdir) { 24038fae3551SRodney W. Grimes free_host(ep->ex_defdir->dp_hosts); 24048fae3551SRodney W. Grimes free((caddr_t)ep->ex_defdir); 24058fae3551SRodney W. Grimes } 24068fae3551SRodney W. Grimes if (ep->ex_fsdir) 24078fae3551SRodney W. Grimes free(ep->ex_fsdir); 2408cb3923e0SDoug Rabson if (ep->ex_indexfile) 2409cb3923e0SDoug Rabson free(ep->ex_indexfile); 24108fae3551SRodney W. Grimes free_dir(ep->ex_dirl); 24118fae3551SRodney W. Grimes free((caddr_t)ep); 24128fae3551SRodney W. Grimes } 24138fae3551SRodney W. Grimes 24148fae3551SRodney W. Grimes /* 24158fae3551SRodney W. Grimes * Free hosts. 24168fae3551SRodney W. Grimes */ 241719c46d8cSEdward Tomasz Napierala static void 2418a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp) 24198fae3551SRodney W. Grimes { 24208fae3551SRodney W. Grimes struct hostlist *hp2; 24218fae3551SRodney W. Grimes 24228fae3551SRodney W. Grimes while (hp) { 24238fae3551SRodney W. Grimes hp2 = hp; 24248fae3551SRodney W. Grimes hp = hp->ht_next; 24258fae3551SRodney W. Grimes free((caddr_t)hp2); 24268fae3551SRodney W. Grimes } 24278fae3551SRodney W. Grimes } 24288fae3551SRodney W. Grimes 242919c46d8cSEdward Tomasz Napierala static struct hostlist * 2430a7a7d96cSPhilippe Charnier get_ht(void) 24318fae3551SRodney W. Grimes { 24328fae3551SRodney W. Grimes struct hostlist *hp; 24338fae3551SRodney W. Grimes 24348fae3551SRodney W. Grimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 24358fae3551SRodney W. Grimes if (hp == (struct hostlist *)NULL) 24368fae3551SRodney W. Grimes out_of_mem(); 24378fae3551SRodney W. Grimes hp->ht_next = (struct hostlist *)NULL; 2438a62dc406SDoug Rabson hp->ht_flag = 0; 24398fae3551SRodney W. Grimes return (hp); 24408fae3551SRodney W. Grimes } 24418fae3551SRodney W. Grimes 24428fae3551SRodney W. Grimes /* 24438fae3551SRodney W. Grimes * Out of memory, fatal 24448fae3551SRodney W. Grimes */ 244519c46d8cSEdward Tomasz Napierala static void 2446a7a7d96cSPhilippe Charnier out_of_mem(void) 24478fae3551SRodney W. Grimes { 24488fae3551SRodney W. Grimes 244974853402SPhilippe Charnier syslog(LOG_ERR, "out of memory"); 24508fae3551SRodney W. Grimes exit(2); 24518fae3551SRodney W. Grimes } 24528fae3551SRodney W. Grimes 24538fae3551SRodney W. Grimes /* 24546a09faf2SCraig Rodrigues * Do the nmount() syscall with the update flag to push the export info into 24558fae3551SRodney W. Grimes * the kernel. 24568fae3551SRodney W. Grimes */ 245719c46d8cSEdward Tomasz Napierala static int 24586a09faf2SCraig Rodrigues do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 24596a09faf2SCraig Rodrigues struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 24608fae3551SRodney W. Grimes { 2461f93caef2SIan Dowse struct statfs fsb1; 24628360efbdSAlfred Perlstein struct addrinfo *ai; 246379b86807SEdward Tomasz Napierala struct export_args *eap; 24646a09faf2SCraig Rodrigues char errmsg[255]; 24656a09faf2SCraig Rodrigues char *cp; 24668fae3551SRodney W. Grimes int done; 24676a09faf2SCraig Rodrigues char savedc; 24686a09faf2SCraig Rodrigues struct iovec *iov; 2469a9148abdSDoug Rabson int i, iovlen; 24706a09faf2SCraig Rodrigues int ret; 2471bcc1d071SRick Macklem struct nfsex_args nfsea; 2472bcc1d071SRick Macklem 2473bcc1d071SRick Macklem eap = &nfsea.export; 24748fae3551SRodney W. Grimes 24756a09faf2SCraig Rodrigues cp = NULL; 24766a09faf2SCraig Rodrigues savedc = '\0'; 24776a09faf2SCraig Rodrigues iov = NULL; 24786a09faf2SCraig Rodrigues iovlen = 0; 24796a09faf2SCraig Rodrigues ret = 0; 248060caaee2SIan Dowse 2481bcc1d071SRick Macklem bzero(eap, sizeof (struct export_args)); 24826a09faf2SCraig Rodrigues bzero(errmsg, sizeof(errmsg)); 2483bcc1d071SRick Macklem eap->ex_flags = exflags; 2484bcc1d071SRick Macklem eap->ex_anon = *anoncrp; 2485bcc1d071SRick Macklem eap->ex_indexfile = ep->ex_indexfile; 24866d359f31SIan Dowse if (grp->gr_type == GT_HOST) 24878360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 24886d359f31SIan Dowse else 24896d359f31SIan Dowse ai = NULL; 2490bcc1d071SRick Macklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2491bcc1d071SRick Macklem for (i = 0; i < eap->ex_numsecflavors; i++) 2492bcc1d071SRick Macklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2493bcc1d071SRick Macklem if (eap->ex_numsecflavors == 0) { 2494bcc1d071SRick Macklem eap->ex_numsecflavors = 1; 2495bcc1d071SRick Macklem eap->ex_secflavors[0] = AUTH_SYS; 2496a9148abdSDoug Rabson } 24978fae3551SRodney W. Grimes done = FALSE; 24986a09faf2SCraig Rodrigues 2499bcc1d071SRick Macklem if (v4root_phase == 0) { 25006a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", NULL, 0); 25016a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", NULL, 0); 25026a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "from", NULL, 0); 25036a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "update", NULL, 0); 2504bcc1d071SRick Macklem build_iovec(&iov, &iovlen, "export", eap, 2505bcc1d071SRick Macklem sizeof (struct export_args)); 25066a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2507bcc1d071SRick Macklem } 25086a09faf2SCraig Rodrigues 25098fae3551SRodney W. Grimes while (!done) { 25108fae3551SRodney W. Grimes switch (grp->gr_type) { 25118fae3551SRodney W. Grimes case GT_HOST: 25126d359f31SIan Dowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 25138360efbdSAlfred Perlstein goto skip; 2514bcc1d071SRick Macklem eap->ex_addr = ai->ai_addr; 2515bcc1d071SRick Macklem eap->ex_addrlen = ai->ai_addrlen; 2516bcc1d071SRick Macklem eap->ex_masklen = 0; 25178fae3551SRodney W. Grimes break; 25188fae3551SRodney W. Grimes case GT_NET: 251960caaee2SIan Dowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 25208360efbdSAlfred Perlstein have_v6 == 0) 25218360efbdSAlfred Perlstein goto skip; 2522bcc1d071SRick Macklem eap->ex_addr = 252360caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2524bcc1d071SRick Macklem eap->ex_addrlen = 25256a09faf2SCraig Rodrigues ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2526bcc1d071SRick Macklem eap->ex_mask = 252760caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2528bcc1d071SRick Macklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 25298fae3551SRodney W. Grimes break; 25306d359f31SIan Dowse case GT_DEFAULT: 2531bcc1d071SRick Macklem eap->ex_addr = NULL; 2532bcc1d071SRick Macklem eap->ex_addrlen = 0; 2533bcc1d071SRick Macklem eap->ex_mask = NULL; 2534bcc1d071SRick Macklem eap->ex_masklen = 0; 25356d359f31SIan Dowse break; 25368b5a6d67SBill Paul case GT_IGNORE: 25376a09faf2SCraig Rodrigues ret = 0; 25386a09faf2SCraig Rodrigues goto error_exit; 25398b5a6d67SBill Paul break; 25408fae3551SRodney W. Grimes default: 254174853402SPhilippe Charnier syslog(LOG_ERR, "bad grouptype"); 25428fae3551SRodney W. Grimes if (cp) 25438fae3551SRodney W. Grimes *cp = savedc; 25446a09faf2SCraig Rodrigues ret = 1; 25456a09faf2SCraig Rodrigues goto error_exit; 254680c7cc1cSPedro F. Giffuni } 25478fae3551SRodney W. Grimes 25488fae3551SRodney W. Grimes /* 2549bcc1d071SRick Macklem * For V4:, use the nfssvc() syscall, instead of mount(). 2550bcc1d071SRick Macklem */ 2551bcc1d071SRick Macklem if (v4root_phase == 2) { 2552bcc1d071SRick Macklem nfsea.fspec = v4root_dirpath; 255379b86807SEdward Tomasz Napierala if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2554bcc1d071SRick Macklem syslog(LOG_ERR, "Exporting V4: failed"); 2555bcc1d071SRick Macklem return (2); 2556bcc1d071SRick Macklem } 2557bcc1d071SRick Macklem } else { 2558bcc1d071SRick Macklem /* 25598fae3551SRodney W. Grimes * XXX: 2560bcc1d071SRick Macklem * Maybe I should just use the fsb->f_mntonname path 2561bcc1d071SRick Macklem * instead of looping back up the dirp to the mount 2562bcc1d071SRick Macklem * point?? 25638fae3551SRodney W. Grimes * Also, needs to know how to export all types of local 256487564113SPeter Wemm * exportable filesystems and not just "ufs". 25658fae3551SRodney W. Grimes */ 25666a09faf2SCraig Rodrigues iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 25676a09faf2SCraig Rodrigues iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 25686a09faf2SCraig Rodrigues iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 25696a09faf2SCraig Rodrigues iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 25706a09faf2SCraig Rodrigues iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 25716a09faf2SCraig Rodrigues iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 25724a185fa6SBryan Drewery errmsg[0] = '\0'; 25736a09faf2SCraig Rodrigues 257455dd1327SCraig Rodrigues while (nmount(iov, iovlen, fsb->f_flags) < 0) { 25758fae3551SRodney W. Grimes if (cp) 25768fae3551SRodney W. Grimes *cp-- = savedc; 25778fae3551SRodney W. Grimes else 25788fae3551SRodney W. Grimes cp = dirp + dirplen - 1; 25796a09faf2SCraig Rodrigues if (opt_flags & OP_QUIET) { 25806a09faf2SCraig Rodrigues ret = 1; 25816a09faf2SCraig Rodrigues goto error_exit; 25826a09faf2SCraig Rodrigues } 25838fae3551SRodney W. Grimes if (errno == EPERM) { 258401709abfSIan Dowse if (debug) 258577909162SXin LI warnx("can't change attributes for %s: %s", 258677909162SXin LI dirp, errmsg); 25878fae3551SRodney W. Grimes syslog(LOG_ERR, 258877909162SXin LI "can't change attributes for %s: %s", 258977909162SXin LI dirp, errmsg); 25906a09faf2SCraig Rodrigues ret = 1; 25916a09faf2SCraig Rodrigues goto error_exit; 25928fae3551SRodney W. Grimes } 25938fae3551SRodney W. Grimes if (opt_flags & OP_ALLDIRS) { 2594288fa14aSJoerg Wunsch if (errno == EINVAL) 2595288fa14aSJoerg Wunsch syslog(LOG_ERR, 2596288fa14aSJoerg Wunsch "-alldirs requested but %s is not a filesystem mountpoint", 2597288fa14aSJoerg Wunsch dirp); 2598288fa14aSJoerg Wunsch else 2599288fa14aSJoerg Wunsch syslog(LOG_ERR, 2600288fa14aSJoerg Wunsch "could not remount %s: %m", 26013980ac4fSGarrett Wollman dirp); 26026a09faf2SCraig Rodrigues ret = 1; 26036a09faf2SCraig Rodrigues goto error_exit; 26048fae3551SRodney W. Grimes } 26058fae3551SRodney W. Grimes /* back up over the last component */ 26068fae3551SRodney W. Grimes while (*cp == '/' && cp > dirp) 26078fae3551SRodney W. Grimes cp--; 26088fae3551SRodney W. Grimes while (*(cp - 1) != '/' && cp > dirp) 26098fae3551SRodney W. Grimes cp--; 26108fae3551SRodney W. Grimes if (cp == dirp) { 26118fae3551SRodney W. Grimes if (debug) 261274853402SPhilippe Charnier warnx("mnt unsucc"); 2613bcc1d071SRick Macklem syslog(LOG_ERR, "can't export %s %s", 2614bcc1d071SRick Macklem dirp, errmsg); 26156a09faf2SCraig Rodrigues ret = 1; 26166a09faf2SCraig Rodrigues goto error_exit; 26178fae3551SRodney W. Grimes } 26188fae3551SRodney W. Grimes savedc = *cp; 26198fae3551SRodney W. Grimes *cp = '\0'; 2620bcc1d071SRick Macklem /* 2621bcc1d071SRick Macklem * Check that we're still on the same 2622bcc1d071SRick Macklem * filesystem. 2623bcc1d071SRick Macklem */ 2624bcc1d071SRick Macklem if (statfs(dirp, &fsb1) != 0 || 2625bcc1d071SRick Macklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2626bcc1d071SRick Macklem sizeof (fsb1.f_fsid)) != 0) { 2627f93caef2SIan Dowse *cp = savedc; 2628bcc1d071SRick Macklem syslog(LOG_ERR, 2629bcc1d071SRick Macklem "can't export %s %s", dirp, 263037518a88SCraig Rodrigues errmsg); 26316a09faf2SCraig Rodrigues ret = 1; 26326a09faf2SCraig Rodrigues goto error_exit; 2633f93caef2SIan Dowse } 26348fae3551SRodney W. Grimes } 2635bcc1d071SRick Macklem } 2636bcc1d071SRick Macklem 2637bcc1d071SRick Macklem /* 2638bcc1d071SRick Macklem * For the experimental server: 2639bcc1d071SRick Macklem * If this is the public directory, get the file handle 2640bcc1d071SRick Macklem * and load it into the kernel via the nfssvc() syscall. 2641bcc1d071SRick Macklem */ 264279b86807SEdward Tomasz Napierala if ((exflags & MNT_EXPUBLIC) != 0) { 2643bcc1d071SRick Macklem fhandle_t fh; 2644bcc1d071SRick Macklem char *public_name; 2645bcc1d071SRick Macklem 2646bcc1d071SRick Macklem if (eap->ex_indexfile != NULL) 2647bcc1d071SRick Macklem public_name = eap->ex_indexfile; 2648bcc1d071SRick Macklem else 2649bcc1d071SRick Macklem public_name = dirp; 2650bcc1d071SRick Macklem if (getfh(public_name, &fh) < 0) 2651bcc1d071SRick Macklem syslog(LOG_ERR, 2652bcc1d071SRick Macklem "Can't get public fh for %s", public_name); 2653bcc1d071SRick Macklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2654bcc1d071SRick Macklem syslog(LOG_ERR, 2655bcc1d071SRick Macklem "Can't set public fh for %s", public_name); 2656bcc1d071SRick Macklem else 2657bcc1d071SRick Macklem has_publicfh = 1; 2658bcc1d071SRick Macklem } 26598360efbdSAlfred Perlstein skip: 26606d359f31SIan Dowse if (ai != NULL) 26618360efbdSAlfred Perlstein ai = ai->ai_next; 26628360efbdSAlfred Perlstein if (ai == NULL) 26638fae3551SRodney W. Grimes done = TRUE; 26648fae3551SRodney W. Grimes } 26658fae3551SRodney W. Grimes if (cp) 26668fae3551SRodney W. Grimes *cp = savedc; 26676a09faf2SCraig Rodrigues error_exit: 26686a09faf2SCraig Rodrigues /* free strings allocated by strdup() in getmntopts.c */ 26696a09faf2SCraig Rodrigues if (iov != NULL) { 26706a09faf2SCraig Rodrigues free(iov[0].iov_base); /* fstype */ 26716a09faf2SCraig Rodrigues free(iov[2].iov_base); /* fspath */ 26726a09faf2SCraig Rodrigues free(iov[4].iov_base); /* from */ 26736a09faf2SCraig Rodrigues free(iov[6].iov_base); /* update */ 26746a09faf2SCraig Rodrigues free(iov[8].iov_base); /* export */ 26756a09faf2SCraig Rodrigues free(iov[10].iov_base); /* errmsg */ 26766a09faf2SCraig Rodrigues 26776a09faf2SCraig Rodrigues /* free iov, allocated by realloc() */ 26786a09faf2SCraig Rodrigues free(iov); 26796a09faf2SCraig Rodrigues } 26806a09faf2SCraig Rodrigues return (ret); 26818fae3551SRodney W. Grimes } 26828fae3551SRodney W. Grimes 26838fae3551SRodney W. Grimes /* 26848fae3551SRodney W. Grimes * Translate a net address. 268560caaee2SIan Dowse * 268660caaee2SIan Dowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 26878fae3551SRodney W. Grimes */ 268819c46d8cSEdward Tomasz Napierala static int 2689a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg) 26908fae3551SRodney W. Grimes { 2691931c04f1SIan Dowse struct netent *np = NULL; 26928360efbdSAlfred Perlstein char *name, *p, *prefp; 269360caaee2SIan Dowse struct sockaddr_in sin; 2694931c04f1SIan Dowse struct sockaddr *sa = NULL; 26958360efbdSAlfred Perlstein struct addrinfo hints, *ai = NULL; 26968360efbdSAlfred Perlstein char netname[NI_MAXHOST]; 26978360efbdSAlfred Perlstein long preflen; 26988fae3551SRodney W. Grimes 269901709abfSIan Dowse p = prefp = NULL; 27008360efbdSAlfred Perlstein if ((opt_flags & OP_MASKLEN) && !maskflg) { 27018360efbdSAlfred Perlstein p = strchr(cp, '/'); 27028360efbdSAlfred Perlstein *p = '\0'; 27038360efbdSAlfred Perlstein prefp = p + 1; 27048360efbdSAlfred Perlstein } 27058360efbdSAlfred Perlstein 2706931c04f1SIan Dowse /* 2707931c04f1SIan Dowse * Check for a numeric address first. We wish to avoid 2708931c04f1SIan Dowse * possible DNS lookups in getnetbyname(). 2709931c04f1SIan Dowse */ 2710931c04f1SIan Dowse if (isxdigit(*cp) || *cp == ':') { 27118360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 271260caaee2SIan Dowse /* Ensure the mask and the network have the same family. */ 271360caaee2SIan Dowse if (maskflg && (opt_flags & OP_NET)) 271460caaee2SIan Dowse hints.ai_family = net->nt_net.ss_family; 271560caaee2SIan Dowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 271660caaee2SIan Dowse hints.ai_family = net->nt_mask.ss_family; 271760caaee2SIan Dowse else 27188360efbdSAlfred Perlstein hints.ai_family = AF_UNSPEC; 27198360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 2720931c04f1SIan Dowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2721931c04f1SIan Dowse sa = ai->ai_addr; 2722931c04f1SIan Dowse if (sa != NULL && ai->ai_family == AF_INET) { 27238fae3551SRodney W. Grimes /* 272460caaee2SIan Dowse * The address in `cp' is really a network address, so 272560caaee2SIan Dowse * use inet_network() to re-interpret this correctly. 272660caaee2SIan Dowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 27278fae3551SRodney W. Grimes */ 272860caaee2SIan Dowse bzero(&sin, sizeof sin); 27298360efbdSAlfred Perlstein sin.sin_family = AF_INET; 27308360efbdSAlfred Perlstein sin.sin_len = sizeof sin; 27318360efbdSAlfred Perlstein sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 27328360efbdSAlfred Perlstein if (debug) 273360caaee2SIan Dowse fprintf(stderr, "get_net: v4 addr %s\n", 273460caaee2SIan Dowse inet_ntoa(sin.sin_addr)); 27358360efbdSAlfred Perlstein sa = (struct sockaddr *)&sin; 2736931c04f1SIan Dowse } 2737931c04f1SIan Dowse } 2738931c04f1SIan Dowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2739931c04f1SIan Dowse bzero(&sin, sizeof sin); 2740931c04f1SIan Dowse sin.sin_family = AF_INET; 2741931c04f1SIan Dowse sin.sin_len = sizeof sin; 2742931c04f1SIan Dowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 2743931c04f1SIan Dowse sa = (struct sockaddr *)&sin; 2744931c04f1SIan Dowse } 2745931c04f1SIan Dowse if (sa == NULL) 27468360efbdSAlfred Perlstein goto fail; 27478360efbdSAlfred Perlstein 274860caaee2SIan Dowse if (maskflg) { 274960caaee2SIan Dowse /* The specified sockaddr is a mask. */ 275060caaee2SIan Dowse if (checkmask(sa) != 0) 27518360efbdSAlfred Perlstein goto fail; 275260caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 275360caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 275460caaee2SIan Dowse } else { 275560caaee2SIan Dowse /* The specified sockaddr is a network address. */ 275660caaee2SIan Dowse bcopy(sa, &net->nt_net, sa->sa_len); 27570f4b7baaSPaul Traina 275860caaee2SIan Dowse /* Get a network name for the export list. */ 275960caaee2SIan Dowse if (np) { 276060caaee2SIan Dowse name = np->n_name; 276160caaee2SIan Dowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 27624f101318SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) { 276360caaee2SIan Dowse name = netname; 276460caaee2SIan Dowse } else { 276560caaee2SIan Dowse goto fail; 276660caaee2SIan Dowse } 276760caaee2SIan Dowse if ((net->nt_name = strdup(name)) == NULL) 276860caaee2SIan Dowse out_of_mem(); 276960caaee2SIan Dowse 277060caaee2SIan Dowse /* 277160caaee2SIan Dowse * Extract a mask from either a "/<masklen>" suffix, or 277260caaee2SIan Dowse * from the class of an IPv4 address. 277360caaee2SIan Dowse */ 27748360efbdSAlfred Perlstein if (opt_flags & OP_MASKLEN) { 27758360efbdSAlfred Perlstein preflen = strtol(prefp, NULL, 10); 277660caaee2SIan Dowse if (preflen < 0L || preflen == LONG_MAX) 27778360efbdSAlfred Perlstein goto fail; 277860caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 277960caaee2SIan Dowse if (makemask(&net->nt_mask, (int)preflen) != 0) 278060caaee2SIan Dowse goto fail; 278160caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 27828360efbdSAlfred Perlstein *p = '/'; 278360caaee2SIan Dowse } else if (sa->sa_family == AF_INET && 278460caaee2SIan Dowse (opt_flags & OP_MASK) == 0) { 278560caaee2SIan Dowse in_addr_t addr; 27868360efbdSAlfred Perlstein 278760caaee2SIan Dowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 278860caaee2SIan Dowse if (IN_CLASSA(addr)) 278960caaee2SIan Dowse preflen = 8; 279060caaee2SIan Dowse else if (IN_CLASSB(addr)) 279160caaee2SIan Dowse preflen = 16; 279260caaee2SIan Dowse else if (IN_CLASSC(addr)) 279360caaee2SIan Dowse preflen = 24; 279460caaee2SIan Dowse else if (IN_CLASSD(addr)) 279560caaee2SIan Dowse preflen = 28; 27968360efbdSAlfred Perlstein else 279760caaee2SIan Dowse preflen = 32; /* XXX */ 279860caaee2SIan Dowse 279960caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 280060caaee2SIan Dowse makemask(&net->nt_mask, (int)preflen); 280160caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 280260caaee2SIan Dowse } 28038360efbdSAlfred Perlstein } 28048360efbdSAlfred Perlstein 28058360efbdSAlfred Perlstein if (ai) 28068360efbdSAlfred Perlstein freeaddrinfo(ai); 28078360efbdSAlfred Perlstein return 0; 28088360efbdSAlfred Perlstein 28098360efbdSAlfred Perlstein fail: 28108360efbdSAlfred Perlstein if (ai) 28118360efbdSAlfred Perlstein freeaddrinfo(ai); 28128360efbdSAlfred Perlstein return 1; 28138fae3551SRodney W. Grimes } 28148fae3551SRodney W. Grimes 28158fae3551SRodney W. Grimes /* 28168fae3551SRodney W. Grimes * Parse out the next white space separated field 28178fae3551SRodney W. Grimes */ 281819c46d8cSEdward Tomasz Napierala static void 2819a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp) 28208fae3551SRodney W. Grimes { 28218fae3551SRodney W. Grimes char *p; 28228fae3551SRodney W. Grimes 28238fae3551SRodney W. Grimes p = *cp; 28248fae3551SRodney W. Grimes while (*p == ' ' || *p == '\t') 28258fae3551SRodney W. Grimes p++; 28268fae3551SRodney W. Grimes if (*p == '\n' || *p == '\0') 28278fae3551SRodney W. Grimes *cp = *endcp = p; 28288fae3551SRodney W. Grimes else { 28298fae3551SRodney W. Grimes *cp = p++; 28308fae3551SRodney W. Grimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 28318fae3551SRodney W. Grimes p++; 28328fae3551SRodney W. Grimes *endcp = p; 28338fae3551SRodney W. Grimes } 28348fae3551SRodney W. Grimes } 28358fae3551SRodney W. Grimes 28368fae3551SRodney W. Grimes /* 28378fae3551SRodney W. Grimes * Get an exports file line. Skip over blank lines and handle line 28388fae3551SRodney W. Grimes * continuations. 28398fae3551SRodney W. Grimes */ 284019c46d8cSEdward Tomasz Napierala static int 2841a7a7d96cSPhilippe Charnier get_line(void) 28428fae3551SRodney W. Grimes { 28438fae3551SRodney W. Grimes char *p, *cp; 284491ca1a91SIan Dowse size_t len; 28458fae3551SRodney W. Grimes int totlen, cont_line; 28468fae3551SRodney W. Grimes 28478fae3551SRodney W. Grimes /* 28488fae3551SRodney W. Grimes * Loop around ignoring blank lines and getting all continuation lines. 28498fae3551SRodney W. Grimes */ 28508fae3551SRodney W. Grimes p = line; 28518fae3551SRodney W. Grimes totlen = 0; 28528fae3551SRodney W. Grimes do { 285391ca1a91SIan Dowse if ((p = fgetln(exp_file, &len)) == NULL) 28548fae3551SRodney W. Grimes return (0); 28558fae3551SRodney W. Grimes cp = p + len - 1; 28568fae3551SRodney W. Grimes cont_line = 0; 28578fae3551SRodney W. Grimes while (cp >= p && 28588fae3551SRodney W. Grimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 28598fae3551SRodney W. Grimes if (*cp == '\\') 28608fae3551SRodney W. Grimes cont_line = 1; 28618fae3551SRodney W. Grimes cp--; 28628fae3551SRodney W. Grimes len--; 28638fae3551SRodney W. Grimes } 2864376f8390SDima Dorfman if (cont_line) { 2865376f8390SDima Dorfman *++cp = ' '; 2866376f8390SDima Dorfman len++; 2867376f8390SDima Dorfman } 286891ca1a91SIan Dowse if (linesize < len + totlen + 1) { 286991ca1a91SIan Dowse linesize = len + totlen + 1; 287091ca1a91SIan Dowse line = realloc(line, linesize); 287191ca1a91SIan Dowse if (line == NULL) 287291ca1a91SIan Dowse out_of_mem(); 287391ca1a91SIan Dowse } 287491ca1a91SIan Dowse memcpy(line + totlen, p, len); 28758fae3551SRodney W. Grimes totlen += len; 287691ca1a91SIan Dowse line[totlen] = '\0'; 28778fae3551SRodney W. Grimes } while (totlen == 0 || cont_line); 28788fae3551SRodney W. Grimes return (1); 28798fae3551SRodney W. Grimes } 28808fae3551SRodney W. Grimes 28818fae3551SRodney W. Grimes /* 28828fae3551SRodney W. Grimes * Parse a description of a credential. 28838fae3551SRodney W. Grimes */ 288419c46d8cSEdward Tomasz Napierala static void 2885a7a7d96cSPhilippe Charnier parsecred(char *namelist, struct xucred *cr) 28868fae3551SRodney W. Grimes { 28878fae3551SRodney W. Grimes char *name; 28888fae3551SRodney W. Grimes int cnt; 28898fae3551SRodney W. Grimes char *names; 28908fae3551SRodney W. Grimes struct passwd *pw; 28918fae3551SRodney W. Grimes struct group *gr; 2892838d9858SBrooks Davis gid_t groups[XU_NGROUPS + 1]; 2893950cc395SStefan Farfeleder int ngroups; 28948fae3551SRodney W. Grimes 289576183f34SDima Dorfman cr->cr_version = XUCRED_VERSION; 28968fae3551SRodney W. Grimes /* 289774853402SPhilippe Charnier * Set up the unprivileged user. 28988fae3551SRodney W. Grimes */ 2899947572b4SRick Macklem cr->cr_uid = 65534; 2900947572b4SRick Macklem cr->cr_groups[0] = 65533; 29018fae3551SRodney W. Grimes cr->cr_ngroups = 1; 29028fae3551SRodney W. Grimes /* 29038fae3551SRodney W. Grimes * Get the user's password table entry. 29048fae3551SRodney W. Grimes */ 2905b875c2e9SJosh Paetzel names = strsep_quote(&namelist, " \t\n"); 29068fae3551SRodney W. Grimes name = strsep(&names, ":"); 2907b875c2e9SJosh Paetzel /* Bug? name could be NULL here */ 29088fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') 29098fae3551SRodney W. Grimes pw = getpwuid(atoi(name)); 29108fae3551SRodney W. Grimes else 29118fae3551SRodney W. Grimes pw = getpwnam(name); 29128fae3551SRodney W. Grimes /* 29138fae3551SRodney W. Grimes * Credentials specified as those of a user. 29148fae3551SRodney W. Grimes */ 29158fae3551SRodney W. Grimes if (names == NULL) { 29168fae3551SRodney W. Grimes if (pw == NULL) { 291774853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 29188fae3551SRodney W. Grimes return; 29198fae3551SRodney W. Grimes } 29208fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 2921838d9858SBrooks Davis ngroups = XU_NGROUPS + 1; 2922020d6f96SAndriy Gapon if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { 292374853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 2924020d6f96SAndriy Gapon ngroups = XU_NGROUPS + 1; 2925020d6f96SAndriy Gapon } 2926020d6f96SAndriy Gapon 29278fae3551SRodney W. Grimes /* 2928950cc395SStefan Farfeleder * Compress out duplicate. 29298fae3551SRodney W. Grimes */ 29308fae3551SRodney W. Grimes cr->cr_ngroups = ngroups - 1; 29318fae3551SRodney W. Grimes cr->cr_groups[0] = groups[0]; 29328fae3551SRodney W. Grimes for (cnt = 2; cnt < ngroups; cnt++) 29338fae3551SRodney W. Grimes cr->cr_groups[cnt - 1] = groups[cnt]; 29348fae3551SRodney W. Grimes return; 29358fae3551SRodney W. Grimes } 29368fae3551SRodney W. Grimes /* 29378fae3551SRodney W. Grimes * Explicit credential specified as a colon separated list: 29388fae3551SRodney W. Grimes * uid:gid:gid:... 29398fae3551SRodney W. Grimes */ 29408fae3551SRodney W. Grimes if (pw != NULL) 29418fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 29428fae3551SRodney W. Grimes else if (isdigit(*name) || *name == '-') 29438fae3551SRodney W. Grimes cr->cr_uid = atoi(name); 29448fae3551SRodney W. Grimes else { 294574853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 29468fae3551SRodney W. Grimes return; 29478fae3551SRodney W. Grimes } 29488fae3551SRodney W. Grimes cr->cr_ngroups = 0; 2949838d9858SBrooks Davis while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 29508fae3551SRodney W. Grimes name = strsep(&names, ":"); 29518fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') { 29528fae3551SRodney W. Grimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 29538fae3551SRodney W. Grimes } else { 29548fae3551SRodney W. Grimes if ((gr = getgrnam(name)) == NULL) { 295574853402SPhilippe Charnier syslog(LOG_ERR, "unknown group: %s", name); 29568fae3551SRodney W. Grimes continue; 29578fae3551SRodney W. Grimes } 29588fae3551SRodney W. Grimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 29598fae3551SRodney W. Grimes } 29608fae3551SRodney W. Grimes } 2961838d9858SBrooks Davis if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 296274853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 29638fae3551SRodney W. Grimes } 29648fae3551SRodney W. Grimes 29650775314bSDoug Rabson #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 29668fae3551SRodney W. Grimes /* 29678fae3551SRodney W. Grimes * Routines that maintain the remote mounttab 29688fae3551SRodney W. Grimes */ 296919c46d8cSEdward Tomasz Napierala static void 2970a7a7d96cSPhilippe Charnier get_mountlist(void) 29718fae3551SRodney W. Grimes { 29721da3e8b0SEmmanuel Vadot struct mountlist *mlp; 297387564113SPeter Wemm char *host, *dirp, *cp; 29748fae3551SRodney W. Grimes char str[STRSIZ]; 29758fae3551SRodney W. Grimes FILE *mlfile; 29768fae3551SRodney W. Grimes 29778fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 297839539916SBill Fumerola if (errno == ENOENT) 297939539916SBill Fumerola return; 298039539916SBill Fumerola else { 298174853402SPhilippe Charnier syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 29828fae3551SRodney W. Grimes return; 29838fae3551SRodney W. Grimes } 298439539916SBill Fumerola } 29858fae3551SRodney W. Grimes while (fgets(str, STRSIZ, mlfile) != NULL) { 298687564113SPeter Wemm cp = str; 298787564113SPeter Wemm host = strsep(&cp, " \t\n"); 298887564113SPeter Wemm dirp = strsep(&cp, " \t\n"); 298987564113SPeter Wemm if (host == NULL || dirp == NULL) 29908fae3551SRodney W. Grimes continue; 29918fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 299274853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 299374853402SPhilippe Charnier out_of_mem(); 29940775314bSDoug Rabson strncpy(mlp->ml_host, host, MNTNAMLEN); 29950775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 29960775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 29970775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 29981da3e8b0SEmmanuel Vadot 29991da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 30008fae3551SRodney W. Grimes } 30018fae3551SRodney W. Grimes fclose(mlfile); 30028fae3551SRodney W. Grimes } 30038fae3551SRodney W. Grimes 300419c46d8cSEdward Tomasz Napierala static void 300501709abfSIan Dowse del_mlist(char *hostp, char *dirp) 30068fae3551SRodney W. Grimes { 30071da3e8b0SEmmanuel Vadot struct mountlist *mlp, *mlp2; 30088fae3551SRodney W. Grimes FILE *mlfile; 30098fae3551SRodney W. Grimes int fnd = 0; 30108fae3551SRodney W. Grimes 30111da3e8b0SEmmanuel Vadot SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) { 30128fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && 30138fae3551SRodney W. Grimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 30148fae3551SRodney W. Grimes fnd = 1; 30151da3e8b0SEmmanuel Vadot SLIST_REMOVE(&mlhead, mlp, mountlist, next); 30161da3e8b0SEmmanuel Vadot free((caddr_t)mlp); 30178fae3551SRodney W. Grimes } 30188fae3551SRodney W. Grimes } 30198fae3551SRodney W. Grimes if (fnd) { 30208fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 302174853402SPhilippe Charnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 30228fae3551SRodney W. Grimes return; 30238fae3551SRodney W. Grimes } 30241da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 30258fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30268fae3551SRodney W. Grimes } 30278fae3551SRodney W. Grimes fclose(mlfile); 30288fae3551SRodney W. Grimes } 30298fae3551SRodney W. Grimes } 30308fae3551SRodney W. Grimes 303119c46d8cSEdward Tomasz Napierala static void 3032a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp) 30338fae3551SRodney W. Grimes { 30341da3e8b0SEmmanuel Vadot struct mountlist *mlp; 30358fae3551SRodney W. Grimes FILE *mlfile; 30368fae3551SRodney W. Grimes 30371da3e8b0SEmmanuel Vadot SLIST_FOREACH(mlp, &mlhead, next) { 30388fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 30398fae3551SRodney W. Grimes return; 30408fae3551SRodney W. Grimes } 30411da3e8b0SEmmanuel Vadot 30428fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 304374853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 304474853402SPhilippe Charnier out_of_mem(); 30450775314bSDoug Rabson strncpy(mlp->ml_host, hostp, MNTNAMLEN); 30460775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 30470775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 30480775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 30491da3e8b0SEmmanuel Vadot SLIST_INSERT_HEAD(&mlhead, mlp, next); 30508fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 305174853402SPhilippe Charnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 30528fae3551SRodney W. Grimes return; 30538fae3551SRodney W. Grimes } 30548fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30558fae3551SRodney W. Grimes fclose(mlfile); 30568fae3551SRodney W. Grimes } 30578fae3551SRodney W. Grimes 30588fae3551SRodney W. Grimes /* 30598fae3551SRodney W. Grimes * Free up a group list. 30608fae3551SRodney W. Grimes */ 306119c46d8cSEdward Tomasz Napierala static void 3062a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp) 30638fae3551SRodney W. Grimes { 30648fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 30658360efbdSAlfred Perlstein if (grp->gr_ptr.gt_addrinfo != NULL) 30668360efbdSAlfred Perlstein freeaddrinfo(grp->gr_ptr.gt_addrinfo); 30678fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 30688fae3551SRodney W. Grimes if (grp->gr_ptr.gt_net.nt_name) 30698fae3551SRodney W. Grimes free(grp->gr_ptr.gt_net.nt_name); 30708fae3551SRodney W. Grimes } 30718fae3551SRodney W. Grimes free((caddr_t)grp); 30728fae3551SRodney W. Grimes } 30738fae3551SRodney W. Grimes 30748fae3551SRodney W. Grimes #ifdef DEBUG 307519c46d8cSEdward Tomasz Napierala static void 30768fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...) 30778fae3551SRodney W. Grimes { 30788fae3551SRodney W. Grimes va_list ap; 30798fae3551SRodney W. Grimes 30808fae3551SRodney W. Grimes va_start(ap, fmt); 30818fae3551SRodney W. Grimes vfprintf(stderr, fmt, ap); 30828fae3551SRodney W. Grimes va_end(ap); 30838fae3551SRodney W. Grimes } 30848fae3551SRodney W. Grimes #endif /* DEBUG */ 30858fae3551SRodney W. Grimes 30868fae3551SRodney W. Grimes /* 30878fae3551SRodney W. Grimes * Check options for consistency. 30888fae3551SRodney W. Grimes */ 308919c46d8cSEdward Tomasz Napierala static int 3090a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp) 30918fae3551SRodney W. Grimes { 30928fae3551SRodney W. Grimes 3093bcc1d071SRick Macklem if (v4root_phase == 0 && dp == NULL) 30948fae3551SRodney W. Grimes return (1); 309591196234SPeter Wemm if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 309691196234SPeter Wemm syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 30978fae3551SRodney W. Grimes return (1); 30988fae3551SRodney W. Grimes } 30998fae3551SRodney W. Grimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 310060caaee2SIan Dowse syslog(LOG_ERR, "-mask requires -network"); 310160caaee2SIan Dowse return (1); 310260caaee2SIan Dowse } 310360caaee2SIan Dowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 310460caaee2SIan Dowse syslog(LOG_ERR, "-network requires mask specification"); 310560caaee2SIan Dowse return (1); 310660caaee2SIan Dowse } 310760caaee2SIan Dowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 310860caaee2SIan Dowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 31098fae3551SRodney W. Grimes return (1); 31108fae3551SRodney W. Grimes } 3111bcc1d071SRick Macklem if (v4root_phase > 0 && 3112bcc1d071SRick Macklem (opt_flags & 3113bcc1d071SRick Macklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3114bcc1d071SRick Macklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3115bcc1d071SRick Macklem return (1); 3116bcc1d071SRick Macklem } 311756cfc5edSRick Macklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 311856cfc5edSRick Macklem syslog(LOG_ERR, "-alldirs has multiple directories"); 311956cfc5edSRick Macklem return (1); 312056cfc5edSRick Macklem } 31218fae3551SRodney W. Grimes return (0); 31228fae3551SRodney W. Grimes } 31238fae3551SRodney W. Grimes 31248fae3551SRodney W. Grimes /* 31258fae3551SRodney W. Grimes * Check an absolute directory path for any symbolic links. Return true 31268fae3551SRodney W. Grimes */ 312719c46d8cSEdward Tomasz Napierala static int 3128a7a7d96cSPhilippe Charnier check_dirpath(char *dirp) 31298fae3551SRodney W. Grimes { 31308fae3551SRodney W. Grimes char *cp; 31318fae3551SRodney W. Grimes int ret = 1; 31328fae3551SRodney W. Grimes struct stat sb; 31338fae3551SRodney W. Grimes 31348fae3551SRodney W. Grimes cp = dirp + 1; 31358fae3551SRodney W. Grimes while (*cp && ret) { 31368fae3551SRodney W. Grimes if (*cp == '/') { 31378fae3551SRodney W. Grimes *cp = '\0'; 3138a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31398fae3551SRodney W. Grimes ret = 0; 31408fae3551SRodney W. Grimes *cp = '/'; 31418fae3551SRodney W. Grimes } 31428fae3551SRodney W. Grimes cp++; 31438fae3551SRodney W. Grimes } 3144a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31458fae3551SRodney W. Grimes ret = 0; 31468fae3551SRodney W. Grimes return (ret); 31478fae3551SRodney W. Grimes } 3148a62dc406SDoug Rabson 314960caaee2SIan Dowse /* 315060caaee2SIan Dowse * Make a netmask according to the specified prefix length. The ss_family 315160caaee2SIan Dowse * and other non-address fields must be initialised before calling this. 315260caaee2SIan Dowse */ 315319c46d8cSEdward Tomasz Napierala static int 315460caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen) 31558360efbdSAlfred Perlstein { 315660caaee2SIan Dowse u_char *p; 315760caaee2SIan Dowse int bits, i, len; 31588360efbdSAlfred Perlstein 315960caaee2SIan Dowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 316060caaee2SIan Dowse return (-1); 316189fdc4e1SMike Barcroft if (bitlen > len * CHAR_BIT) 316260caaee2SIan Dowse return (-1); 31638360efbdSAlfred Perlstein 316460caaee2SIan Dowse for (i = 0; i < len; i++) { 3165a175f065SMarcelo Araujo bits = MIN(CHAR_BIT, bitlen); 316658202d89SRuslan Ermilov *p++ = (u_char)~0 << (CHAR_BIT - bits); 316760caaee2SIan Dowse bitlen -= bits; 31688360efbdSAlfred Perlstein } 31698360efbdSAlfred Perlstein return 0; 31708360efbdSAlfred Perlstein } 31718360efbdSAlfred Perlstein 317260caaee2SIan Dowse /* 317360caaee2SIan Dowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 317460caaee2SIan Dowse * is acceptable (i.e. of the form 1...10....0). 317560caaee2SIan Dowse */ 317619c46d8cSEdward Tomasz Napierala static int 317760caaee2SIan Dowse checkmask(struct sockaddr *sa) 31788360efbdSAlfred Perlstein { 317960caaee2SIan Dowse u_char *mask; 318060caaee2SIan Dowse int i, len; 318160caaee2SIan Dowse 318260caaee2SIan Dowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 318360caaee2SIan Dowse return (-1); 318460caaee2SIan Dowse 318560caaee2SIan Dowse for (i = 0; i < len; i++) 318660caaee2SIan Dowse if (mask[i] != 0xff) 318760caaee2SIan Dowse break; 318860caaee2SIan Dowse if (i < len) { 318960caaee2SIan Dowse if (~mask[i] & (u_char)(~mask[i] + 1)) 319060caaee2SIan Dowse return (-1); 319160caaee2SIan Dowse i++; 319260caaee2SIan Dowse } 319360caaee2SIan Dowse for (; i < len; i++) 319460caaee2SIan Dowse if (mask[i] != 0) 319560caaee2SIan Dowse return (-1); 319660caaee2SIan Dowse return (0); 319760caaee2SIan Dowse } 319860caaee2SIan Dowse 319960caaee2SIan Dowse /* 320060caaee2SIan Dowse * Compare two sockaddrs according to a specified mask. Return zero if 320160caaee2SIan Dowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 32023df5ecacSUlrich Spörlein * If samask is NULL, perform a full comparison. 320360caaee2SIan Dowse */ 320419c46d8cSEdward Tomasz Napierala static int 320560caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 320660caaee2SIan Dowse { 320760caaee2SIan Dowse unsigned char *p1, *p2, *mask; 320860caaee2SIan Dowse int len, i; 320960caaee2SIan Dowse 321060caaee2SIan Dowse if (sa1->sa_family != sa2->sa_family || 321160caaee2SIan Dowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 321260caaee2SIan Dowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 321360caaee2SIan Dowse return (1); 321460caaee2SIan Dowse 321560caaee2SIan Dowse switch (sa1->sa_family) { 321660caaee2SIan Dowse case AF_INET6: 321760caaee2SIan Dowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 321860caaee2SIan Dowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 321960caaee2SIan Dowse return (1); 322060caaee2SIan Dowse break; 322160caaee2SIan Dowse } 322260caaee2SIan Dowse 322360caaee2SIan Dowse /* Simple binary comparison if no mask specified. */ 322460caaee2SIan Dowse if (samask == NULL) 322560caaee2SIan Dowse return (memcmp(p1, p2, len)); 322660caaee2SIan Dowse 322760caaee2SIan Dowse /* Set up the mask, and do a mask-based comparison. */ 322860caaee2SIan Dowse if (sa1->sa_family != samask->sa_family || 322960caaee2SIan Dowse (mask = sa_rawaddr(samask, NULL)) == NULL) 323060caaee2SIan Dowse return (1); 323160caaee2SIan Dowse 323260caaee2SIan Dowse for (i = 0; i < len; i++) 323360caaee2SIan Dowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 323460caaee2SIan Dowse return (1); 323560caaee2SIan Dowse return (0); 323660caaee2SIan Dowse } 323760caaee2SIan Dowse 323860caaee2SIan Dowse /* 323960caaee2SIan Dowse * Return a pointer to the part of the sockaddr that contains the 324060caaee2SIan Dowse * raw address, and set *nbytes to its length in bytes. Returns 324160caaee2SIan Dowse * NULL if the address family is unknown. 324260caaee2SIan Dowse */ 324319c46d8cSEdward Tomasz Napierala static void * 324460caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) { 324560caaee2SIan Dowse void *p; 324660caaee2SIan Dowse int len; 32478360efbdSAlfred Perlstein 32488360efbdSAlfred Perlstein switch (sa->sa_family) { 32498360efbdSAlfred Perlstein case AF_INET: 325060caaee2SIan Dowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 325160caaee2SIan Dowse p = &((struct sockaddr_in *)sa)->sin_addr; 32528360efbdSAlfred Perlstein break; 32538360efbdSAlfred Perlstein case AF_INET6: 325460caaee2SIan Dowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 325560caaee2SIan Dowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 32568360efbdSAlfred Perlstein break; 32578360efbdSAlfred Perlstein default: 325860caaee2SIan Dowse p = NULL; 325960caaee2SIan Dowse len = 0; 32608360efbdSAlfred Perlstein } 32618360efbdSAlfred Perlstein 326260caaee2SIan Dowse if (nbytes != NULL) 326360caaee2SIan Dowse *nbytes = len; 326460caaee2SIan Dowse return (p); 32658360efbdSAlfred Perlstein } 32668360efbdSAlfred Perlstein 326719c46d8cSEdward Tomasz Napierala static void 3268a7a7d96cSPhilippe Charnier huphandler(int sig __unused) 326969d65572SIan Dowse { 327019c46d8cSEdward Tomasz Napierala 327169d65572SIan Dowse got_sighup = 1; 327269d65572SIan Dowse } 327369d65572SIan Dowse 327419c46d8cSEdward Tomasz Napierala static void 327519c46d8cSEdward Tomasz Napierala terminate(int sig __unused) 32768360efbdSAlfred Perlstein { 3277a032b226SPawel Jakub Dawidek pidfile_remove(pfh); 32780775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 32790775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 32808360efbdSAlfred Perlstein exit (0); 32818360efbdSAlfred Perlstein } 3282