18fae3551SRodney W. Grimes /* 28fae3551SRodney W. Grimes * Copyright (c) 1989, 1993 38fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved. 48fae3551SRodney W. Grimes * 58fae3551SRodney W. Grimes * This code is derived from software contributed to Berkeley by 68fae3551SRodney W. Grimes * Herb Hasler and Rick Macklem at The University of Guelph. 78fae3551SRodney W. Grimes * 88fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 98fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions 108fae3551SRodney W. Grimes * are met: 118fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 128fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 138fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 148fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 158fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution. 168fae3551SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 178fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software 188fae3551SRodney W. Grimes * without specific prior written permission. 198fae3551SRodney W. Grimes * 208fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 218fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 228fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 238fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 248fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 258fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 268fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 278fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 288fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 298fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 308fae3551SRodney W. Grimes * SUCH DAMAGE. 318fae3551SRodney W. Grimes */ 328fae3551SRodney W. Grimes 338fae3551SRodney W. Grimes #ifndef lint 3474853402SPhilippe Charnier static const char copyright[] = 358fae3551SRodney W. Grimes "@(#) Copyright (c) 1989, 1993\n\ 368fae3551SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 37d599144dSGarrett Wollman #endif /*not lint*/ 388fae3551SRodney W. Grimes 3974853402SPhilippe Charnier #if 0 4075201fa4SPhilippe Charnier #ifndef lint 4174853402SPhilippe Charnier static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42d599144dSGarrett Wollman #endif /*not lint*/ 4375201fa4SPhilippe Charnier #endif 4475201fa4SPhilippe Charnier 4575201fa4SPhilippe Charnier #include <sys/cdefs.h> 4675201fa4SPhilippe Charnier __FBSDID("$FreeBSD$"); 478fae3551SRodney W. Grimes 488fae3551SRodney W. Grimes #include <sys/param.h> 498360efbdSAlfred Perlstein #include <sys/fcntl.h> 5091ca1a91SIan Dowse #include <sys/linker.h> 5191ca1a91SIan Dowse #include <sys/module.h> 52bcc1d071SRick Macklem #include <sys/mount.h> 53bcc1d071SRick Macklem #include <sys/stat.h> 54bcc1d071SRick Macklem #include <sys/sysctl.h> 55bcc1d071SRick Macklem #include <sys/syslog.h> 568fae3551SRodney W. Grimes 578fae3551SRodney W. Grimes #include <rpc/rpc.h> 58bcb53b16SMartin Blapp #include <rpc/rpc_com.h> 598fae3551SRodney W. Grimes #include <rpc/pmap_clnt.h> 608360efbdSAlfred Perlstein #include <rpc/pmap_prot.h> 618360efbdSAlfred Perlstein #include <rpcsvc/mount.h> 62a62dc406SDoug Rabson #include <nfs/nfsproto.h> 63bcc1d071SRick Macklem #include <nfs/nfssvc.h> 6491196234SPeter Wemm #include <nfsserver/nfs.h> 658fae3551SRodney W. Grimes 66bcc1d071SRick Macklem #include <fs/nfs/nfsport.h> 67bcc1d071SRick Macklem 688fae3551SRodney W. Grimes #include <arpa/inet.h> 698fae3551SRodney W. Grimes 708fae3551SRodney W. Grimes #include <ctype.h> 7174853402SPhilippe Charnier #include <err.h> 728fae3551SRodney W. Grimes #include <errno.h> 738fae3551SRodney W. Grimes #include <grp.h> 74a032b226SPawel Jakub Dawidek #include <libutil.h> 7589fdc4e1SMike Barcroft #include <limits.h> 768fae3551SRodney W. Grimes #include <netdb.h> 778fae3551SRodney W. Grimes #include <pwd.h> 788fae3551SRodney W. Grimes #include <signal.h> 798fae3551SRodney W. Grimes #include <stdio.h> 808fae3551SRodney W. Grimes #include <stdlib.h> 818fae3551SRodney W. Grimes #include <string.h> 828fae3551SRodney W. Grimes #include <unistd.h> 838fae3551SRodney W. Grimes #include "pathnames.h" 846a09faf2SCraig Rodrigues #include "mntopts.h" 858fae3551SRodney W. Grimes 868fae3551SRodney W. Grimes #ifdef DEBUG 878fae3551SRodney W. Grimes #include <stdarg.h> 888fae3551SRodney W. Grimes #endif 898fae3551SRodney W. Grimes 908fae3551SRodney W. Grimes /* 918fae3551SRodney W. Grimes * Structures for keeping the mount list and export list 928fae3551SRodney W. Grimes */ 938fae3551SRodney W. Grimes struct mountlist { 948fae3551SRodney W. Grimes struct mountlist *ml_next; 950775314bSDoug Rabson char ml_host[MNTNAMLEN+1]; 960775314bSDoug Rabson char ml_dirp[MNTPATHLEN+1]; 978fae3551SRodney W. Grimes }; 988fae3551SRodney W. Grimes 998fae3551SRodney W. Grimes struct dirlist { 1008fae3551SRodney W. Grimes struct dirlist *dp_left; 1018fae3551SRodney W. Grimes struct dirlist *dp_right; 1028fae3551SRodney W. Grimes int dp_flag; 1038fae3551SRodney W. Grimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1048fae3551SRodney W. Grimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1058fae3551SRodney W. Grimes }; 1068fae3551SRodney W. Grimes /* dp_flag bits */ 1078fae3551SRodney W. Grimes #define DP_DEFSET 0x1 108a62dc406SDoug Rabson #define DP_HOSTSET 0x2 1098fae3551SRodney W. Grimes 1108fae3551SRodney W. Grimes struct exportlist { 1118fae3551SRodney W. Grimes struct exportlist *ex_next; 1128fae3551SRodney W. Grimes struct dirlist *ex_dirl; 1138fae3551SRodney W. Grimes struct dirlist *ex_defdir; 1148fae3551SRodney W. Grimes int ex_flag; 1158fae3551SRodney W. Grimes fsid_t ex_fs; 1168fae3551SRodney W. Grimes char *ex_fsdir; 117cb3923e0SDoug Rabson char *ex_indexfile; 118a9148abdSDoug Rabson int ex_numsecflavors; 119a9148abdSDoug Rabson int ex_secflavors[MAXSECFLAVORS]; 1208fae3551SRodney W. Grimes }; 1218fae3551SRodney W. Grimes /* ex_flag bits */ 1228fae3551SRodney W. Grimes #define EX_LINKED 0x1 1238fae3551SRodney W. Grimes 1248fae3551SRodney W. Grimes struct netmsk { 1258360efbdSAlfred Perlstein struct sockaddr_storage nt_net; 12660caaee2SIan Dowse struct sockaddr_storage nt_mask; 1278fae3551SRodney W. Grimes char *nt_name; 1288fae3551SRodney W. Grimes }; 1298fae3551SRodney W. Grimes 1308fae3551SRodney W. Grimes union grouptypes { 1318360efbdSAlfred Perlstein struct addrinfo *gt_addrinfo; 1328fae3551SRodney W. Grimes struct netmsk gt_net; 1338fae3551SRodney W. Grimes }; 1348fae3551SRodney W. Grimes 1358fae3551SRodney W. Grimes struct grouplist { 1368fae3551SRodney W. Grimes int gr_type; 1378fae3551SRodney W. Grimes union grouptypes gr_ptr; 1388fae3551SRodney W. Grimes struct grouplist *gr_next; 1398fae3551SRodney W. Grimes }; 1408fae3551SRodney W. Grimes /* Group types */ 1418fae3551SRodney W. Grimes #define GT_NULL 0x0 1428fae3551SRodney W. Grimes #define GT_HOST 0x1 1438fae3551SRodney W. Grimes #define GT_NET 0x2 1446d359f31SIan Dowse #define GT_DEFAULT 0x3 1458b5a6d67SBill Paul #define GT_IGNORE 0x5 1468fae3551SRodney W. Grimes 1478fae3551SRodney W. Grimes struct hostlist { 148a62dc406SDoug Rabson int ht_flag; /* Uses DP_xx bits */ 1498fae3551SRodney W. Grimes struct grouplist *ht_grp; 1508fae3551SRodney W. Grimes struct hostlist *ht_next; 1518fae3551SRodney W. Grimes }; 1528fae3551SRodney W. Grimes 153a62dc406SDoug Rabson struct fhreturn { 154a62dc406SDoug Rabson int fhr_flag; 155a62dc406SDoug Rabson int fhr_vers; 156a62dc406SDoug Rabson nfsfh_t fhr_fh; 157a9148abdSDoug Rabson int fhr_numsecflavors; 158a9148abdSDoug Rabson int *fhr_secflavors; 159a62dc406SDoug Rabson }; 160a62dc406SDoug Rabson 1618fae3551SRodney W. Grimes /* Global defs */ 16285429990SWarner Losh char *add_expdir(struct dirlist **, char *, int); 16385429990SWarner Losh void add_dlist(struct dirlist **, struct dirlist *, 16485429990SWarner Losh struct grouplist *, int); 16585429990SWarner Losh void add_mlist(char *, char *); 16685429990SWarner Losh int check_dirpath(char *); 16785429990SWarner Losh int check_options(struct dirlist *); 16860caaee2SIan Dowse int checkmask(struct sockaddr *sa); 16985429990SWarner Losh int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 170d11e3645SMatteo Riondato void create_service(struct netconfig *nconf); 17101709abfSIan Dowse void del_mlist(char *hostp, char *dirp); 17285429990SWarner Losh struct dirlist *dirp_search(struct dirlist *, char *); 17385429990SWarner Losh int do_mount(struct exportlist *, struct grouplist *, int, 17485429990SWarner Losh struct xucred *, char *, int, struct statfs *); 17585429990SWarner Losh int do_opt(char **, char **, struct exportlist *, struct grouplist *, 17685429990SWarner Losh int *, int *, struct xucred *); 17785429990SWarner Losh struct exportlist *ex_search(fsid_t *); 17885429990SWarner Losh struct exportlist *get_exp(void); 17985429990SWarner Losh void free_dir(struct dirlist *); 18085429990SWarner Losh void free_exp(struct exportlist *); 18185429990SWarner Losh void free_grp(struct grouplist *); 18285429990SWarner Losh void free_host(struct hostlist *); 18385429990SWarner Losh void get_exportlist(void); 18485429990SWarner Losh int get_host(char *, struct grouplist *, struct grouplist *); 18585429990SWarner Losh struct hostlist *get_ht(void); 18685429990SWarner Losh int get_line(void); 18785429990SWarner Losh void get_mountlist(void); 18885429990SWarner Losh int get_net(char *, struct netmsk *, int); 18985429990SWarner Losh void getexp_err(struct exportlist *, struct grouplist *); 19085429990SWarner Losh struct grouplist *get_grp(void); 19185429990SWarner Losh void hang_dirp(struct dirlist *, struct grouplist *, 19285429990SWarner Losh struct exportlist *, int); 19369d65572SIan Dowse void huphandler(int sig); 19460caaee2SIan Dowse int makemask(struct sockaddr_storage *ssp, int bitlen); 19585429990SWarner Losh void mntsrv(struct svc_req *, SVCXPRT *); 19685429990SWarner Losh void nextfield(char **, char **); 19785429990SWarner Losh void out_of_mem(void); 19885429990SWarner Losh void parsecred(char *, struct xucred *); 199a7a7d96cSPhilippe Charnier int parsesec(char *, struct exportlist *); 20091acb349SAlfred Perlstein int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 20160caaee2SIan Dowse void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 20260caaee2SIan Dowse int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20360caaee2SIan Dowse struct sockaddr *samask); 20485429990SWarner Losh int scan_tree(struct dirlist *, struct sockaddr *); 20585429990SWarner Losh static void usage(void); 20685429990SWarner Losh int xdr_dir(XDR *, char *); 20785429990SWarner Losh int xdr_explist(XDR *, caddr_t); 20891acb349SAlfred Perlstein int xdr_explist_brief(XDR *, caddr_t); 209a7a7d96cSPhilippe Charnier int xdr_explist_common(XDR *, caddr_t, int); 21085429990SWarner Losh int xdr_fhs(XDR *, caddr_t); 21185429990SWarner Losh int xdr_mlist(XDR *, caddr_t); 21285429990SWarner Losh void terminate(int); 2138fae3551SRodney W. Grimes 2148fae3551SRodney W. Grimes struct exportlist *exphead; 2158fae3551SRodney W. Grimes struct mountlist *mlhead; 2168fae3551SRodney W. Grimes struct grouplist *grphead; 21796968c22SPawel Jakub Dawidek char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 21896968c22SPawel Jakub Dawidek char **exnames; 219d11e3645SMatteo Riondato char **hosts = NULL; 220c0511d3bSBrian Feldman struct xucred def_anon = { 22176183f34SDima Dorfman XUCRED_VERSION, 2228fae3551SRodney W. Grimes (uid_t)-2, 2238fae3551SRodney W. Grimes 1, 224c0511d3bSBrian Feldman { (gid_t)-2 }, 225c0511d3bSBrian Feldman NULL 2268fae3551SRodney W. Grimes }; 2272a66cfc5SDoug Rabson int force_v2 = 0; 228a62dc406SDoug Rabson int resvport_only = 1; 229d11e3645SMatteo Riondato int nhosts = 0; 230a62dc406SDoug Rabson int dir_only = 1; 231c903443aSPeter Wemm int dolog = 0; 23269d65572SIan Dowse int got_sighup = 0; 233d11e3645SMatteo Riondato int xcreated = 0; 234d11e3645SMatteo Riondato 235d11e3645SMatteo Riondato char *svcport_str = NULL; 2368360efbdSAlfred Perlstein 2378fae3551SRodney W. Grimes int opt_flags; 2388360efbdSAlfred Perlstein static int have_v6 = 1; 2398360efbdSAlfred Perlstein 240bcc1d071SRick Macklem int v4root_phase = 0; 241bcc1d071SRick Macklem char v4root_dirpath[PATH_MAX + 1]; 242bcc1d071SRick Macklem int run_v4server = 0; 243bcc1d071SRick Macklem int has_publicfh = 0; 244bcc1d071SRick Macklem 245a032b226SPawel Jakub Dawidek struct pidfh *pfh = NULL; 24660caaee2SIan Dowse /* Bits for opt_flags above */ 2478fae3551SRodney W. Grimes #define OP_MAPROOT 0x01 2488fae3551SRodney W. Grimes #define OP_MAPALL 0x02 24991196234SPeter Wemm /* 0x4 free */ 2508fae3551SRodney W. Grimes #define OP_MASK 0x08 2518fae3551SRodney W. Grimes #define OP_NET 0x10 2528fae3551SRodney W. Grimes #define OP_ALLDIRS 0x40 25360caaee2SIan Dowse #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 254288fa14aSJoerg Wunsch #define OP_QUIET 0x100 2558360efbdSAlfred Perlstein #define OP_MASKLEN 0x200 256a9148abdSDoug Rabson #define OP_SEC 0x400 2578fae3551SRodney W. Grimes 2588fae3551SRodney W. Grimes #ifdef DEBUG 2598fae3551SRodney W. Grimes int debug = 1; 26085429990SWarner Losh void SYSLOG(int, const char *, ...) __printflike(2, 3); 2618fae3551SRodney W. Grimes #define syslog SYSLOG 2628fae3551SRodney W. Grimes #else 2638fae3551SRodney W. Grimes int debug = 0; 2648fae3551SRodney W. Grimes #endif 2658fae3551SRodney W. Grimes 2668fae3551SRodney W. Grimes /* 2678fae3551SRodney W. Grimes * Mountd server for NFS mount protocol as described in: 2688fae3551SRodney W. Grimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2698fae3551SRodney W. Grimes * The optional arguments are the exports file name 2708fae3551SRodney W. Grimes * default: _PATH_EXPORTS 2718fae3551SRodney W. Grimes * and "-n" to allow nonroot mount. 2728fae3551SRodney W. Grimes */ 2738fae3551SRodney W. Grimes int 274a7a7d96cSPhilippe Charnier main(int argc, char **argv) 2758fae3551SRodney W. Grimes { 27669d65572SIan Dowse fd_set readfds; 277d11e3645SMatteo Riondato struct netconfig *nconf; 278d11e3645SMatteo Riondato char *endptr, **hosts_bak; 279d11e3645SMatteo Riondato void *nc_handle; 280a032b226SPawel Jakub Dawidek pid_t otherpid; 281d11e3645SMatteo Riondato in_port_t svcport; 282d11e3645SMatteo Riondato int c, k, s; 283bcb53b16SMartin Blapp int maxrec = RPC_MAXDATASIZE; 2848360efbdSAlfred Perlstein 28501709abfSIan Dowse /* Check that another mountd isn't already running. */ 2868b28aef2SPawel Jakub Dawidek pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 287a032b226SPawel Jakub Dawidek if (pfh == NULL) { 288a032b226SPawel Jakub Dawidek if (errno == EEXIST) 289a032b226SPawel Jakub Dawidek errx(1, "mountd already running, pid: %d.", otherpid); 290a032b226SPawel Jakub Dawidek warn("cannot open or create pidfile"); 291a032b226SPawel Jakub Dawidek } 2928360efbdSAlfred Perlstein 2938360efbdSAlfred Perlstein s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 2948360efbdSAlfred Perlstein if (s < 0) 2958360efbdSAlfred Perlstein have_v6 = 0; 2968360efbdSAlfred Perlstein else 2978360efbdSAlfred Perlstein close(s); 2988fae3551SRodney W. Grimes 2992179ae1eSRick Macklem while ((c = getopt(argc, argv, "2deh:lnp:r")) != -1) 3008fae3551SRodney W. Grimes switch (c) { 3012a66cfc5SDoug Rabson case '2': 3022a66cfc5SDoug Rabson force_v2 = 1; 3032a66cfc5SDoug Rabson break; 3042179ae1eSRick Macklem case 'e': 305bcc1d071SRick Macklem run_v4server = 1; 306bcc1d071SRick Macklem break; 307a62dc406SDoug Rabson case 'n': 308a62dc406SDoug Rabson resvport_only = 0; 309a62dc406SDoug Rabson break; 310a62dc406SDoug Rabson case 'r': 311a62dc406SDoug Rabson dir_only = 0; 312a62dc406SDoug Rabson break; 3136444ef3bSPoul-Henning Kamp case 'd': 3146444ef3bSPoul-Henning Kamp debug = debug ? 0 : 1; 3156444ef3bSPoul-Henning Kamp break; 316f51631d7SGuido van Rooij case 'l': 317c903443aSPeter Wemm dolog = 1; 318f51631d7SGuido van Rooij break; 319c203da27SBruce M Simpson case 'p': 320c203da27SBruce M Simpson endptr = NULL; 321c203da27SBruce M Simpson svcport = (in_port_t)strtoul(optarg, &endptr, 10); 322c203da27SBruce M Simpson if (endptr == NULL || *endptr != '\0' || 323c203da27SBruce M Simpson svcport == 0 || svcport >= IPPORT_MAX) 324c203da27SBruce M Simpson usage(); 325d11e3645SMatteo Riondato svcport_str = strdup(optarg); 326d11e3645SMatteo Riondato break; 327d11e3645SMatteo Riondato case 'h': 328d11e3645SMatteo Riondato ++nhosts; 329d11e3645SMatteo Riondato hosts_bak = hosts; 330d11e3645SMatteo Riondato hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 331d11e3645SMatteo Riondato if (hosts_bak == NULL) { 332d11e3645SMatteo Riondato if (hosts != NULL) { 333d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 334d11e3645SMatteo Riondato free(hosts[k]); 335d11e3645SMatteo Riondato free(hosts); 336d11e3645SMatteo Riondato out_of_mem(); 337d11e3645SMatteo Riondato } 338d11e3645SMatteo Riondato } 339d11e3645SMatteo Riondato hosts = hosts_bak; 340d11e3645SMatteo Riondato hosts[nhosts - 1] = strdup(optarg); 341d11e3645SMatteo Riondato if (hosts[nhosts - 1] == NULL) { 342d11e3645SMatteo Riondato for (k = 0; k < (nhosts - 1); k++) 343d11e3645SMatteo Riondato free(hosts[k]); 344d11e3645SMatteo Riondato free(hosts); 345d11e3645SMatteo Riondato out_of_mem(); 346d11e3645SMatteo Riondato } 347c203da27SBruce M Simpson break; 3488fae3551SRodney W. Grimes default: 34974853402SPhilippe Charnier usage(); 3508fae3551SRodney W. Grimes }; 351bcc1d071SRick Macklem 352bcc1d071SRick Macklem /* 3532179ae1eSRick Macklem * If the "-e" option was specified OR only the nfsd module is 354bcc1d071SRick Macklem * found in the server, run "nfsd". 355bcc1d071SRick Macklem * Otherwise, try and run "nfsserver". 356bcc1d071SRick Macklem */ 357bcc1d071SRick Macklem if (run_v4server > 0) { 358bcc1d071SRick Macklem if (modfind("nfsd") < 0) { 359bcc1d071SRick Macklem /* Not present in kernel, try loading it */ 360bcc1d071SRick Macklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 361bcc1d071SRick Macklem errx(1, "NFS server is not available"); 362bcc1d071SRick Macklem } 363bcc1d071SRick Macklem } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { 364bcc1d071SRick Macklem run_v4server = 1; 365bcc1d071SRick Macklem } else if (modfind("nfsserver") < 0) { 366bcc1d071SRick Macklem /* Not present in kernel, try loading it */ 367bcc1d071SRick Macklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 368bcc1d071SRick Macklem errx(1, "NFS server is not available"); 369bcc1d071SRick Macklem } 370bcc1d071SRick Macklem 3718fae3551SRodney W. Grimes argc -= optind; 3728fae3551SRodney W. Grimes argv += optind; 3738fae3551SRodney W. Grimes grphead = (struct grouplist *)NULL; 3748fae3551SRodney W. Grimes exphead = (struct exportlist *)NULL; 3758fae3551SRodney W. Grimes mlhead = (struct mountlist *)NULL; 37696968c22SPawel Jakub Dawidek if (argc > 0) 37796968c22SPawel Jakub Dawidek exnames = argv; 37896968c22SPawel Jakub Dawidek else 37996968c22SPawel Jakub Dawidek exnames = exnames_default; 3808fae3551SRodney W. Grimes openlog("mountd", LOG_PID, LOG_DAEMON); 3818fae3551SRodney W. Grimes if (debug) 38274853402SPhilippe Charnier warnx("getting export list"); 3838fae3551SRodney W. Grimes get_exportlist(); 3848fae3551SRodney W. Grimes if (debug) 38574853402SPhilippe Charnier warnx("getting mount list"); 3868fae3551SRodney W. Grimes get_mountlist(); 3878fae3551SRodney W. Grimes if (debug) 38874853402SPhilippe Charnier warnx("here we go"); 3898fae3551SRodney W. Grimes if (debug == 0) { 3908fae3551SRodney W. Grimes daemon(0, 0); 3918fae3551SRodney W. Grimes signal(SIGINT, SIG_IGN); 3928fae3551SRodney W. Grimes signal(SIGQUIT, SIG_IGN); 3938fae3551SRodney W. Grimes } 39469d65572SIan Dowse signal(SIGHUP, huphandler); 3958360efbdSAlfred Perlstein signal(SIGTERM, terminate); 39609fc9dc6SCraig Rodrigues signal(SIGPIPE, SIG_IGN); 397a032b226SPawel Jakub Dawidek 398a032b226SPawel Jakub Dawidek pidfile_write(pfh); 399a032b226SPawel Jakub Dawidek 4000775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 4010775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 402bcb53b16SMartin Blapp rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 403bcb53b16SMartin Blapp 404c6e5e158SGuido van Rooij if (!resvport_only) { 4054a0785aaSPeter Wemm if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 4064a0785aaSPeter Wemm &resvport_only, sizeof(resvport_only)) != 0 && 4074a0785aaSPeter Wemm errno != ENOENT) { 408394da4c1SGuido van Rooij syslog(LOG_ERR, "sysctl: %m"); 409394da4c1SGuido van Rooij exit(1); 410394da4c1SGuido van Rooij } 411c6e5e158SGuido van Rooij } 412c203da27SBruce M Simpson 413d11e3645SMatteo Riondato /* 414d11e3645SMatteo Riondato * If no hosts were specified, add a wildcard entry to bind to 415d11e3645SMatteo Riondato * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 416d11e3645SMatteo Riondato * list. 417d11e3645SMatteo Riondato */ 418d11e3645SMatteo Riondato if (nhosts == 0) { 419d11e3645SMatteo Riondato hosts = malloc(sizeof(char**)); 420d11e3645SMatteo Riondato if (hosts == NULL) 421d11e3645SMatteo Riondato out_of_mem(); 422d11e3645SMatteo Riondato hosts[0] = "*"; 423d11e3645SMatteo Riondato nhosts = 1; 424d11e3645SMatteo Riondato } else { 425d11e3645SMatteo Riondato hosts_bak = hosts; 426d11e3645SMatteo Riondato if (have_v6) { 427d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 2) * 428d11e3645SMatteo Riondato sizeof(char *)); 429d11e3645SMatteo Riondato if (hosts_bak == NULL) { 430d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 431d11e3645SMatteo Riondato free(hosts[k]); 432d11e3645SMatteo Riondato free(hosts); 433d11e3645SMatteo Riondato out_of_mem(); 434c203da27SBruce M Simpson } else 435d11e3645SMatteo Riondato hosts = hosts_bak; 436d11e3645SMatteo Riondato nhosts += 2; 437d11e3645SMatteo Riondato hosts[nhosts - 2] = "::1"; 438d11e3645SMatteo Riondato } else { 439d11e3645SMatteo Riondato hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 440d11e3645SMatteo Riondato if (hosts_bak == NULL) { 441d11e3645SMatteo Riondato for (k = 0; k < nhosts; k++) 442d11e3645SMatteo Riondato free(hosts[k]); 443d11e3645SMatteo Riondato free(hosts); 444d11e3645SMatteo Riondato out_of_mem(); 445d11e3645SMatteo Riondato } else { 446d11e3645SMatteo Riondato nhosts += 1; 447d11e3645SMatteo Riondato hosts = hosts_bak; 4488fae3551SRodney W. Grimes } 449d11e3645SMatteo Riondato } 4508360efbdSAlfred Perlstein 451d11e3645SMatteo Riondato hosts[nhosts - 1] = "127.0.0.1"; 4528360efbdSAlfred Perlstein } 4538360efbdSAlfred Perlstein 454d11e3645SMatteo Riondato nc_handle = setnetconfig(); 455d11e3645SMatteo Riondato while ((nconf = getnetconfig(nc_handle))) { 456d11e3645SMatteo Riondato if (nconf->nc_flag & NC_VISIBLE) { 457d11e3645SMatteo Riondato if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 458d11e3645SMatteo Riondato "inet6") == 0) { 459d11e3645SMatteo Riondato /* DO NOTHING */ 460c203da27SBruce M Simpson } else 461d11e3645SMatteo Riondato create_service(nconf); 4628360efbdSAlfred Perlstein } 463d11e3645SMatteo Riondato } 464d11e3645SMatteo Riondato endnetconfig(nc_handle); 4658360efbdSAlfred Perlstein 4668360efbdSAlfred Perlstein if (xcreated == 0) { 4678360efbdSAlfred Perlstein syslog(LOG_ERR, "could not create any services"); 4682a66cfc5SDoug Rabson exit(1); 4692a66cfc5SDoug Rabson } 47069d65572SIan Dowse 47169d65572SIan Dowse /* Expand svc_run() here so that we can call get_exportlist(). */ 47269d65572SIan Dowse for (;;) { 47369d65572SIan Dowse if (got_sighup) { 47469d65572SIan Dowse get_exportlist(); 47569d65572SIan Dowse got_sighup = 0; 47669d65572SIan Dowse } 47769d65572SIan Dowse readfds = svc_fdset; 47869d65572SIan Dowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 47969d65572SIan Dowse case -1: 48069d65572SIan Dowse if (errno == EINTR) 48169d65572SIan Dowse continue; 48269d65572SIan Dowse syslog(LOG_ERR, "mountd died: select: %m"); 48374853402SPhilippe Charnier exit(1); 48469d65572SIan Dowse case 0: 48569d65572SIan Dowse continue; 48669d65572SIan Dowse default: 48769d65572SIan Dowse svc_getreqset(&readfds); 48869d65572SIan Dowse } 48969d65572SIan Dowse } 49074853402SPhilippe Charnier } 49174853402SPhilippe Charnier 492d11e3645SMatteo Riondato /* 493d11e3645SMatteo Riondato * This routine creates and binds sockets on the appropriate 494d11e3645SMatteo Riondato * addresses. It gets called one time for each transport and 495d11e3645SMatteo Riondato * registrates the service with rpcbind on that trasport. 496d11e3645SMatteo Riondato */ 497d11e3645SMatteo Riondato void 498d11e3645SMatteo Riondato create_service(struct netconfig *nconf) 499d11e3645SMatteo Riondato { 500d11e3645SMatteo Riondato struct addrinfo hints, *res = NULL; 501d11e3645SMatteo Riondato struct sockaddr_in *sin; 502d11e3645SMatteo Riondato struct sockaddr_in6 *sin6; 503d11e3645SMatteo Riondato struct __rpc_sockinfo si; 504d11e3645SMatteo Riondato struct netbuf servaddr; 505d11e3645SMatteo Riondato SVCXPRT *transp = NULL; 506d11e3645SMatteo Riondato int aicode; 507d11e3645SMatteo Riondato int fd; 508d11e3645SMatteo Riondato int nhostsbak; 509d11e3645SMatteo Riondato int one = 1; 510d11e3645SMatteo Riondato int r; 511d11e3645SMatteo Riondato int registered = 0; 512d11e3645SMatteo Riondato u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 513d11e3645SMatteo Riondato 514d11e3645SMatteo Riondato if ((nconf->nc_semantics != NC_TPI_CLTS) && 515d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS) && 516d11e3645SMatteo Riondato (nconf->nc_semantics != NC_TPI_COTS_ORD)) 517d11e3645SMatteo Riondato return; /* not my type */ 518d11e3645SMatteo Riondato 519d11e3645SMatteo Riondato /* 520d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 521d11e3645SMatteo Riondato */ 522d11e3645SMatteo Riondato if (!__rpc_nconf2sockinfo(nconf, &si)) { 523d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get information for %s", 524d11e3645SMatteo Riondato nconf->nc_netid); 525d11e3645SMatteo Riondato return; 526d11e3645SMatteo Riondato } 527d11e3645SMatteo Riondato 528d11e3645SMatteo Riondato /* Get mountd's address on this transport */ 529d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 530d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE; 531d11e3645SMatteo Riondato hints.ai_family = si.si_af; 532d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 533d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 534d11e3645SMatteo Riondato 535d11e3645SMatteo Riondato /* 536d11e3645SMatteo Riondato * Bind to specific IPs if asked to 537d11e3645SMatteo Riondato */ 538d11e3645SMatteo Riondato nhostsbak = nhosts; 539d11e3645SMatteo Riondato while (nhostsbak > 0) { 540d11e3645SMatteo Riondato --nhostsbak; 541d11e3645SMatteo Riondato /* 542d11e3645SMatteo Riondato * XXX - using RPC library internal functions. 543d11e3645SMatteo Riondato */ 544d11e3645SMatteo Riondato if ((fd = __rpc_nconf2fd(nconf)) < 0) { 545d11e3645SMatteo Riondato int non_fatal = 0; 546d11e3645SMatteo Riondato if (errno == EPROTONOSUPPORT && 547d11e3645SMatteo Riondato nconf->nc_semantics != NC_TPI_CLTS) 548d11e3645SMatteo Riondato non_fatal = 1; 549d11e3645SMatteo Riondato 550d11e3645SMatteo Riondato syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 551d11e3645SMatteo Riondato "cannot create socket for %s", nconf->nc_netid); 552d11e3645SMatteo Riondato return; 553d11e3645SMatteo Riondato } 554d11e3645SMatteo Riondato 555d11e3645SMatteo Riondato switch (hints.ai_family) { 556d11e3645SMatteo Riondato case AF_INET: 557d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 558d11e3645SMatteo Riondato host_addr) == 1) { 559d11e3645SMatteo Riondato hints.ai_flags &= AI_NUMERICHOST; 560d11e3645SMatteo Riondato } else { 561d11e3645SMatteo Riondato /* 562d11e3645SMatteo Riondato * Skip if we have an AF_INET6 address. 563d11e3645SMatteo Riondato */ 564d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 565d11e3645SMatteo Riondato host_addr) == 1) { 566d11e3645SMatteo Riondato close(fd); 567d11e3645SMatteo Riondato continue; 568d11e3645SMatteo Riondato } 569d11e3645SMatteo Riondato } 570d11e3645SMatteo Riondato break; 571d11e3645SMatteo Riondato case AF_INET6: 572d11e3645SMatteo Riondato if (inet_pton(AF_INET6, hosts[nhostsbak], 573d11e3645SMatteo Riondato host_addr) == 1) { 574d11e3645SMatteo Riondato hints.ai_flags &= AI_NUMERICHOST; 575d11e3645SMatteo Riondato } else { 576d11e3645SMatteo Riondato /* 577d11e3645SMatteo Riondato * Skip if we have an AF_INET address. 578d11e3645SMatteo Riondato */ 579d11e3645SMatteo Riondato if (inet_pton(AF_INET, hosts[nhostsbak], 580d11e3645SMatteo Riondato host_addr) == 1) { 581d11e3645SMatteo Riondato close(fd); 582d11e3645SMatteo Riondato continue; 583d11e3645SMatteo Riondato } 584d11e3645SMatteo Riondato } 585d11e3645SMatteo Riondato 586d11e3645SMatteo Riondato /* 587d11e3645SMatteo Riondato * We're doing host-based access checks here, so don't 588d11e3645SMatteo Riondato * allow v4-in-v6 to confuse things. The kernel will 589d11e3645SMatteo Riondato * disable it by default on NFS sockets too. 590d11e3645SMatteo Riondato */ 591d11e3645SMatteo Riondato if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 592d11e3645SMatteo Riondato sizeof one) < 0) { 593d11e3645SMatteo Riondato syslog(LOG_ERR, 594d11e3645SMatteo Riondato "can't disable v4-in-v6 on IPv6 socket"); 595d11e3645SMatteo Riondato exit(1); 596d11e3645SMatteo Riondato } 597d11e3645SMatteo Riondato break; 598d11e3645SMatteo Riondato default: 599d11e3645SMatteo Riondato break; 600d11e3645SMatteo Riondato } 601d11e3645SMatteo Riondato 602d11e3645SMatteo Riondato /* 603d11e3645SMatteo Riondato * If no hosts were specified, just bind to INADDR_ANY 604d11e3645SMatteo Riondato */ 605d11e3645SMatteo Riondato if (strcmp("*", hosts[nhostsbak]) == 0) { 606d11e3645SMatteo Riondato if (svcport_str == NULL) { 607d11e3645SMatteo Riondato res = malloc(sizeof(struct addrinfo)); 608d11e3645SMatteo Riondato if (res == NULL) 609d11e3645SMatteo Riondato out_of_mem(); 610d11e3645SMatteo Riondato res->ai_flags = hints.ai_flags; 611d11e3645SMatteo Riondato res->ai_family = hints.ai_family; 612d11e3645SMatteo Riondato res->ai_protocol = hints.ai_protocol; 613d11e3645SMatteo Riondato switch (res->ai_family) { 614d11e3645SMatteo Riondato case AF_INET: 615d11e3645SMatteo Riondato sin = malloc(sizeof(struct sockaddr_in)); 616d11e3645SMatteo Riondato if (sin == NULL) 617d11e3645SMatteo Riondato out_of_mem(); 618d11e3645SMatteo Riondato sin->sin_family = AF_INET; 619d11e3645SMatteo Riondato sin->sin_port = htons(0); 620d11e3645SMatteo Riondato sin->sin_addr.s_addr = htonl(INADDR_ANY); 621d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin; 622d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 623d11e3645SMatteo Riondato sizeof(res->ai_addr); 624d11e3645SMatteo Riondato break; 625d11e3645SMatteo Riondato case AF_INET6: 626d11e3645SMatteo Riondato sin6 = malloc(sizeof(struct sockaddr_in6)); 62789ca9145SSimon L. B. Nielsen if (sin6 == NULL) 628d11e3645SMatteo Riondato out_of_mem(); 629d11e3645SMatteo Riondato sin6->sin6_family = AF_INET6; 630d11e3645SMatteo Riondato sin6->sin6_port = htons(0); 631d11e3645SMatteo Riondato sin6->sin6_addr = in6addr_any; 632d11e3645SMatteo Riondato res->ai_addr = (struct sockaddr*) sin6; 633d11e3645SMatteo Riondato res->ai_addrlen = (socklen_t) 634d11e3645SMatteo Riondato sizeof(res->ai_addr); 635d11e3645SMatteo Riondato break; 636d11e3645SMatteo Riondato default: 637d11e3645SMatteo Riondato break; 638d11e3645SMatteo Riondato } 639d11e3645SMatteo Riondato } else { 640d11e3645SMatteo Riondato if ((aicode = getaddrinfo(NULL, svcport_str, 641d11e3645SMatteo Riondato &hints, &res)) != 0) { 642d11e3645SMatteo Riondato syslog(LOG_ERR, 643d11e3645SMatteo Riondato "cannot get local address for %s: %s", 644d11e3645SMatteo Riondato nconf->nc_netid, 645d11e3645SMatteo Riondato gai_strerror(aicode)); 646d11e3645SMatteo Riondato continue; 647d11e3645SMatteo Riondato } 648d11e3645SMatteo Riondato } 649d11e3645SMatteo Riondato } else { 650d11e3645SMatteo Riondato if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 651d11e3645SMatteo Riondato &hints, &res)) != 0) { 652d11e3645SMatteo Riondato syslog(LOG_ERR, 653d11e3645SMatteo Riondato "cannot get local address for %s: %s", 654d11e3645SMatteo Riondato nconf->nc_netid, gai_strerror(aicode)); 655d11e3645SMatteo Riondato continue; 656d11e3645SMatteo Riondato } 657d11e3645SMatteo Riondato } 658d11e3645SMatteo Riondato 659d11e3645SMatteo Riondato r = bindresvport_sa(fd, res->ai_addr); 660d11e3645SMatteo Riondato if (r != 0) { 661d11e3645SMatteo Riondato syslog(LOG_ERR, "bindresvport_sa: %m"); 662d11e3645SMatteo Riondato exit(1); 663d11e3645SMatteo Riondato } 664d11e3645SMatteo Riondato 665d11e3645SMatteo Riondato if (nconf->nc_semantics != NC_TPI_CLTS) 666d11e3645SMatteo Riondato listen(fd, SOMAXCONN); 667d11e3645SMatteo Riondato 668d11e3645SMatteo Riondato if (nconf->nc_semantics == NC_TPI_CLTS ) 669d11e3645SMatteo Riondato transp = svc_dg_create(fd, 0, 0); 670d11e3645SMatteo Riondato else 671d11e3645SMatteo Riondato transp = svc_vc_create(fd, RPC_MAXDATASIZE, 672d11e3645SMatteo Riondato RPC_MAXDATASIZE); 673d11e3645SMatteo Riondato 674d11e3645SMatteo Riondato if (transp != (SVCXPRT *) NULL) { 6750775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 676d11e3645SMatteo Riondato NULL)) 677d11e3645SMatteo Riondato syslog(LOG_ERR, 6780775314bSDoug Rabson "can't register %s MOUNTVERS service", 679d11e3645SMatteo Riondato nconf->nc_netid); 680d11e3645SMatteo Riondato if (!force_v2) { 6810775314bSDoug Rabson if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 682d11e3645SMatteo Riondato mntsrv, NULL)) 683d11e3645SMatteo Riondato syslog(LOG_ERR, 6840775314bSDoug Rabson "can't register %s MOUNTVERS3 service", 685d11e3645SMatteo Riondato nconf->nc_netid); 686d11e3645SMatteo Riondato } 687d11e3645SMatteo Riondato } else 688d11e3645SMatteo Riondato syslog(LOG_WARNING, "can't create %s services", 689d11e3645SMatteo Riondato nconf->nc_netid); 690d11e3645SMatteo Riondato 691d11e3645SMatteo Riondato if (registered == 0) { 692d11e3645SMatteo Riondato registered = 1; 693d11e3645SMatteo Riondato memset(&hints, 0, sizeof hints); 694d11e3645SMatteo Riondato hints.ai_flags = AI_PASSIVE; 695d11e3645SMatteo Riondato hints.ai_family = si.si_af; 696d11e3645SMatteo Riondato hints.ai_socktype = si.si_socktype; 697d11e3645SMatteo Riondato hints.ai_protocol = si.si_proto; 698d11e3645SMatteo Riondato 699d11e3645SMatteo Riondato if (svcport_str == NULL) { 700d11e3645SMatteo Riondato svcport_str = malloc(NI_MAXSERV * sizeof(char)); 701d11e3645SMatteo Riondato if (svcport_str == NULL) 702d11e3645SMatteo Riondato out_of_mem(); 703d11e3645SMatteo Riondato 704d11e3645SMatteo Riondato if (getnameinfo(res->ai_addr, 705d11e3645SMatteo Riondato res->ai_addr->sa_len, NULL, NI_MAXHOST, 706d11e3645SMatteo Riondato svcport_str, NI_MAXSERV * sizeof(char), 707d11e3645SMatteo Riondato NI_NUMERICHOST | NI_NUMERICSERV)) 708d11e3645SMatteo Riondato errx(1, "Cannot get port number"); 709d11e3645SMatteo Riondato } 710d11e3645SMatteo Riondato 711d11e3645SMatteo Riondato if((aicode = getaddrinfo(NULL, svcport_str, &hints, 712d11e3645SMatteo Riondato &res)) != 0) { 713d11e3645SMatteo Riondato syslog(LOG_ERR, "cannot get local address: %s", 714d11e3645SMatteo Riondato gai_strerror(aicode)); 715d11e3645SMatteo Riondato exit(1); 716d11e3645SMatteo Riondato } 717d11e3645SMatteo Riondato 718d11e3645SMatteo Riondato servaddr.buf = malloc(res->ai_addrlen); 719d11e3645SMatteo Riondato memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 720d11e3645SMatteo Riondato servaddr.len = res->ai_addrlen; 721d11e3645SMatteo Riondato 7220775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 7230775314bSDoug Rabson rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 724d11e3645SMatteo Riondato 725d11e3645SMatteo Riondato xcreated++; 726d11e3645SMatteo Riondato freeaddrinfo(res); 727d11e3645SMatteo Riondato } 728d11e3645SMatteo Riondato } /* end while */ 729d11e3645SMatteo Riondato } 730d11e3645SMatteo Riondato 73174853402SPhilippe Charnier static void 732a7a7d96cSPhilippe Charnier usage(void) 73374853402SPhilippe Charnier { 73474853402SPhilippe Charnier fprintf(stderr, 7352179ae1eSRick Macklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 736d11e3645SMatteo Riondato "[-h <bindip>] [export_file ...]\n"); 7378fae3551SRodney W. Grimes exit(1); 7388fae3551SRodney W. Grimes } 7398fae3551SRodney W. Grimes 7408fae3551SRodney W. Grimes /* 7418fae3551SRodney W. Grimes * The mount rpc service 7428fae3551SRodney W. Grimes */ 7438fae3551SRodney W. Grimes void 744a7a7d96cSPhilippe Charnier mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 7458fae3551SRodney W. Grimes { 7468fae3551SRodney W. Grimes struct exportlist *ep; 7478fae3551SRodney W. Grimes struct dirlist *dp; 748a62dc406SDoug Rabson struct fhreturn fhr; 7498fae3551SRodney W. Grimes struct stat stb; 7508fae3551SRodney W. Grimes struct statfs fsb; 7518360efbdSAlfred Perlstein char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 7528360efbdSAlfred Perlstein int lookup_failed = 1; 7538360efbdSAlfred Perlstein struct sockaddr *saddr; 754a62dc406SDoug Rabson u_short sport; 7550775314bSDoug Rabson char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 756e90cdb54SGuido van Rooij int bad = 0, defset, hostset; 757a62dc406SDoug Rabson sigset_t sighup_mask; 7588fae3551SRodney W. Grimes 759a62dc406SDoug Rabson sigemptyset(&sighup_mask); 760a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 7618360efbdSAlfred Perlstein saddr = svc_getrpccaller(transp)->buf; 7628360efbdSAlfred Perlstein switch (saddr->sa_family) { 7638360efbdSAlfred Perlstein case AF_INET6: 76401709abfSIan Dowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 7658360efbdSAlfred Perlstein break; 7668360efbdSAlfred Perlstein case AF_INET: 76701709abfSIan Dowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 7688360efbdSAlfred Perlstein break; 7698360efbdSAlfred Perlstein default: 7708360efbdSAlfred Perlstein syslog(LOG_ERR, "request from unknown address family"); 7718360efbdSAlfred Perlstein return; 7728360efbdSAlfred Perlstein } 7738360efbdSAlfred Perlstein lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 7748360efbdSAlfred Perlstein NULL, 0, 0); 7758360efbdSAlfred Perlstein getnameinfo(saddr, saddr->sa_len, numerichost, 7768360efbdSAlfred Perlstein sizeof numerichost, NULL, 0, NI_NUMERICHOST); 7778fae3551SRodney W. Grimes switch (rqstp->rq_proc) { 7788fae3551SRodney W. Grimes case NULLPROC: 779389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 78074853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 7818fae3551SRodney W. Grimes return; 7820775314bSDoug Rabson case MOUNTPROC_MNT: 783a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 784f51631d7SGuido van Rooij syslog(LOG_NOTICE, 785f51631d7SGuido van Rooij "mount request from %s from unprivileged port", 7868360efbdSAlfred Perlstein numerichost); 7878fae3551SRodney W. Grimes svcerr_weakauth(transp); 7888fae3551SRodney W. Grimes return; 7898fae3551SRodney W. Grimes } 790389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 791f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable mount request from %s", 7928360efbdSAlfred Perlstein numerichost); 7938fae3551SRodney W. Grimes svcerr_decode(transp); 7948fae3551SRodney W. Grimes return; 7958fae3551SRodney W. Grimes } 7968fae3551SRodney W. Grimes 7978fae3551SRodney W. Grimes /* 7988fae3551SRodney W. Grimes * Get the real pathname and make sure it is a directory 799a62dc406SDoug Rabson * or a regular file if the -r option was specified 800a62dc406SDoug Rabson * and it exists. 8018fae3551SRodney W. Grimes */ 802cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL || 8038fae3551SRodney W. Grimes stat(dirpath, &stb) < 0 || 804a62dc406SDoug Rabson (!S_ISDIR(stb.st_mode) && 805a62dc406SDoug Rabson (dir_only || !S_ISREG(stb.st_mode))) || 8068fae3551SRodney W. Grimes statfs(dirpath, &fsb) < 0) { 8078fae3551SRodney W. Grimes chdir("/"); /* Just in case realpath doesn't */ 808f51631d7SGuido van Rooij syslog(LOG_NOTICE, 80974853402SPhilippe Charnier "mount request from %s for non existent path %s", 8108360efbdSAlfred Perlstein numerichost, dirpath); 8118fae3551SRodney W. Grimes if (debug) 81274853402SPhilippe Charnier warnx("stat failed on %s", dirpath); 813e90cdb54SGuido van Rooij bad = ENOENT; /* We will send error reply later */ 8148fae3551SRodney W. Grimes } 8158fae3551SRodney W. Grimes 8168fae3551SRodney W. Grimes /* Check in the exports list */ 817a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8188fae3551SRodney W. Grimes ep = ex_search(&fsb.f_fsid); 819a62dc406SDoug Rabson hostset = defset = 0; 820a62dc406SDoug Rabson if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 8218fae3551SRodney W. Grimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 822a62dc406SDoug Rabson chk_host(dp, saddr, &defset, &hostset)) || 8238fae3551SRodney W. Grimes (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 8248fae3551SRodney W. Grimes scan_tree(ep->ex_dirl, saddr) == 0))) { 825e90cdb54SGuido van Rooij if (bad) { 826389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 827e90cdb54SGuido van Rooij (caddr_t)&bad)) 82874853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 829e90cdb54SGuido van Rooij sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 830e90cdb54SGuido van Rooij return; 831e90cdb54SGuido van Rooij } 832a62dc406SDoug Rabson if (hostset & DP_HOSTSET) 833a62dc406SDoug Rabson fhr.fhr_flag = hostset; 834a62dc406SDoug Rabson else 835a62dc406SDoug Rabson fhr.fhr_flag = defset; 836a62dc406SDoug Rabson fhr.fhr_vers = rqstp->rq_vers; 8378fae3551SRodney W. Grimes /* Get the file handle */ 83887564113SPeter Wemm memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 839a62dc406SDoug Rabson if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 8408fae3551SRodney W. Grimes bad = errno; 84174853402SPhilippe Charnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 842389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 8438fae3551SRodney W. Grimes (caddr_t)&bad)) 84474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 845a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8468fae3551SRodney W. Grimes return; 8478fae3551SRodney W. Grimes } 848a9148abdSDoug Rabson fhr.fhr_numsecflavors = ep->ex_numsecflavors; 849a9148abdSDoug Rabson fhr.fhr_secflavors = ep->ex_secflavors; 850389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 851389b8446SPeter Wemm (caddr_t)&fhr)) 85274853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 8538360efbdSAlfred Perlstein if (!lookup_failed) 8548360efbdSAlfred Perlstein add_mlist(host, dirpath); 8558fae3551SRodney W. Grimes else 8568360efbdSAlfred Perlstein add_mlist(numerichost, dirpath); 8578fae3551SRodney W. Grimes if (debug) 85874853402SPhilippe Charnier warnx("mount successful"); 859c903443aSPeter Wemm if (dolog) 860f51631d7SGuido van Rooij syslog(LOG_NOTICE, 861f51631d7SGuido van Rooij "mount request succeeded from %s for %s", 8628360efbdSAlfred Perlstein numerichost, dirpath); 863f51631d7SGuido van Rooij } else { 8648fae3551SRodney W. Grimes bad = EACCES; 865f51631d7SGuido van Rooij syslog(LOG_NOTICE, 866f51631d7SGuido van Rooij "mount request denied from %s for %s", 8678360efbdSAlfred Perlstein numerichost, dirpath); 868f51631d7SGuido van Rooij } 869e90cdb54SGuido van Rooij 870389b8446SPeter Wemm if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 871389b8446SPeter Wemm (caddr_t)&bad)) 87274853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 873a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8748fae3551SRodney W. Grimes return; 8750775314bSDoug Rabson case MOUNTPROC_DUMP: 876389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 87774853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 878c903443aSPeter Wemm else if (dolog) 879f51631d7SGuido van Rooij syslog(LOG_NOTICE, 880f51631d7SGuido van Rooij "dump request succeeded from %s", 8818360efbdSAlfred Perlstein numerichost); 8828fae3551SRodney W. Grimes return; 8830775314bSDoug Rabson case MOUNTPROC_UMNT: 884a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 885f51631d7SGuido van Rooij syslog(LOG_NOTICE, 886f51631d7SGuido van Rooij "umount request from %s from unprivileged port", 8878360efbdSAlfred Perlstein numerichost); 8888fae3551SRodney W. Grimes svcerr_weakauth(transp); 8898fae3551SRodney W. Grimes return; 8908fae3551SRodney W. Grimes } 891389b8446SPeter Wemm if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 892f51631d7SGuido van Rooij syslog(LOG_NOTICE, "undecodable umount request from %s", 8938360efbdSAlfred Perlstein numerichost); 8948fae3551SRodney W. Grimes svcerr_decode(transp); 8958fae3551SRodney W. Grimes return; 8968fae3551SRodney W. Grimes } 897cb479b11SAlfred Perlstein if (realpath(rpcpath, dirpath) == NULL) { 898cb479b11SAlfred Perlstein syslog(LOG_NOTICE, "umount request from %s " 899cb479b11SAlfred Perlstein "for non existent path %s", 9008360efbdSAlfred Perlstein numerichost, dirpath); 901cb479b11SAlfred Perlstein } 902389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 90374853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 9048360efbdSAlfred Perlstein if (!lookup_failed) 90501709abfSIan Dowse del_mlist(host, dirpath); 90601709abfSIan Dowse del_mlist(numerichost, dirpath); 907c903443aSPeter Wemm if (dolog) 908f51631d7SGuido van Rooij syslog(LOG_NOTICE, 909f51631d7SGuido van Rooij "umount request succeeded from %s for %s", 9108360efbdSAlfred Perlstein numerichost, dirpath); 9118fae3551SRodney W. Grimes return; 9120775314bSDoug Rabson case MOUNTPROC_UMNTALL: 913a62dc406SDoug Rabson if (sport >= IPPORT_RESERVED && resvport_only) { 914f51631d7SGuido van Rooij syslog(LOG_NOTICE, 915f51631d7SGuido van Rooij "umountall request from %s from unprivileged port", 9168360efbdSAlfred Perlstein numerichost); 9178fae3551SRodney W. Grimes svcerr_weakauth(transp); 9188fae3551SRodney W. Grimes return; 9198fae3551SRodney W. Grimes } 920389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 92174853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 9228360efbdSAlfred Perlstein if (!lookup_failed) 92301709abfSIan Dowse del_mlist(host, NULL); 92401709abfSIan Dowse del_mlist(numerichost, NULL); 925c903443aSPeter Wemm if (dolog) 926f51631d7SGuido van Rooij syslog(LOG_NOTICE, 927f51631d7SGuido van Rooij "umountall request succeeded from %s", 9288360efbdSAlfred Perlstein numerichost); 9298fae3551SRodney W. Grimes return; 9300775314bSDoug Rabson case MOUNTPROC_EXPORT: 931389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 932389b8446SPeter Wemm if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 933389b8446SPeter Wemm (caddr_t)NULL)) 93474853402SPhilippe Charnier syslog(LOG_ERR, "can't send reply"); 935c903443aSPeter Wemm if (dolog) 936f51631d7SGuido van Rooij syslog(LOG_NOTICE, 937f51631d7SGuido van Rooij "export request succeeded from %s", 9388360efbdSAlfred Perlstein numerichost); 9398fae3551SRodney W. Grimes return; 9408fae3551SRodney W. Grimes default: 9418fae3551SRodney W. Grimes svcerr_noproc(transp); 9428fae3551SRodney W. Grimes return; 9438fae3551SRodney W. Grimes } 9448fae3551SRodney W. Grimes } 9458fae3551SRodney W. Grimes 9468fae3551SRodney W. Grimes /* 9478fae3551SRodney W. Grimes * Xdr conversion for a dirpath string 9488fae3551SRodney W. Grimes */ 9498fae3551SRodney W. Grimes int 950a7a7d96cSPhilippe Charnier xdr_dir(XDR *xdrsp, char *dirp) 9518fae3551SRodney W. Grimes { 9520775314bSDoug Rabson return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 9538fae3551SRodney W. Grimes } 9548fae3551SRodney W. Grimes 9558fae3551SRodney W. Grimes /* 956a62dc406SDoug Rabson * Xdr routine to generate file handle reply 9578fae3551SRodney W. Grimes */ 9588fae3551SRodney W. Grimes int 959a7a7d96cSPhilippe Charnier xdr_fhs(XDR *xdrsp, caddr_t cp) 9608fae3551SRodney W. Grimes { 9613d438ad6SDavid E. O'Brien struct fhreturn *fhrp = (struct fhreturn *)cp; 962a62dc406SDoug Rabson u_long ok = 0, len, auth; 963a9148abdSDoug Rabson int i; 9648fae3551SRodney W. Grimes 9658fae3551SRodney W. Grimes if (!xdr_long(xdrsp, &ok)) 9668fae3551SRodney W. Grimes return (0); 967a62dc406SDoug Rabson switch (fhrp->fhr_vers) { 968a62dc406SDoug Rabson case 1: 969a62dc406SDoug Rabson return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 970a62dc406SDoug Rabson case 3: 971a62dc406SDoug Rabson len = NFSX_V3FH; 972a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 973a62dc406SDoug Rabson return (0); 974a62dc406SDoug Rabson if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 975a62dc406SDoug Rabson return (0); 976a9148abdSDoug Rabson if (fhrp->fhr_numsecflavors) { 977a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 978a9148abdSDoug Rabson return (0); 979a9148abdSDoug Rabson for (i = 0; i < fhrp->fhr_numsecflavors; i++) 980a9148abdSDoug Rabson if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 981a9148abdSDoug Rabson return (0); 982a9148abdSDoug Rabson return (1); 983a9148abdSDoug Rabson } else { 984a9148abdSDoug Rabson auth = AUTH_SYS; 985a62dc406SDoug Rabson len = 1; 986a62dc406SDoug Rabson if (!xdr_long(xdrsp, &len)) 987a62dc406SDoug Rabson return (0); 988a62dc406SDoug Rabson return (xdr_long(xdrsp, &auth)); 989a9148abdSDoug Rabson } 990a62dc406SDoug Rabson }; 991a62dc406SDoug Rabson return (0); 9928fae3551SRodney W. Grimes } 9938fae3551SRodney W. Grimes 9948fae3551SRodney W. Grimes int 995a7a7d96cSPhilippe Charnier xdr_mlist(XDR *xdrsp, caddr_t cp __unused) 9968fae3551SRodney W. Grimes { 9978fae3551SRodney W. Grimes struct mountlist *mlp; 9988fae3551SRodney W. Grimes int true = 1; 9998fae3551SRodney W. Grimes int false = 0; 10008fae3551SRodney W. Grimes char *strp; 10018fae3551SRodney W. Grimes 10028fae3551SRodney W. Grimes mlp = mlhead; 10038fae3551SRodney W. Grimes while (mlp) { 10048fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 10058fae3551SRodney W. Grimes return (0); 10068fae3551SRodney W. Grimes strp = &mlp->ml_host[0]; 10070775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 10088fae3551SRodney W. Grimes return (0); 10098fae3551SRodney W. Grimes strp = &mlp->ml_dirp[0]; 10100775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 10118fae3551SRodney W. Grimes return (0); 10128fae3551SRodney W. Grimes mlp = mlp->ml_next; 10138fae3551SRodney W. Grimes } 10148fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 10158fae3551SRodney W. Grimes return (0); 10168fae3551SRodney W. Grimes return (1); 10178fae3551SRodney W. Grimes } 10188fae3551SRodney W. Grimes 10198fae3551SRodney W. Grimes /* 10208fae3551SRodney W. Grimes * Xdr conversion for export list 10218fae3551SRodney W. Grimes */ 10228fae3551SRodney W. Grimes int 1023a7a7d96cSPhilippe Charnier xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 10248fae3551SRodney W. Grimes { 10258fae3551SRodney W. Grimes struct exportlist *ep; 10268fae3551SRodney W. Grimes int false = 0; 1027a62dc406SDoug Rabson int putdef; 1028a62dc406SDoug Rabson sigset_t sighup_mask; 10298fae3551SRodney W. Grimes 1030a62dc406SDoug Rabson sigemptyset(&sighup_mask); 1031a62dc406SDoug Rabson sigaddset(&sighup_mask, SIGHUP); 1032a62dc406SDoug Rabson sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10338fae3551SRodney W. Grimes ep = exphead; 10348fae3551SRodney W. Grimes while (ep) { 10358fae3551SRodney W. Grimes putdef = 0; 103691acb349SAlfred Perlstein if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 103791acb349SAlfred Perlstein &putdef, brief)) 10388fae3551SRodney W. Grimes goto errout; 10398fae3551SRodney W. Grimes if (ep->ex_defdir && putdef == 0 && 10408fae3551SRodney W. Grimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 104191acb349SAlfred Perlstein &putdef, brief)) 10428fae3551SRodney W. Grimes goto errout; 10438fae3551SRodney W. Grimes ep = ep->ex_next; 10448fae3551SRodney W. Grimes } 1045a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10468fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 10478fae3551SRodney W. Grimes return (0); 10488fae3551SRodney W. Grimes return (1); 10498fae3551SRodney W. Grimes errout: 1050a62dc406SDoug Rabson sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10518fae3551SRodney W. Grimes return (0); 10528fae3551SRodney W. Grimes } 10538fae3551SRodney W. Grimes 10548fae3551SRodney W. Grimes /* 10558fae3551SRodney W. Grimes * Called from xdr_explist() to traverse the tree and export the 10568fae3551SRodney W. Grimes * directory paths. 10578fae3551SRodney W. Grimes */ 10588fae3551SRodney W. Grimes int 1059a7a7d96cSPhilippe Charnier put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1060a7a7d96cSPhilippe Charnier int brief) 10618fae3551SRodney W. Grimes { 10628fae3551SRodney W. Grimes struct grouplist *grp; 10638fae3551SRodney W. Grimes struct hostlist *hp; 10648fae3551SRodney W. Grimes int true = 1; 10658fae3551SRodney W. Grimes int false = 0; 10668fae3551SRodney W. Grimes int gotalldir = 0; 10678fae3551SRodney W. Grimes char *strp; 10688fae3551SRodney W. Grimes 10698fae3551SRodney W. Grimes if (dp) { 107091acb349SAlfred Perlstein if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 10718fae3551SRodney W. Grimes return (1); 10728fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 10738fae3551SRodney W. Grimes return (1); 10748fae3551SRodney W. Grimes strp = dp->dp_dirp; 10750775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 10768fae3551SRodney W. Grimes return (1); 10778fae3551SRodney W. Grimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 10788fae3551SRodney W. Grimes gotalldir = 1; 10798fae3551SRodney W. Grimes *putdefp = 1; 10808fae3551SRodney W. Grimes } 108191acb349SAlfred Perlstein if (brief) { 108291acb349SAlfred Perlstein if (!xdr_bool(xdrsp, &true)) 108391acb349SAlfred Perlstein return (1); 108491acb349SAlfred Perlstein strp = "(...)"; 10850775314bSDoug Rabson if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 108691acb349SAlfred Perlstein return (1); 108791acb349SAlfred Perlstein } else if ((dp->dp_flag & DP_DEFSET) == 0 && 10888fae3551SRodney W. Grimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 10898fae3551SRodney W. Grimes hp = dp->dp_hosts; 10908fae3551SRodney W. Grimes while (hp) { 10918fae3551SRodney W. Grimes grp = hp->ht_grp; 10928fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 10938fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 10948fae3551SRodney W. Grimes return (1); 10958360efbdSAlfred Perlstein strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 10968fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 10970775314bSDoug Rabson MNTNAMLEN)) 10988fae3551SRodney W. Grimes return (1); 10998fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 11008fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &true)) 11018fae3551SRodney W. Grimes return (1); 11028fae3551SRodney W. Grimes strp = grp->gr_ptr.gt_net.nt_name; 11038fae3551SRodney W. Grimes if (!xdr_string(xdrsp, &strp, 11040775314bSDoug Rabson MNTNAMLEN)) 11058fae3551SRodney W. Grimes return (1); 11068fae3551SRodney W. Grimes } 11078fae3551SRodney W. Grimes hp = hp->ht_next; 11088fae3551SRodney W. Grimes if (gotalldir && hp == (struct hostlist *)NULL) { 11098fae3551SRodney W. Grimes hp = adp->dp_hosts; 11108fae3551SRodney W. Grimes gotalldir = 0; 11118fae3551SRodney W. Grimes } 11128fae3551SRodney W. Grimes } 11138fae3551SRodney W. Grimes } 11148fae3551SRodney W. Grimes if (!xdr_bool(xdrsp, &false)) 11158fae3551SRodney W. Grimes return (1); 111691acb349SAlfred Perlstein if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 11178fae3551SRodney W. Grimes return (1); 11188fae3551SRodney W. Grimes } 11198fae3551SRodney W. Grimes return (0); 11208fae3551SRodney W. Grimes } 11218fae3551SRodney W. Grimes 112291acb349SAlfred Perlstein int 1123a7a7d96cSPhilippe Charnier xdr_explist(XDR *xdrsp, caddr_t cp) 112491acb349SAlfred Perlstein { 112591acb349SAlfred Perlstein 112691acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 0); 112791acb349SAlfred Perlstein } 112891acb349SAlfred Perlstein 112991acb349SAlfred Perlstein int 1130a7a7d96cSPhilippe Charnier xdr_explist_brief(XDR *xdrsp, caddr_t cp) 113191acb349SAlfred Perlstein { 113291acb349SAlfred Perlstein 113391acb349SAlfred Perlstein return xdr_explist_common(xdrsp, cp, 1); 113491acb349SAlfred Perlstein } 113591acb349SAlfred Perlstein 113691ca1a91SIan Dowse char *line; 113791ca1a91SIan Dowse int linesize; 11388fae3551SRodney W. Grimes FILE *exp_file; 11398fae3551SRodney W. Grimes 11408fae3551SRodney W. Grimes /* 114196968c22SPawel Jakub Dawidek * Get the export list from one, currently open file 11428fae3551SRodney W. Grimes */ 114396968c22SPawel Jakub Dawidek static void 1144a7a7d96cSPhilippe Charnier get_exportlist_one(void) 11458fae3551SRodney W. Grimes { 11468fae3551SRodney W. Grimes struct exportlist *ep, *ep2; 11478fae3551SRodney W. Grimes struct grouplist *grp, *tgrp; 11488fae3551SRodney W. Grimes struct exportlist **epp; 11498fae3551SRodney W. Grimes struct dirlist *dirhead; 115096968c22SPawel Jakub Dawidek struct statfs fsb; 1151c0511d3bSBrian Feldman struct xucred anon; 11528fae3551SRodney W. Grimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 115396968c22SPawel Jakub Dawidek int len, has_host, exflags, got_nondir, dirplen, netgrp; 11548fae3551SRodney W. Grimes 1155bcc1d071SRick Macklem v4root_phase = 0; 11568fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 11578fae3551SRodney W. Grimes while (get_line()) { 11588fae3551SRodney W. Grimes if (debug) 115974853402SPhilippe Charnier warnx("got line %s", line); 11608fae3551SRodney W. Grimes cp = line; 11618fae3551SRodney W. Grimes nextfield(&cp, &endcp); 11628fae3551SRodney W. Grimes if (*cp == '#') 11638fae3551SRodney W. Grimes goto nextline; 11648fae3551SRodney W. Grimes 11658fae3551SRodney W. Grimes /* 11668fae3551SRodney W. Grimes * Set defaults. 11678fae3551SRodney W. Grimes */ 11688fae3551SRodney W. Grimes has_host = FALSE; 11698fae3551SRodney W. Grimes anon = def_anon; 11708fae3551SRodney W. Grimes exflags = MNT_EXPORTED; 11718fae3551SRodney W. Grimes got_nondir = 0; 11728fae3551SRodney W. Grimes opt_flags = 0; 11738fae3551SRodney W. Grimes ep = (struct exportlist *)NULL; 1174bcc1d071SRick Macklem dirp = NULL; 1175bcc1d071SRick Macklem 1176bcc1d071SRick Macklem /* 1177bcc1d071SRick Macklem * Handle the V4 root dir. 1178bcc1d071SRick Macklem */ 1179bcc1d071SRick Macklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1180bcc1d071SRick Macklem /* 1181bcc1d071SRick Macklem * V4: just indicates that it is the v4 root point, 1182bcc1d071SRick Macklem * so skip over that and set v4root_phase. 1183bcc1d071SRick Macklem */ 1184bcc1d071SRick Macklem if (v4root_phase > 0) { 1185bcc1d071SRick Macklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1186bcc1d071SRick Macklem goto nextline; 1187bcc1d071SRick Macklem } 1188bcc1d071SRick Macklem v4root_phase = 1; 1189bcc1d071SRick Macklem cp += 3; 1190bcc1d071SRick Macklem nextfield(&cp, &endcp); 1191bcc1d071SRick Macklem } 11928fae3551SRodney W. Grimes 11938fae3551SRodney W. Grimes /* 11948fae3551SRodney W. Grimes * Create new exports list entry 11958fae3551SRodney W. Grimes */ 11968fae3551SRodney W. Grimes len = endcp-cp; 11978fae3551SRodney W. Grimes tgrp = grp = get_grp(); 11988fae3551SRodney W. Grimes while (len > 0) { 11990775314bSDoug Rabson if (len > MNTNAMLEN) { 12008fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12018fae3551SRodney W. Grimes goto nextline; 12028fae3551SRodney W. Grimes } 12038fae3551SRodney W. Grimes if (*cp == '-') { 12048fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 12058fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12068fae3551SRodney W. Grimes goto nextline; 12078fae3551SRodney W. Grimes } 12088fae3551SRodney W. Grimes if (debug) 120974853402SPhilippe Charnier warnx("doing opt %s", cp); 12108fae3551SRodney W. Grimes got_nondir = 1; 12118fae3551SRodney W. Grimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 12128fae3551SRodney W. Grimes &exflags, &anon)) { 12138fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12148fae3551SRodney W. Grimes goto nextline; 12158fae3551SRodney W. Grimes } 12168fae3551SRodney W. Grimes } else if (*cp == '/') { 12178fae3551SRodney W. Grimes savedc = *endcp; 12188fae3551SRodney W. Grimes *endcp = '\0'; 1219bcc1d071SRick Macklem if (v4root_phase > 1) { 1220bcc1d071SRick Macklem if (dirp != NULL) { 1221bcc1d071SRick Macklem syslog(LOG_ERR, "Multiple V4 dirs"); 1222bcc1d071SRick Macklem getexp_err(ep, tgrp); 1223bcc1d071SRick Macklem goto nextline; 1224bcc1d071SRick Macklem } 1225bcc1d071SRick Macklem } 12268fae3551SRodney W. Grimes if (check_dirpath(cp) && 12278fae3551SRodney W. Grimes statfs(cp, &fsb) >= 0) { 12288fae3551SRodney W. Grimes if (got_nondir) { 122974853402SPhilippe Charnier syslog(LOG_ERR, "dirs must be first"); 12308fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12318fae3551SRodney W. Grimes goto nextline; 12328fae3551SRodney W. Grimes } 1233bcc1d071SRick Macklem if (v4root_phase == 1) { 1234bcc1d071SRick Macklem if (dirp != NULL) { 1235bcc1d071SRick Macklem syslog(LOG_ERR, "Multiple V4 dirs"); 1236bcc1d071SRick Macklem getexp_err(ep, tgrp); 1237bcc1d071SRick Macklem goto nextline; 1238bcc1d071SRick Macklem } 1239bcc1d071SRick Macklem if (strlen(v4root_dirpath) == 0) { 1240bcc1d071SRick Macklem strlcpy(v4root_dirpath, cp, 1241bcc1d071SRick Macklem sizeof (v4root_dirpath)); 1242bcc1d071SRick Macklem } else if (strcmp(v4root_dirpath, cp) 1243bcc1d071SRick Macklem != 0) { 1244bcc1d071SRick Macklem syslog(LOG_ERR, 1245bcc1d071SRick Macklem "different V4 dirpath %s", cp); 1246bcc1d071SRick Macklem getexp_err(ep, tgrp); 1247bcc1d071SRick Macklem goto nextline; 1248bcc1d071SRick Macklem } 1249bcc1d071SRick Macklem dirp = cp; 1250bcc1d071SRick Macklem v4root_phase = 2; 1251bcc1d071SRick Macklem got_nondir = 1; 1252bcc1d071SRick Macklem ep = get_exp(); 1253bcc1d071SRick Macklem } else { 12548fae3551SRodney W. Grimes if (ep) { 1255bcc1d071SRick Macklem if (ep->ex_fs.val[0] != 1256bcc1d071SRick Macklem fsb.f_fsid.val[0] || 1257bcc1d071SRick Macklem ep->ex_fs.val[1] != 1258bcc1d071SRick Macklem fsb.f_fsid.val[1]) { 12598fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12608fae3551SRodney W. Grimes goto nextline; 12618fae3551SRodney W. Grimes } 12628fae3551SRodney W. Grimes } else { 12638fae3551SRodney W. Grimes /* 12648fae3551SRodney W. Grimes * See if this directory is already 12658fae3551SRodney W. Grimes * in the list. 12668fae3551SRodney W. Grimes */ 12678fae3551SRodney W. Grimes ep = ex_search(&fsb.f_fsid); 12688fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 12698fae3551SRodney W. Grimes ep = get_exp(); 12708fae3551SRodney W. Grimes ep->ex_fs = fsb.f_fsid; 1271bcc1d071SRick Macklem ep->ex_fsdir = (char *)malloc 1272bcc1d071SRick Macklem (strlen(fsb.f_mntonname) + 1); 12738fae3551SRodney W. Grimes if (ep->ex_fsdir) 12748fae3551SRodney W. Grimes strcpy(ep->ex_fsdir, 12758fae3551SRodney W. Grimes fsb.f_mntonname); 12768fae3551SRodney W. Grimes else 12778fae3551SRodney W. Grimes out_of_mem(); 12788fae3551SRodney W. Grimes if (debug) 1279bcc1d071SRick Macklem warnx( 1280bcc1d071SRick Macklem "making new ep fs=0x%x,0x%x", 12818fae3551SRodney W. Grimes fsb.f_fsid.val[0], 12828fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 12838fae3551SRodney W. Grimes } else if (debug) 128474853402SPhilippe Charnier warnx("found ep fs=0x%x,0x%x", 12858fae3551SRodney W. Grimes fsb.f_fsid.val[0], 12868fae3551SRodney W. Grimes fsb.f_fsid.val[1]); 12878fae3551SRodney W. Grimes } 12888fae3551SRodney W. Grimes 12898fae3551SRodney W. Grimes /* 12908fae3551SRodney W. Grimes * Add dirpath to export mount point. 12918fae3551SRodney W. Grimes */ 12928fae3551SRodney W. Grimes dirp = add_expdir(&dirhead, cp, len); 12938fae3551SRodney W. Grimes dirplen = len; 1294bcc1d071SRick Macklem } 12958fae3551SRodney W. Grimes } else { 12968fae3551SRodney W. Grimes getexp_err(ep, tgrp); 12978fae3551SRodney W. Grimes goto nextline; 12988fae3551SRodney W. Grimes } 12998fae3551SRodney W. Grimes *endcp = savedc; 13008fae3551SRodney W. Grimes } else { 13018fae3551SRodney W. Grimes savedc = *endcp; 13028fae3551SRodney W. Grimes *endcp = '\0'; 13038fae3551SRodney W. Grimes got_nondir = 1; 13048fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) { 13058fae3551SRodney W. Grimes getexp_err(ep, tgrp); 13068fae3551SRodney W. Grimes goto nextline; 13078fae3551SRodney W. Grimes } 13088fae3551SRodney W. Grimes 13098fae3551SRodney W. Grimes /* 13108fae3551SRodney W. Grimes * Get the host or netgroup. 13118fae3551SRodney W. Grimes */ 13128fae3551SRodney W. Grimes setnetgrent(cp); 13138fae3551SRodney W. Grimes netgrp = getnetgrent(&hst, &usr, &dom); 13148fae3551SRodney W. Grimes do { 13158fae3551SRodney W. Grimes if (has_host) { 13168fae3551SRodney W. Grimes grp->gr_next = get_grp(); 13178fae3551SRodney W. Grimes grp = grp->gr_next; 13188fae3551SRodney W. Grimes } 13198fae3551SRodney W. Grimes if (netgrp) { 13209d70a156SJoerg Wunsch if (hst == 0) { 132174853402SPhilippe Charnier syslog(LOG_ERR, 132274853402SPhilippe Charnier "null hostname in netgroup %s, skipping", cp); 132301d48801SJoerg Wunsch grp->gr_type = GT_IGNORE; 13249d70a156SJoerg Wunsch } else if (get_host(hst, grp, tgrp)) { 132574853402SPhilippe Charnier syslog(LOG_ERR, 132674853402SPhilippe Charnier "bad host %s in netgroup %s, skipping", hst, cp); 1327a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 13288fae3551SRodney W. Grimes } 13298b5a6d67SBill Paul } else if (get_host(cp, grp, tgrp)) { 133074853402SPhilippe Charnier syslog(LOG_ERR, "bad host %s, skipping", cp); 1331a968cfd8SJonathan Lemon grp->gr_type = GT_IGNORE; 13328fae3551SRodney W. Grimes } 13338fae3551SRodney W. Grimes has_host = TRUE; 13348fae3551SRodney W. Grimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 13358fae3551SRodney W. Grimes endnetgrent(); 13368fae3551SRodney W. Grimes *endcp = savedc; 13378fae3551SRodney W. Grimes } 13388fae3551SRodney W. Grimes cp = endcp; 13398fae3551SRodney W. Grimes nextfield(&cp, &endcp); 13408fae3551SRodney W. Grimes len = endcp - cp; 13418fae3551SRodney W. Grimes } 13428fae3551SRodney W. Grimes if (check_options(dirhead)) { 13438fae3551SRodney W. Grimes getexp_err(ep, tgrp); 13448fae3551SRodney W. Grimes goto nextline; 13458fae3551SRodney W. Grimes } 13468fae3551SRodney W. Grimes if (!has_host) { 13476d359f31SIan Dowse grp->gr_type = GT_DEFAULT; 13488fae3551SRodney W. Grimes if (debug) 134974853402SPhilippe Charnier warnx("adding a default entry"); 13508fae3551SRodney W. Grimes 13518fae3551SRodney W. Grimes /* 13528fae3551SRodney W. Grimes * Don't allow a network export coincide with a list of 13538fae3551SRodney W. Grimes * host(s) on the same line. 13548fae3551SRodney W. Grimes */ 13558fae3551SRodney W. Grimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 135660caaee2SIan Dowse syslog(LOG_ERR, "network/host conflict"); 13578fae3551SRodney W. Grimes getexp_err(ep, tgrp); 13588fae3551SRodney W. Grimes goto nextline; 1359a968cfd8SJonathan Lemon 1360a968cfd8SJonathan Lemon /* 1361a968cfd8SJonathan Lemon * If an export list was specified on this line, make sure 1362a968cfd8SJonathan Lemon * that we have at least one valid entry, otherwise skip it. 1363a968cfd8SJonathan Lemon */ 1364a968cfd8SJonathan Lemon } else { 1365a968cfd8SJonathan Lemon grp = tgrp; 1366a968cfd8SJonathan Lemon while (grp && grp->gr_type == GT_IGNORE) 1367a968cfd8SJonathan Lemon grp = grp->gr_next; 1368a968cfd8SJonathan Lemon if (! grp) { 1369a968cfd8SJonathan Lemon getexp_err(ep, tgrp); 1370a968cfd8SJonathan Lemon goto nextline; 1371a968cfd8SJonathan Lemon } 13728fae3551SRodney W. Grimes } 13738fae3551SRodney W. Grimes 1374bcc1d071SRick Macklem if (v4root_phase == 1) { 1375bcc1d071SRick Macklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1376bcc1d071SRick Macklem getexp_err(ep, tgrp); 1377bcc1d071SRick Macklem goto nextline; 1378bcc1d071SRick Macklem } 1379bcc1d071SRick Macklem 13808fae3551SRodney W. Grimes /* 13818fae3551SRodney W. Grimes * Loop through hosts, pushing the exports into the kernel. 13828fae3551SRodney W. Grimes * After loop, tgrp points to the start of the list and 13838fae3551SRodney W. Grimes * grp points to the last entry in the list. 13848fae3551SRodney W. Grimes */ 13858fae3551SRodney W. Grimes grp = tgrp; 13868fae3551SRodney W. Grimes do { 138701709abfSIan Dowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 138801709abfSIan Dowse &fsb)) { 13898fae3551SRodney W. Grimes getexp_err(ep, tgrp); 13908fae3551SRodney W. Grimes goto nextline; 13918fae3551SRodney W. Grimes } 13928fae3551SRodney W. Grimes } while (grp->gr_next && (grp = grp->gr_next)); 13938fae3551SRodney W. Grimes 13948fae3551SRodney W. Grimes /* 1395bcc1d071SRick Macklem * For V4: don't enter in mount lists. 1396bcc1d071SRick Macklem */ 139773f4ccbdSRick Macklem if (v4root_phase > 0 && v4root_phase <= 2) { 139873f4ccbdSRick Macklem /* 139973f4ccbdSRick Macklem * Since these structures aren't used by mountd, 140073f4ccbdSRick Macklem * free them up now. 140173f4ccbdSRick Macklem */ 140273f4ccbdSRick Macklem if (ep != NULL) 140373f4ccbdSRick Macklem free_exp(ep); 140473f4ccbdSRick Macklem while (tgrp != NULL) { 140573f4ccbdSRick Macklem grp = tgrp; 140673f4ccbdSRick Macklem tgrp = tgrp->gr_next; 140773f4ccbdSRick Macklem free_grp(grp); 140873f4ccbdSRick Macklem } 1409bcc1d071SRick Macklem goto nextline; 141073f4ccbdSRick Macklem } 1411bcc1d071SRick Macklem 1412bcc1d071SRick Macklem /* 14138fae3551SRodney W. Grimes * Success. Update the data structures. 14148fae3551SRodney W. Grimes */ 14158fae3551SRodney W. Grimes if (has_host) { 1416a62dc406SDoug Rabson hang_dirp(dirhead, tgrp, ep, opt_flags); 14178fae3551SRodney W. Grimes grp->gr_next = grphead; 14188fae3551SRodney W. Grimes grphead = tgrp; 14198fae3551SRodney W. Grimes } else { 14208fae3551SRodney W. Grimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1421a62dc406SDoug Rabson opt_flags); 14228fae3551SRodney W. Grimes free_grp(grp); 14238fae3551SRodney W. Grimes } 14248fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 14258fae3551SRodney W. Grimes if ((ep->ex_flag & EX_LINKED) == 0) { 14268fae3551SRodney W. Grimes ep2 = exphead; 14278fae3551SRodney W. Grimes epp = &exphead; 14288fae3551SRodney W. Grimes 14298fae3551SRodney W. Grimes /* 14308fae3551SRodney W. Grimes * Insert in the list in alphabetical order. 14318fae3551SRodney W. Grimes */ 14328fae3551SRodney W. Grimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 14338fae3551SRodney W. Grimes epp = &ep2->ex_next; 14348fae3551SRodney W. Grimes ep2 = ep2->ex_next; 14358fae3551SRodney W. Grimes } 14368fae3551SRodney W. Grimes if (ep2) 14378fae3551SRodney W. Grimes ep->ex_next = ep2; 14388fae3551SRodney W. Grimes *epp = ep; 14398fae3551SRodney W. Grimes ep->ex_flag |= EX_LINKED; 14408fae3551SRodney W. Grimes } 14418fae3551SRodney W. Grimes nextline: 1442bcc1d071SRick Macklem v4root_phase = 0; 14438fae3551SRodney W. Grimes if (dirhead) { 14448fae3551SRodney W. Grimes free_dir(dirhead); 14458fae3551SRodney W. Grimes dirhead = (struct dirlist *)NULL; 14468fae3551SRodney W. Grimes } 14478fae3551SRodney W. Grimes } 144896968c22SPawel Jakub Dawidek } 144996968c22SPawel Jakub Dawidek 145096968c22SPawel Jakub Dawidek /* 145196968c22SPawel Jakub Dawidek * Get the export list from all specified files 145296968c22SPawel Jakub Dawidek */ 145396968c22SPawel Jakub Dawidek void 1454a7a7d96cSPhilippe Charnier get_exportlist(void) 145596968c22SPawel Jakub Dawidek { 145696968c22SPawel Jakub Dawidek struct exportlist *ep, *ep2; 145796968c22SPawel Jakub Dawidek struct grouplist *grp, *tgrp; 145896968c22SPawel Jakub Dawidek struct export_args export; 145996968c22SPawel Jakub Dawidek struct iovec *iov; 146096968c22SPawel Jakub Dawidek struct statfs *fsp, *mntbufp; 146196968c22SPawel Jakub Dawidek struct xvfsconf vfc; 146296968c22SPawel Jakub Dawidek char *dirp; 146396968c22SPawel Jakub Dawidek char errmsg[255]; 146496968c22SPawel Jakub Dawidek int dirplen, num, i; 146596968c22SPawel Jakub Dawidek int iovlen; 14666c90092bSPawel Jakub Dawidek int done; 1467bcc1d071SRick Macklem struct nfsex_args eargs; 146896968c22SPawel Jakub Dawidek 1469bcc1d071SRick Macklem v4root_dirpath[0] = '\0'; 147096968c22SPawel Jakub Dawidek bzero(&export, sizeof(export)); 147196968c22SPawel Jakub Dawidek export.ex_flags = MNT_DELEXPORT; 147296968c22SPawel Jakub Dawidek dirp = NULL; 147396968c22SPawel Jakub Dawidek dirplen = 0; 147496968c22SPawel Jakub Dawidek iov = NULL; 147596968c22SPawel Jakub Dawidek iovlen = 0; 147696968c22SPawel Jakub Dawidek bzero(errmsg, sizeof(errmsg)); 147796968c22SPawel Jakub Dawidek 147896968c22SPawel Jakub Dawidek /* 147996968c22SPawel Jakub Dawidek * First, get rid of the old list 148096968c22SPawel Jakub Dawidek */ 148196968c22SPawel Jakub Dawidek ep = exphead; 148296968c22SPawel Jakub Dawidek while (ep) { 148396968c22SPawel Jakub Dawidek ep2 = ep; 148496968c22SPawel Jakub Dawidek ep = ep->ex_next; 148596968c22SPawel Jakub Dawidek free_exp(ep2); 148696968c22SPawel Jakub Dawidek } 148796968c22SPawel Jakub Dawidek exphead = (struct exportlist *)NULL; 148896968c22SPawel Jakub Dawidek 148996968c22SPawel Jakub Dawidek grp = grphead; 149096968c22SPawel Jakub Dawidek while (grp) { 149196968c22SPawel Jakub Dawidek tgrp = grp; 149296968c22SPawel Jakub Dawidek grp = grp->gr_next; 149396968c22SPawel Jakub Dawidek free_grp(tgrp); 149496968c22SPawel Jakub Dawidek } 149596968c22SPawel Jakub Dawidek grphead = (struct grouplist *)NULL; 149696968c22SPawel Jakub Dawidek 149796968c22SPawel Jakub Dawidek /* 1498bcc1d071SRick Macklem * and the old V4 root dir. 1499bcc1d071SRick Macklem */ 1500bcc1d071SRick Macklem bzero(&eargs, sizeof (eargs)); 1501bcc1d071SRick Macklem eargs.export.ex_flags = MNT_DELEXPORT; 1502bcc1d071SRick Macklem if (run_v4server > 0 && 1503bcc1d071SRick Macklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1504bcc1d071SRick Macklem errno != ENOENT) 1505bcc1d071SRick Macklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1506bcc1d071SRick Macklem 1507bcc1d071SRick Macklem /* 1508bcc1d071SRick Macklem * and clear flag that notes if a public fh has been exported. 1509bcc1d071SRick Macklem */ 1510bcc1d071SRick Macklem has_publicfh = 0; 1511bcc1d071SRick Macklem 1512bcc1d071SRick Macklem /* 151396968c22SPawel Jakub Dawidek * And delete exports that are in the kernel for all local 151496968c22SPawel Jakub Dawidek * filesystems. 151596968c22SPawel Jakub Dawidek * XXX: Should know how to handle all local exportable filesystems. 151696968c22SPawel Jakub Dawidek */ 151796968c22SPawel Jakub Dawidek num = getmntinfo(&mntbufp, MNT_NOWAIT); 151896968c22SPawel Jakub Dawidek 151996968c22SPawel Jakub Dawidek if (num > 0) { 152096968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "fstype", NULL, 0); 152196968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "fspath", NULL, 0); 152296968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "from", NULL, 0); 152396968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "update", NULL, 0); 152496968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 152596968c22SPawel Jakub Dawidek build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 152696968c22SPawel Jakub Dawidek } 152796968c22SPawel Jakub Dawidek 152896968c22SPawel Jakub Dawidek for (i = 0; i < num; i++) { 152996968c22SPawel Jakub Dawidek fsp = &mntbufp[i]; 153096968c22SPawel Jakub Dawidek if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 153196968c22SPawel Jakub Dawidek syslog(LOG_ERR, "getvfsbyname() failed for %s", 153296968c22SPawel Jakub Dawidek fsp->f_fstypename); 153396968c22SPawel Jakub Dawidek continue; 153496968c22SPawel Jakub Dawidek } 153596968c22SPawel Jakub Dawidek 153696968c22SPawel Jakub Dawidek /* 153796968c22SPawel Jakub Dawidek * Do not delete export for network filesystem by 153896968c22SPawel Jakub Dawidek * passing "export" arg to nmount(). 153996968c22SPawel Jakub Dawidek * It only makes sense to do this for local filesystems. 154096968c22SPawel Jakub Dawidek */ 154196968c22SPawel Jakub Dawidek if (vfc.vfc_flags & VFCF_NETWORK) 154296968c22SPawel Jakub Dawidek continue; 154396968c22SPawel Jakub Dawidek 154496968c22SPawel Jakub Dawidek iov[1].iov_base = fsp->f_fstypename; 154596968c22SPawel Jakub Dawidek iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 154696968c22SPawel Jakub Dawidek iov[3].iov_base = fsp->f_mntonname; 154796968c22SPawel Jakub Dawidek iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 154896968c22SPawel Jakub Dawidek iov[5].iov_base = fsp->f_mntfromname; 154996968c22SPawel Jakub Dawidek iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 155096968c22SPawel Jakub Dawidek 155196968c22SPawel Jakub Dawidek if (nmount(iov, iovlen, fsp->f_flags) < 0 && 155296968c22SPawel Jakub Dawidek errno != ENOENT && errno != ENOTSUP) { 155396968c22SPawel Jakub Dawidek syslog(LOG_ERR, 155496968c22SPawel Jakub Dawidek "can't delete exports for %s: %m %s", 155596968c22SPawel Jakub Dawidek fsp->f_mntonname, errmsg); 155696968c22SPawel Jakub Dawidek } 155796968c22SPawel Jakub Dawidek } 155896968c22SPawel Jakub Dawidek 155996968c22SPawel Jakub Dawidek if (iov != NULL) { 156096968c22SPawel Jakub Dawidek /* Free strings allocated by strdup() in getmntopts.c */ 156196968c22SPawel Jakub Dawidek free(iov[0].iov_base); /* fstype */ 156296968c22SPawel Jakub Dawidek free(iov[2].iov_base); /* fspath */ 156396968c22SPawel Jakub Dawidek free(iov[4].iov_base); /* from */ 156496968c22SPawel Jakub Dawidek free(iov[6].iov_base); /* update */ 156596968c22SPawel Jakub Dawidek free(iov[8].iov_base); /* export */ 156696968c22SPawel Jakub Dawidek free(iov[10].iov_base); /* errmsg */ 156796968c22SPawel Jakub Dawidek 156896968c22SPawel Jakub Dawidek /* free iov, allocated by realloc() */ 156996968c22SPawel Jakub Dawidek free(iov); 157096968c22SPawel Jakub Dawidek iovlen = 0; 157196968c22SPawel Jakub Dawidek } 157296968c22SPawel Jakub Dawidek 157396968c22SPawel Jakub Dawidek /* 157496968c22SPawel Jakub Dawidek * Read in the exports file and build the list, calling 157596968c22SPawel Jakub Dawidek * nmount() as we go along to push the export rules into the kernel. 157696968c22SPawel Jakub Dawidek */ 15776c90092bSPawel Jakub Dawidek done = 0; 157896968c22SPawel Jakub Dawidek for (i = 0; exnames[i] != NULL; i++) { 157996968c22SPawel Jakub Dawidek if (debug) 158096968c22SPawel Jakub Dawidek warnx("reading exports from %s", exnames[i]); 158196968c22SPawel Jakub Dawidek if ((exp_file = fopen(exnames[i], "r")) == NULL) { 15826c90092bSPawel Jakub Dawidek syslog(LOG_WARNING, "can't open %s", exnames[i]); 15836c90092bSPawel Jakub Dawidek continue; 158496968c22SPawel Jakub Dawidek } 158596968c22SPawel Jakub Dawidek get_exportlist_one(); 15868fae3551SRodney W. Grimes fclose(exp_file); 15876c90092bSPawel Jakub Dawidek done++; 15886c90092bSPawel Jakub Dawidek } 15896c90092bSPawel Jakub Dawidek if (done == 0) { 15906c90092bSPawel Jakub Dawidek syslog(LOG_ERR, "can't open any exports file"); 15916c90092bSPawel Jakub Dawidek exit(2); 15928fae3551SRodney W. Grimes } 1593bcc1d071SRick Macklem 1594bcc1d071SRick Macklem /* 1595bcc1d071SRick Macklem * If there was no public fh, clear any previous one set. 1596bcc1d071SRick Macklem */ 1597bcc1d071SRick Macklem if (run_v4server > 0 && has_publicfh == 0) 1598bcc1d071SRick Macklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 159996968c22SPawel Jakub Dawidek } 16008fae3551SRodney W. Grimes 16018fae3551SRodney W. Grimes /* 16028fae3551SRodney W. Grimes * Allocate an export list element 16038fae3551SRodney W. Grimes */ 16048fae3551SRodney W. Grimes struct exportlist * 1605a7a7d96cSPhilippe Charnier get_exp(void) 16068fae3551SRodney W. Grimes { 16078fae3551SRodney W. Grimes struct exportlist *ep; 16088fae3551SRodney W. Grimes 16098fae3551SRodney W. Grimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 16108fae3551SRodney W. Grimes if (ep == (struct exportlist *)NULL) 16118fae3551SRodney W. Grimes out_of_mem(); 161287564113SPeter Wemm memset(ep, 0, sizeof(struct exportlist)); 16138fae3551SRodney W. Grimes return (ep); 16148fae3551SRodney W. Grimes } 16158fae3551SRodney W. Grimes 16168fae3551SRodney W. Grimes /* 16178fae3551SRodney W. Grimes * Allocate a group list element 16188fae3551SRodney W. Grimes */ 16198fae3551SRodney W. Grimes struct grouplist * 1620a7a7d96cSPhilippe Charnier get_grp(void) 16218fae3551SRodney W. Grimes { 16228fae3551SRodney W. Grimes struct grouplist *gp; 16238fae3551SRodney W. Grimes 16248fae3551SRodney W. Grimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 16258fae3551SRodney W. Grimes if (gp == (struct grouplist *)NULL) 16268fae3551SRodney W. Grimes out_of_mem(); 162787564113SPeter Wemm memset(gp, 0, sizeof(struct grouplist)); 16288fae3551SRodney W. Grimes return (gp); 16298fae3551SRodney W. Grimes } 16308fae3551SRodney W. Grimes 16318fae3551SRodney W. Grimes /* 16328fae3551SRodney W. Grimes * Clean up upon an error in get_exportlist(). 16338fae3551SRodney W. Grimes */ 16348fae3551SRodney W. Grimes void 1635a7a7d96cSPhilippe Charnier getexp_err(struct exportlist *ep, struct grouplist *grp) 16368fae3551SRodney W. Grimes { 16378fae3551SRodney W. Grimes struct grouplist *tgrp; 16388fae3551SRodney W. Grimes 1639288fa14aSJoerg Wunsch if (!(opt_flags & OP_QUIET)) 164074853402SPhilippe Charnier syslog(LOG_ERR, "bad exports list line %s", line); 16418fae3551SRodney W. Grimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 16428fae3551SRodney W. Grimes free_exp(ep); 16438fae3551SRodney W. Grimes while (grp) { 16448fae3551SRodney W. Grimes tgrp = grp; 16458fae3551SRodney W. Grimes grp = grp->gr_next; 16468fae3551SRodney W. Grimes free_grp(tgrp); 16478fae3551SRodney W. Grimes } 16488fae3551SRodney W. Grimes } 16498fae3551SRodney W. Grimes 16508fae3551SRodney W. Grimes /* 16518fae3551SRodney W. Grimes * Search the export list for a matching fs. 16528fae3551SRodney W. Grimes */ 16538fae3551SRodney W. Grimes struct exportlist * 1654a7a7d96cSPhilippe Charnier ex_search(fsid_t *fsid) 16558fae3551SRodney W. Grimes { 16568fae3551SRodney W. Grimes struct exportlist *ep; 16578fae3551SRodney W. Grimes 16588fae3551SRodney W. Grimes ep = exphead; 16598fae3551SRodney W. Grimes while (ep) { 16608fae3551SRodney W. Grimes if (ep->ex_fs.val[0] == fsid->val[0] && 16618fae3551SRodney W. Grimes ep->ex_fs.val[1] == fsid->val[1]) 16628fae3551SRodney W. Grimes return (ep); 16638fae3551SRodney W. Grimes ep = ep->ex_next; 16648fae3551SRodney W. Grimes } 16658fae3551SRodney W. Grimes return (ep); 16668fae3551SRodney W. Grimes } 16678fae3551SRodney W. Grimes 16688fae3551SRodney W. Grimes /* 16698fae3551SRodney W. Grimes * Add a directory path to the list. 16708fae3551SRodney W. Grimes */ 16718fae3551SRodney W. Grimes char * 1672a7a7d96cSPhilippe Charnier add_expdir(struct dirlist **dpp, char *cp, int len) 16738fae3551SRodney W. Grimes { 16748fae3551SRodney W. Grimes struct dirlist *dp; 16758fae3551SRodney W. Grimes 16768fae3551SRodney W. Grimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 167774853402SPhilippe Charnier if (dp == (struct dirlist *)NULL) 167874853402SPhilippe Charnier out_of_mem(); 16798fae3551SRodney W. Grimes dp->dp_left = *dpp; 16808fae3551SRodney W. Grimes dp->dp_right = (struct dirlist *)NULL; 16818fae3551SRodney W. Grimes dp->dp_flag = 0; 16828fae3551SRodney W. Grimes dp->dp_hosts = (struct hostlist *)NULL; 16838fae3551SRodney W. Grimes strcpy(dp->dp_dirp, cp); 16848fae3551SRodney W. Grimes *dpp = dp; 16858fae3551SRodney W. Grimes return (dp->dp_dirp); 16868fae3551SRodney W. Grimes } 16878fae3551SRodney W. Grimes 16888fae3551SRodney W. Grimes /* 16898fae3551SRodney W. Grimes * Hang the dir list element off the dirpath binary tree as required 16908fae3551SRodney W. Grimes * and update the entry for host. 16918fae3551SRodney W. Grimes */ 16928fae3551SRodney W. Grimes void 1693a7a7d96cSPhilippe Charnier hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1694a7a7d96cSPhilippe Charnier int flags) 16958fae3551SRodney W. Grimes { 16968fae3551SRodney W. Grimes struct hostlist *hp; 16978fae3551SRodney W. Grimes struct dirlist *dp2; 16988fae3551SRodney W. Grimes 1699a62dc406SDoug Rabson if (flags & OP_ALLDIRS) { 17008fae3551SRodney W. Grimes if (ep->ex_defdir) 17018fae3551SRodney W. Grimes free((caddr_t)dp); 17028fae3551SRodney W. Grimes else 17038fae3551SRodney W. Grimes ep->ex_defdir = dp; 1704a62dc406SDoug Rabson if (grp == (struct grouplist *)NULL) { 17058fae3551SRodney W. Grimes ep->ex_defdir->dp_flag |= DP_DEFSET; 1706a62dc406SDoug Rabson } else while (grp) { 17078fae3551SRodney W. Grimes hp = get_ht(); 17088fae3551SRodney W. Grimes hp->ht_grp = grp; 17098fae3551SRodney W. Grimes hp->ht_next = ep->ex_defdir->dp_hosts; 17108fae3551SRodney W. Grimes ep->ex_defdir->dp_hosts = hp; 17118fae3551SRodney W. Grimes grp = grp->gr_next; 17128fae3551SRodney W. Grimes } 17138fae3551SRodney W. Grimes } else { 17148fae3551SRodney W. Grimes 17158fae3551SRodney W. Grimes /* 171674853402SPhilippe Charnier * Loop through the directories adding them to the tree. 17178fae3551SRodney W. Grimes */ 17188fae3551SRodney W. Grimes while (dp) { 17198fae3551SRodney W. Grimes dp2 = dp->dp_left; 1720a62dc406SDoug Rabson add_dlist(&ep->ex_dirl, dp, grp, flags); 17218fae3551SRodney W. Grimes dp = dp2; 17228fae3551SRodney W. Grimes } 17238fae3551SRodney W. Grimes } 17248fae3551SRodney W. Grimes } 17258fae3551SRodney W. Grimes 17268fae3551SRodney W. Grimes /* 17278fae3551SRodney W. Grimes * Traverse the binary tree either updating a node that is already there 17288fae3551SRodney W. Grimes * for the new directory or adding the new node. 17298fae3551SRodney W. Grimes */ 17308fae3551SRodney W. Grimes void 1731a7a7d96cSPhilippe Charnier add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1732a7a7d96cSPhilippe Charnier int flags) 17338fae3551SRodney W. Grimes { 17348fae3551SRodney W. Grimes struct dirlist *dp; 17358fae3551SRodney W. Grimes struct hostlist *hp; 17368fae3551SRodney W. Grimes int cmp; 17378fae3551SRodney W. Grimes 17388fae3551SRodney W. Grimes dp = *dpp; 17398fae3551SRodney W. Grimes if (dp) { 17408fae3551SRodney W. Grimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 17418fae3551SRodney W. Grimes if (cmp > 0) { 1742a62dc406SDoug Rabson add_dlist(&dp->dp_left, newdp, grp, flags); 17438fae3551SRodney W. Grimes return; 17448fae3551SRodney W. Grimes } else if (cmp < 0) { 1745a62dc406SDoug Rabson add_dlist(&dp->dp_right, newdp, grp, flags); 17468fae3551SRodney W. Grimes return; 17478fae3551SRodney W. Grimes } else 17488fae3551SRodney W. Grimes free((caddr_t)newdp); 17498fae3551SRodney W. Grimes } else { 17508fae3551SRodney W. Grimes dp = newdp; 17518fae3551SRodney W. Grimes dp->dp_left = (struct dirlist *)NULL; 17528fae3551SRodney W. Grimes *dpp = dp; 17538fae3551SRodney W. Grimes } 17548fae3551SRodney W. Grimes if (grp) { 17558fae3551SRodney W. Grimes 17568fae3551SRodney W. Grimes /* 17578fae3551SRodney W. Grimes * Hang all of the host(s) off of the directory point. 17588fae3551SRodney W. Grimes */ 17598fae3551SRodney W. Grimes do { 17608fae3551SRodney W. Grimes hp = get_ht(); 17618fae3551SRodney W. Grimes hp->ht_grp = grp; 17628fae3551SRodney W. Grimes hp->ht_next = dp->dp_hosts; 17638fae3551SRodney W. Grimes dp->dp_hosts = hp; 17648fae3551SRodney W. Grimes grp = grp->gr_next; 17658fae3551SRodney W. Grimes } while (grp); 1766a62dc406SDoug Rabson } else { 17678fae3551SRodney W. Grimes dp->dp_flag |= DP_DEFSET; 1768a62dc406SDoug Rabson } 17698fae3551SRodney W. Grimes } 17708fae3551SRodney W. Grimes 17718fae3551SRodney W. Grimes /* 17728fae3551SRodney W. Grimes * Search for a dirpath on the export point. 17738fae3551SRodney W. Grimes */ 17748fae3551SRodney W. Grimes struct dirlist * 1775a7a7d96cSPhilippe Charnier dirp_search(struct dirlist *dp, char *dirp) 17768fae3551SRodney W. Grimes { 17778fae3551SRodney W. Grimes int cmp; 17788fae3551SRodney W. Grimes 17798fae3551SRodney W. Grimes if (dp) { 17808360efbdSAlfred Perlstein cmp = strcmp(dp->dp_dirp, dirp); 17818fae3551SRodney W. Grimes if (cmp > 0) 17828360efbdSAlfred Perlstein return (dirp_search(dp->dp_left, dirp)); 17838fae3551SRodney W. Grimes else if (cmp < 0) 17848360efbdSAlfred Perlstein return (dirp_search(dp->dp_right, dirp)); 17858fae3551SRodney W. Grimes else 17868fae3551SRodney W. Grimes return (dp); 17878fae3551SRodney W. Grimes } 17888fae3551SRodney W. Grimes return (dp); 17898fae3551SRodney W. Grimes } 17908fae3551SRodney W. Grimes 17918fae3551SRodney W. Grimes /* 17928fae3551SRodney W. Grimes * Scan for a host match in a directory tree. 17938fae3551SRodney W. Grimes */ 17948fae3551SRodney W. Grimes int 1795a7a7d96cSPhilippe Charnier chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 1796a7a7d96cSPhilippe Charnier int *hostsetp) 17978fae3551SRodney W. Grimes { 17988fae3551SRodney W. Grimes struct hostlist *hp; 17998fae3551SRodney W. Grimes struct grouplist *grp; 18008360efbdSAlfred Perlstein struct addrinfo *ai; 18018fae3551SRodney W. Grimes 18028fae3551SRodney W. Grimes if (dp) { 18038fae3551SRodney W. Grimes if (dp->dp_flag & DP_DEFSET) 1804a62dc406SDoug Rabson *defsetp = dp->dp_flag; 18058fae3551SRodney W. Grimes hp = dp->dp_hosts; 18068fae3551SRodney W. Grimes while (hp) { 18078fae3551SRodney W. Grimes grp = hp->ht_grp; 18088fae3551SRodney W. Grimes switch (grp->gr_type) { 18098fae3551SRodney W. Grimes case GT_HOST: 18108360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 18118360efbdSAlfred Perlstein for (; ai; ai = ai->ai_next) { 181260caaee2SIan Dowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 18138360efbdSAlfred Perlstein *hostsetp = 18148360efbdSAlfred Perlstein (hp->ht_flag | DP_HOSTSET); 18158fae3551SRodney W. Grimes return (1); 1816a62dc406SDoug Rabson } 18178fae3551SRodney W. Grimes } 18188fae3551SRodney W. Grimes break; 18198fae3551SRodney W. Grimes case GT_NET: 182060caaee2SIan Dowse if (!sacmp(saddr, (struct sockaddr *) 182160caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_net, 182260caaee2SIan Dowse (struct sockaddr *) 182360caaee2SIan Dowse &grp->gr_ptr.gt_net.nt_mask)) { 1824a62dc406SDoug Rabson *hostsetp = (hp->ht_flag | DP_HOSTSET); 18258fae3551SRodney W. Grimes return (1); 1826a62dc406SDoug Rabson } 18278fae3551SRodney W. Grimes break; 182860caaee2SIan Dowse } 18298fae3551SRodney W. Grimes hp = hp->ht_next; 18308fae3551SRodney W. Grimes } 18318fae3551SRodney W. Grimes } 18328fae3551SRodney W. Grimes return (0); 18338fae3551SRodney W. Grimes } 18348fae3551SRodney W. Grimes 18358fae3551SRodney W. Grimes /* 18368fae3551SRodney W. Grimes * Scan tree for a host that matches the address. 18378fae3551SRodney W. Grimes */ 18388fae3551SRodney W. Grimes int 1839a7a7d96cSPhilippe Charnier scan_tree(struct dirlist *dp, struct sockaddr *saddr) 18408fae3551SRodney W. Grimes { 1841a62dc406SDoug Rabson int defset, hostset; 18428fae3551SRodney W. Grimes 18438fae3551SRodney W. Grimes if (dp) { 18448fae3551SRodney W. Grimes if (scan_tree(dp->dp_left, saddr)) 18458fae3551SRodney W. Grimes return (1); 1846a62dc406SDoug Rabson if (chk_host(dp, saddr, &defset, &hostset)) 18478fae3551SRodney W. Grimes return (1); 18488fae3551SRodney W. Grimes if (scan_tree(dp->dp_right, saddr)) 18498fae3551SRodney W. Grimes return (1); 18508fae3551SRodney W. Grimes } 18518fae3551SRodney W. Grimes return (0); 18528fae3551SRodney W. Grimes } 18538fae3551SRodney W. Grimes 18548fae3551SRodney W. Grimes /* 18558fae3551SRodney W. Grimes * Traverse the dirlist tree and free it up. 18568fae3551SRodney W. Grimes */ 18578fae3551SRodney W. Grimes void 1858a7a7d96cSPhilippe Charnier free_dir(struct dirlist *dp) 18598fae3551SRodney W. Grimes { 18608fae3551SRodney W. Grimes 18618fae3551SRodney W. Grimes if (dp) { 18628fae3551SRodney W. Grimes free_dir(dp->dp_left); 18638fae3551SRodney W. Grimes free_dir(dp->dp_right); 18648fae3551SRodney W. Grimes free_host(dp->dp_hosts); 18658fae3551SRodney W. Grimes free((caddr_t)dp); 18668fae3551SRodney W. Grimes } 18678fae3551SRodney W. Grimes } 18688fae3551SRodney W. Grimes 18698fae3551SRodney W. Grimes /* 1870a9148abdSDoug Rabson * Parse a colon separated list of security flavors 1871a9148abdSDoug Rabson */ 1872a9148abdSDoug Rabson int 1873a7a7d96cSPhilippe Charnier parsesec(char *seclist, struct exportlist *ep) 1874a9148abdSDoug Rabson { 1875a9148abdSDoug Rabson char *cp, savedc; 1876a9148abdSDoug Rabson int flavor; 1877a9148abdSDoug Rabson 1878a9148abdSDoug Rabson ep->ex_numsecflavors = 0; 1879a9148abdSDoug Rabson for (;;) { 1880a9148abdSDoug Rabson cp = strchr(seclist, ':'); 1881a9148abdSDoug Rabson if (cp) { 1882a9148abdSDoug Rabson savedc = *cp; 1883a9148abdSDoug Rabson *cp = '\0'; 1884a9148abdSDoug Rabson } 1885a9148abdSDoug Rabson 1886a9148abdSDoug Rabson if (!strcmp(seclist, "sys")) 1887a9148abdSDoug Rabson flavor = AUTH_SYS; 1888a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5")) 1889a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5; 1890a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5i")) 1891a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5I; 1892a9148abdSDoug Rabson else if (!strcmp(seclist, "krb5p")) 1893a9148abdSDoug Rabson flavor = RPCSEC_GSS_KRB5P; 1894a9148abdSDoug Rabson else { 1895a9148abdSDoug Rabson if (cp) 1896a9148abdSDoug Rabson *cp = savedc; 1897a9148abdSDoug Rabson syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1898a9148abdSDoug Rabson return (1); 1899a9148abdSDoug Rabson } 1900a9148abdSDoug Rabson if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1901a9148abdSDoug Rabson if (cp) 1902a9148abdSDoug Rabson *cp = savedc; 1903a9148abdSDoug Rabson syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1904a9148abdSDoug Rabson return (1); 1905a9148abdSDoug Rabson } 1906a9148abdSDoug Rabson ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1907a9148abdSDoug Rabson ep->ex_numsecflavors++; 1908a9148abdSDoug Rabson if (cp) { 1909a9148abdSDoug Rabson *cp = savedc; 1910a9148abdSDoug Rabson seclist = cp + 1; 1911a9148abdSDoug Rabson } else { 1912a9148abdSDoug Rabson break; 1913a9148abdSDoug Rabson } 1914a9148abdSDoug Rabson } 1915a9148abdSDoug Rabson return (0); 1916a9148abdSDoug Rabson } 1917a9148abdSDoug Rabson 1918a9148abdSDoug Rabson /* 19198fae3551SRodney W. Grimes * Parse the option string and update fields. 19208fae3551SRodney W. Grimes * Option arguments may either be -<option>=<value> or 19218fae3551SRodney W. Grimes * -<option> <value> 19228fae3551SRodney W. Grimes */ 19238fae3551SRodney W. Grimes int 1924a7a7d96cSPhilippe Charnier do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 1925a7a7d96cSPhilippe Charnier int *has_hostp, int *exflagsp, struct xucred *cr) 19268fae3551SRodney W. Grimes { 19278fae3551SRodney W. Grimes char *cpoptarg, *cpoptend; 19288fae3551SRodney W. Grimes char *cp, *endcp, *cpopt, savedc, savedc2; 19298fae3551SRodney W. Grimes int allflag, usedarg; 19308fae3551SRodney W. Grimes 1931cb479b11SAlfred Perlstein savedc2 = '\0'; 19328fae3551SRodney W. Grimes cpopt = *cpp; 19338fae3551SRodney W. Grimes cpopt++; 19348fae3551SRodney W. Grimes cp = *endcpp; 19358fae3551SRodney W. Grimes savedc = *cp; 19368fae3551SRodney W. Grimes *cp = '\0'; 19378fae3551SRodney W. Grimes while (cpopt && *cpopt) { 19388fae3551SRodney W. Grimes allflag = 1; 19398fae3551SRodney W. Grimes usedarg = -2; 194074853402SPhilippe Charnier if ((cpoptend = strchr(cpopt, ','))) { 19418fae3551SRodney W. Grimes *cpoptend++ = '\0'; 194274853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 19438fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 19448fae3551SRodney W. Grimes } else { 194574853402SPhilippe Charnier if ((cpoptarg = strchr(cpopt, '='))) 19468fae3551SRodney W. Grimes *cpoptarg++ = '\0'; 19478fae3551SRodney W. Grimes else { 19488fae3551SRodney W. Grimes *cp = savedc; 19498fae3551SRodney W. Grimes nextfield(&cp, &endcp); 19508fae3551SRodney W. Grimes **endcpp = '\0'; 19518fae3551SRodney W. Grimes if (endcp > cp && *cp != '-') { 19528fae3551SRodney W. Grimes cpoptarg = cp; 19538fae3551SRodney W. Grimes savedc2 = *endcp; 19548fae3551SRodney W. Grimes *endcp = '\0'; 19558fae3551SRodney W. Grimes usedarg = 0; 19568fae3551SRodney W. Grimes } 19578fae3551SRodney W. Grimes } 19588fae3551SRodney W. Grimes } 19598fae3551SRodney W. Grimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 19608fae3551SRodney W. Grimes *exflagsp |= MNT_EXRDONLY; 19618fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 19628fae3551SRodney W. Grimes !(allflag = strcmp(cpopt, "mapall")) || 19638fae3551SRodney W. Grimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 19648fae3551SRodney W. Grimes usedarg++; 19658fae3551SRodney W. Grimes parsecred(cpoptarg, cr); 19668fae3551SRodney W. Grimes if (allflag == 0) { 19678fae3551SRodney W. Grimes *exflagsp |= MNT_EXPORTANON; 19688fae3551SRodney W. Grimes opt_flags |= OP_MAPALL; 19698fae3551SRodney W. Grimes } else 19708fae3551SRodney W. Grimes opt_flags |= OP_MAPROOT; 19718fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 19728fae3551SRodney W. Grimes !strcmp(cpopt, "m"))) { 19738fae3551SRodney W. Grimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 197474853402SPhilippe Charnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 19758fae3551SRodney W. Grimes return (1); 19768fae3551SRodney W. Grimes } 19778fae3551SRodney W. Grimes usedarg++; 19788fae3551SRodney W. Grimes opt_flags |= OP_MASK; 19798fae3551SRodney W. Grimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 19808fae3551SRodney W. Grimes !strcmp(cpopt, "n"))) { 19818360efbdSAlfred Perlstein if (strchr(cpoptarg, '/') != NULL) { 19828360efbdSAlfred Perlstein if (debug) 19838360efbdSAlfred Perlstein fprintf(stderr, "setting OP_MASKLEN\n"); 19848360efbdSAlfred Perlstein opt_flags |= OP_MASKLEN; 19858360efbdSAlfred Perlstein } 19868fae3551SRodney W. Grimes if (grp->gr_type != GT_NULL) { 198774853402SPhilippe Charnier syslog(LOG_ERR, "network/host conflict"); 19888fae3551SRodney W. Grimes return (1); 19898fae3551SRodney W. Grimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 199074853402SPhilippe Charnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 19918fae3551SRodney W. Grimes return (1); 19928fae3551SRodney W. Grimes } 19938fae3551SRodney W. Grimes grp->gr_type = GT_NET; 19948fae3551SRodney W. Grimes *has_hostp = 1; 19958fae3551SRodney W. Grimes usedarg++; 19968fae3551SRodney W. Grimes opt_flags |= OP_NET; 19978fae3551SRodney W. Grimes } else if (!strcmp(cpopt, "alldirs")) { 19988fae3551SRodney W. Grimes opt_flags |= OP_ALLDIRS; 1999cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "public")) { 2000cb3923e0SDoug Rabson *exflagsp |= MNT_EXPUBLIC; 2001cb3923e0SDoug Rabson } else if (!strcmp(cpopt, "webnfs")) { 2002cb3923e0SDoug Rabson *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2003cb3923e0SDoug Rabson opt_flags |= OP_MAPALL; 2004cb3923e0SDoug Rabson } else if (cpoptarg && !strcmp(cpopt, "index")) { 2005cb3923e0SDoug Rabson ep->ex_indexfile = strdup(cpoptarg); 2006288fa14aSJoerg Wunsch } else if (!strcmp(cpopt, "quiet")) { 2007288fa14aSJoerg Wunsch opt_flags |= OP_QUIET; 2008a9148abdSDoug Rabson } else if (!strcmp(cpopt, "sec")) { 2009a9148abdSDoug Rabson if (parsesec(cpoptarg, ep)) 2010a9148abdSDoug Rabson return (1); 2011a9148abdSDoug Rabson opt_flags |= OP_SEC; 2012a9148abdSDoug Rabson usedarg++; 20138fae3551SRodney W. Grimes } else { 201474853402SPhilippe Charnier syslog(LOG_ERR, "bad opt %s", cpopt); 20158fae3551SRodney W. Grimes return (1); 20168fae3551SRodney W. Grimes } 20178fae3551SRodney W. Grimes if (usedarg >= 0) { 20188fae3551SRodney W. Grimes *endcp = savedc2; 20198fae3551SRodney W. Grimes **endcpp = savedc; 20208fae3551SRodney W. Grimes if (usedarg > 0) { 20218fae3551SRodney W. Grimes *cpp = cp; 20228fae3551SRodney W. Grimes *endcpp = endcp; 20238fae3551SRodney W. Grimes } 20248fae3551SRodney W. Grimes return (0); 20258fae3551SRodney W. Grimes } 20268fae3551SRodney W. Grimes cpopt = cpoptend; 20278fae3551SRodney W. Grimes } 20288fae3551SRodney W. Grimes **endcpp = savedc; 20298fae3551SRodney W. Grimes return (0); 20308fae3551SRodney W. Grimes } 20318fae3551SRodney W. Grimes 20328fae3551SRodney W. Grimes /* 20338fae3551SRodney W. Grimes * Translate a character string to the corresponding list of network 20348fae3551SRodney W. Grimes * addresses for a hostname. 20358fae3551SRodney W. Grimes */ 20368fae3551SRodney W. Grimes int 2037a7a7d96cSPhilippe Charnier get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 20388fae3551SRodney W. Grimes { 20398b5a6d67SBill Paul struct grouplist *checkgrp; 204001709abfSIan Dowse struct addrinfo *ai, *tai, hints; 20418360efbdSAlfred Perlstein int ecode; 20428360efbdSAlfred Perlstein char host[NI_MAXHOST]; 20438fae3551SRodney W. Grimes 20448360efbdSAlfred Perlstein if (grp->gr_type != GT_NULL) { 20458360efbdSAlfred Perlstein syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 20468fae3551SRodney W. Grimes return (1); 20478fae3551SRodney W. Grimes } 20488360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 20498360efbdSAlfred Perlstein hints.ai_flags = AI_CANONNAME; 20508360efbdSAlfred Perlstein hints.ai_protocol = IPPROTO_UDP; 20518360efbdSAlfred Perlstein ecode = getaddrinfo(cp, NULL, &hints, &ai); 20528360efbdSAlfred Perlstein if (ecode != 0) { 205301709abfSIan Dowse syslog(LOG_ERR,"can't get address info for host %s", cp); 20548360efbdSAlfred Perlstein return 1; 20558fae3551SRodney W. Grimes } 20568360efbdSAlfred Perlstein grp->gr_ptr.gt_addrinfo = ai; 20578360efbdSAlfred Perlstein while (ai != NULL) { 20588360efbdSAlfred Perlstein if (ai->ai_canonname == NULL) { 20598360efbdSAlfred Perlstein if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 20604f101318SHajimu UMEMOTO sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 20618360efbdSAlfred Perlstein strlcpy(host, "?", sizeof(host)); 20628360efbdSAlfred Perlstein ai->ai_canonname = strdup(host); 20638360efbdSAlfred Perlstein ai->ai_flags |= AI_CANONNAME; 20646d359f31SIan Dowse } 20658fae3551SRodney W. Grimes if (debug) 206601709abfSIan Dowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 206701709abfSIan Dowse /* 206801709abfSIan Dowse * Sanity check: make sure we don't already have an entry 206901709abfSIan Dowse * for this host in the grouplist. 207001709abfSIan Dowse */ 207101709abfSIan Dowse for (checkgrp = tgrp; checkgrp != NULL; 207201709abfSIan Dowse checkgrp = checkgrp->gr_next) { 207301709abfSIan Dowse if (checkgrp->gr_type != GT_HOST) 207401709abfSIan Dowse continue; 207501709abfSIan Dowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 207601709abfSIan Dowse tai = tai->ai_next) { 207760caaee2SIan Dowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 207801709abfSIan Dowse continue; 207901709abfSIan Dowse if (debug) 208001709abfSIan Dowse fprintf(stderr, 208101709abfSIan Dowse "ignoring duplicate host %s\n", 208201709abfSIan Dowse ai->ai_canonname); 208301709abfSIan Dowse grp->gr_type = GT_IGNORE; 208401709abfSIan Dowse return (0); 208501709abfSIan Dowse } 208601709abfSIan Dowse } 20878360efbdSAlfred Perlstein ai = ai->ai_next; 20888360efbdSAlfred Perlstein } 208901709abfSIan Dowse grp->gr_type = GT_HOST; 20908fae3551SRodney W. Grimes return (0); 20918fae3551SRodney W. Grimes } 20928fae3551SRodney W. Grimes 20938fae3551SRodney W. Grimes /* 20948fae3551SRodney W. Grimes * Free up an exports list component 20958fae3551SRodney W. Grimes */ 20968fae3551SRodney W. Grimes void 2097a7a7d96cSPhilippe Charnier free_exp(struct exportlist *ep) 20988fae3551SRodney W. Grimes { 20998fae3551SRodney W. Grimes 21008fae3551SRodney W. Grimes if (ep->ex_defdir) { 21018fae3551SRodney W. Grimes free_host(ep->ex_defdir->dp_hosts); 21028fae3551SRodney W. Grimes free((caddr_t)ep->ex_defdir); 21038fae3551SRodney W. Grimes } 21048fae3551SRodney W. Grimes if (ep->ex_fsdir) 21058fae3551SRodney W. Grimes free(ep->ex_fsdir); 2106cb3923e0SDoug Rabson if (ep->ex_indexfile) 2107cb3923e0SDoug Rabson free(ep->ex_indexfile); 21088fae3551SRodney W. Grimes free_dir(ep->ex_dirl); 21098fae3551SRodney W. Grimes free((caddr_t)ep); 21108fae3551SRodney W. Grimes } 21118fae3551SRodney W. Grimes 21128fae3551SRodney W. Grimes /* 21138fae3551SRodney W. Grimes * Free hosts. 21148fae3551SRodney W. Grimes */ 21158fae3551SRodney W. Grimes void 2116a7a7d96cSPhilippe Charnier free_host(struct hostlist *hp) 21178fae3551SRodney W. Grimes { 21188fae3551SRodney W. Grimes struct hostlist *hp2; 21198fae3551SRodney W. Grimes 21208fae3551SRodney W. Grimes while (hp) { 21218fae3551SRodney W. Grimes hp2 = hp; 21228fae3551SRodney W. Grimes hp = hp->ht_next; 21238fae3551SRodney W. Grimes free((caddr_t)hp2); 21248fae3551SRodney W. Grimes } 21258fae3551SRodney W. Grimes } 21268fae3551SRodney W. Grimes 21278fae3551SRodney W. Grimes struct hostlist * 2128a7a7d96cSPhilippe Charnier get_ht(void) 21298fae3551SRodney W. Grimes { 21308fae3551SRodney W. Grimes struct hostlist *hp; 21318fae3551SRodney W. Grimes 21328fae3551SRodney W. Grimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 21338fae3551SRodney W. Grimes if (hp == (struct hostlist *)NULL) 21348fae3551SRodney W. Grimes out_of_mem(); 21358fae3551SRodney W. Grimes hp->ht_next = (struct hostlist *)NULL; 2136a62dc406SDoug Rabson hp->ht_flag = 0; 21378fae3551SRodney W. Grimes return (hp); 21388fae3551SRodney W. Grimes } 21398fae3551SRodney W. Grimes 21408fae3551SRodney W. Grimes /* 21418fae3551SRodney W. Grimes * Out of memory, fatal 21428fae3551SRodney W. Grimes */ 21438fae3551SRodney W. Grimes void 2144a7a7d96cSPhilippe Charnier out_of_mem(void) 21458fae3551SRodney W. Grimes { 21468fae3551SRodney W. Grimes 214774853402SPhilippe Charnier syslog(LOG_ERR, "out of memory"); 21488fae3551SRodney W. Grimes exit(2); 21498fae3551SRodney W. Grimes } 21508fae3551SRodney W. Grimes 21518fae3551SRodney W. Grimes /* 21526a09faf2SCraig Rodrigues * Do the nmount() syscall with the update flag to push the export info into 21538fae3551SRodney W. Grimes * the kernel. 21548fae3551SRodney W. Grimes */ 21558fae3551SRodney W. Grimes int 21566a09faf2SCraig Rodrigues do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 21576a09faf2SCraig Rodrigues struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 21588fae3551SRodney W. Grimes { 2159f93caef2SIan Dowse struct statfs fsb1; 21608360efbdSAlfred Perlstein struct addrinfo *ai; 2161bcc1d071SRick Macklem struct export_args ea, *eap; 21626a09faf2SCraig Rodrigues char errmsg[255]; 21636a09faf2SCraig Rodrigues char *cp; 21648fae3551SRodney W. Grimes int done; 21656a09faf2SCraig Rodrigues char savedc; 21666a09faf2SCraig Rodrigues struct iovec *iov; 2167a9148abdSDoug Rabson int i, iovlen; 21686a09faf2SCraig Rodrigues int ret; 2169bcc1d071SRick Macklem struct nfsex_args nfsea; 2170bcc1d071SRick Macklem 2171bcc1d071SRick Macklem if (run_v4server > 0) 2172bcc1d071SRick Macklem eap = &nfsea.export; 2173bcc1d071SRick Macklem else 2174bcc1d071SRick Macklem eap = &ea; 21758fae3551SRodney W. Grimes 21766a09faf2SCraig Rodrigues cp = NULL; 21776a09faf2SCraig Rodrigues savedc = '\0'; 21786a09faf2SCraig Rodrigues iov = NULL; 21796a09faf2SCraig Rodrigues iovlen = 0; 21806a09faf2SCraig Rodrigues ret = 0; 218160caaee2SIan Dowse 2182bcc1d071SRick Macklem bzero(eap, sizeof (struct export_args)); 21836a09faf2SCraig Rodrigues bzero(errmsg, sizeof(errmsg)); 2184bcc1d071SRick Macklem eap->ex_flags = exflags; 2185bcc1d071SRick Macklem eap->ex_anon = *anoncrp; 2186bcc1d071SRick Macklem eap->ex_indexfile = ep->ex_indexfile; 21876d359f31SIan Dowse if (grp->gr_type == GT_HOST) 21888360efbdSAlfred Perlstein ai = grp->gr_ptr.gt_addrinfo; 21896d359f31SIan Dowse else 21906d359f31SIan Dowse ai = NULL; 2191bcc1d071SRick Macklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2192bcc1d071SRick Macklem for (i = 0; i < eap->ex_numsecflavors; i++) 2193bcc1d071SRick Macklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2194bcc1d071SRick Macklem if (eap->ex_numsecflavors == 0) { 2195bcc1d071SRick Macklem eap->ex_numsecflavors = 1; 2196bcc1d071SRick Macklem eap->ex_secflavors[0] = AUTH_SYS; 2197a9148abdSDoug Rabson } 21988fae3551SRodney W. Grimes done = FALSE; 21996a09faf2SCraig Rodrigues 2200bcc1d071SRick Macklem if (v4root_phase == 0) { 22016a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fstype", NULL, 0); 22026a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "fspath", NULL, 0); 22036a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "from", NULL, 0); 22046a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "update", NULL, 0); 2205bcc1d071SRick Macklem build_iovec(&iov, &iovlen, "export", eap, 2206bcc1d071SRick Macklem sizeof (struct export_args)); 22076a09faf2SCraig Rodrigues build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2208bcc1d071SRick Macklem } 22096a09faf2SCraig Rodrigues 22108fae3551SRodney W. Grimes while (!done) { 22118fae3551SRodney W. Grimes switch (grp->gr_type) { 22128fae3551SRodney W. Grimes case GT_HOST: 22136d359f31SIan Dowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 22148360efbdSAlfred Perlstein goto skip; 2215bcc1d071SRick Macklem eap->ex_addr = ai->ai_addr; 2216bcc1d071SRick Macklem eap->ex_addrlen = ai->ai_addrlen; 2217bcc1d071SRick Macklem eap->ex_masklen = 0; 22188fae3551SRodney W. Grimes break; 22198fae3551SRodney W. Grimes case GT_NET: 222060caaee2SIan Dowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 22218360efbdSAlfred Perlstein have_v6 == 0) 22228360efbdSAlfred Perlstein goto skip; 2223bcc1d071SRick Macklem eap->ex_addr = 222460caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2225bcc1d071SRick Macklem eap->ex_addrlen = 22266a09faf2SCraig Rodrigues ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2227bcc1d071SRick Macklem eap->ex_mask = 222860caaee2SIan Dowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2229bcc1d071SRick Macklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 22308fae3551SRodney W. Grimes break; 22316d359f31SIan Dowse case GT_DEFAULT: 2232bcc1d071SRick Macklem eap->ex_addr = NULL; 2233bcc1d071SRick Macklem eap->ex_addrlen = 0; 2234bcc1d071SRick Macklem eap->ex_mask = NULL; 2235bcc1d071SRick Macklem eap->ex_masklen = 0; 22366d359f31SIan Dowse break; 22378b5a6d67SBill Paul case GT_IGNORE: 22386a09faf2SCraig Rodrigues ret = 0; 22396a09faf2SCraig Rodrigues goto error_exit; 22408b5a6d67SBill Paul break; 22418fae3551SRodney W. Grimes default: 224274853402SPhilippe Charnier syslog(LOG_ERR, "bad grouptype"); 22438fae3551SRodney W. Grimes if (cp) 22448fae3551SRodney W. Grimes *cp = savedc; 22456a09faf2SCraig Rodrigues ret = 1; 22466a09faf2SCraig Rodrigues goto error_exit; 22478fae3551SRodney W. Grimes }; 22488fae3551SRodney W. Grimes 22498fae3551SRodney W. Grimes /* 2250bcc1d071SRick Macklem * For V4:, use the nfssvc() syscall, instead of mount(). 2251bcc1d071SRick Macklem */ 2252bcc1d071SRick Macklem if (v4root_phase == 2) { 2253bcc1d071SRick Macklem nfsea.fspec = v4root_dirpath; 2254bcc1d071SRick Macklem if (run_v4server > 0 && 2255bcc1d071SRick Macklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2256bcc1d071SRick Macklem syslog(LOG_ERR, "Exporting V4: failed"); 2257bcc1d071SRick Macklem return (2); 2258bcc1d071SRick Macklem } 2259bcc1d071SRick Macklem } else { 2260bcc1d071SRick Macklem /* 22618fae3551SRodney W. Grimes * XXX: 2262bcc1d071SRick Macklem * Maybe I should just use the fsb->f_mntonname path 2263bcc1d071SRick Macklem * instead of looping back up the dirp to the mount 2264bcc1d071SRick Macklem * point?? 22658fae3551SRodney W. Grimes * Also, needs to know how to export all types of local 226687564113SPeter Wemm * exportable filesystems and not just "ufs". 22678fae3551SRodney W. Grimes */ 22686a09faf2SCraig Rodrigues iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 22696a09faf2SCraig Rodrigues iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 22706a09faf2SCraig Rodrigues iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 22716a09faf2SCraig Rodrigues iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 22726a09faf2SCraig Rodrigues iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 22736a09faf2SCraig Rodrigues iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 22746a09faf2SCraig Rodrigues 227555dd1327SCraig Rodrigues while (nmount(iov, iovlen, fsb->f_flags) < 0) { 22768fae3551SRodney W. Grimes if (cp) 22778fae3551SRodney W. Grimes *cp-- = savedc; 22788fae3551SRodney W. Grimes else 22798fae3551SRodney W. Grimes cp = dirp + dirplen - 1; 22806a09faf2SCraig Rodrigues if (opt_flags & OP_QUIET) { 22816a09faf2SCraig Rodrigues ret = 1; 22826a09faf2SCraig Rodrigues goto error_exit; 22836a09faf2SCraig Rodrigues } 22848fae3551SRodney W. Grimes if (errno == EPERM) { 228501709abfSIan Dowse if (debug) 228601709abfSIan Dowse warnx("can't change attributes for %s", 228701709abfSIan Dowse dirp); 22888fae3551SRodney W. Grimes syslog(LOG_ERR, 2289bcc1d071SRick Macklem "can't change attributes for %s", 2290bcc1d071SRick Macklem dirp); 22916a09faf2SCraig Rodrigues ret = 1; 22926a09faf2SCraig Rodrigues goto error_exit; 22938fae3551SRodney W. Grimes } 22948fae3551SRodney W. Grimes if (opt_flags & OP_ALLDIRS) { 2295288fa14aSJoerg Wunsch if (errno == EINVAL) 2296288fa14aSJoerg Wunsch syslog(LOG_ERR, 2297288fa14aSJoerg Wunsch "-alldirs requested but %s is not a filesystem mountpoint", 2298288fa14aSJoerg Wunsch dirp); 2299288fa14aSJoerg Wunsch else 2300288fa14aSJoerg Wunsch syslog(LOG_ERR, 2301288fa14aSJoerg Wunsch "could not remount %s: %m", 23023980ac4fSGarrett Wollman dirp); 23036a09faf2SCraig Rodrigues ret = 1; 23046a09faf2SCraig Rodrigues goto error_exit; 23058fae3551SRodney W. Grimes } 23068fae3551SRodney W. Grimes /* back up over the last component */ 23078fae3551SRodney W. Grimes while (*cp == '/' && cp > dirp) 23088fae3551SRodney W. Grimes cp--; 23098fae3551SRodney W. Grimes while (*(cp - 1) != '/' && cp > dirp) 23108fae3551SRodney W. Grimes cp--; 23118fae3551SRodney W. Grimes if (cp == dirp) { 23128fae3551SRodney W. Grimes if (debug) 231374853402SPhilippe Charnier warnx("mnt unsucc"); 2314bcc1d071SRick Macklem syslog(LOG_ERR, "can't export %s %s", 2315bcc1d071SRick Macklem dirp, errmsg); 23166a09faf2SCraig Rodrigues ret = 1; 23176a09faf2SCraig Rodrigues goto error_exit; 23188fae3551SRodney W. Grimes } 23198fae3551SRodney W. Grimes savedc = *cp; 23208fae3551SRodney W. Grimes *cp = '\0'; 2321bcc1d071SRick Macklem /* 2322bcc1d071SRick Macklem * Check that we're still on the same 2323bcc1d071SRick Macklem * filesystem. 2324bcc1d071SRick Macklem */ 2325bcc1d071SRick Macklem if (statfs(dirp, &fsb1) != 0 || 2326bcc1d071SRick Macklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2327bcc1d071SRick Macklem sizeof (fsb1.f_fsid)) != 0) { 2328f93caef2SIan Dowse *cp = savedc; 2329bcc1d071SRick Macklem syslog(LOG_ERR, 2330bcc1d071SRick Macklem "can't export %s %s", dirp, 233137518a88SCraig Rodrigues errmsg); 23326a09faf2SCraig Rodrigues ret = 1; 23336a09faf2SCraig Rodrigues goto error_exit; 2334f93caef2SIan Dowse } 23358fae3551SRodney W. Grimes } 2336bcc1d071SRick Macklem } 2337bcc1d071SRick Macklem 2338bcc1d071SRick Macklem /* 2339bcc1d071SRick Macklem * For the experimental server: 2340bcc1d071SRick Macklem * If this is the public directory, get the file handle 2341bcc1d071SRick Macklem * and load it into the kernel via the nfssvc() syscall. 2342bcc1d071SRick Macklem */ 2343bcc1d071SRick Macklem if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2344bcc1d071SRick Macklem fhandle_t fh; 2345bcc1d071SRick Macklem char *public_name; 2346bcc1d071SRick Macklem 2347bcc1d071SRick Macklem if (eap->ex_indexfile != NULL) 2348bcc1d071SRick Macklem public_name = eap->ex_indexfile; 2349bcc1d071SRick Macklem else 2350bcc1d071SRick Macklem public_name = dirp; 2351bcc1d071SRick Macklem if (getfh(public_name, &fh) < 0) 2352bcc1d071SRick Macklem syslog(LOG_ERR, 2353bcc1d071SRick Macklem "Can't get public fh for %s", public_name); 2354bcc1d071SRick Macklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2355bcc1d071SRick Macklem syslog(LOG_ERR, 2356bcc1d071SRick Macklem "Can't set public fh for %s", public_name); 2357bcc1d071SRick Macklem else 2358bcc1d071SRick Macklem has_publicfh = 1; 2359bcc1d071SRick Macklem } 23608360efbdSAlfred Perlstein skip: 23616d359f31SIan Dowse if (ai != NULL) 23628360efbdSAlfred Perlstein ai = ai->ai_next; 23638360efbdSAlfred Perlstein if (ai == NULL) 23648fae3551SRodney W. Grimes done = TRUE; 23658fae3551SRodney W. Grimes } 23668fae3551SRodney W. Grimes if (cp) 23678fae3551SRodney W. Grimes *cp = savedc; 23686a09faf2SCraig Rodrigues error_exit: 23696a09faf2SCraig Rodrigues /* free strings allocated by strdup() in getmntopts.c */ 23706a09faf2SCraig Rodrigues if (iov != NULL) { 23716a09faf2SCraig Rodrigues free(iov[0].iov_base); /* fstype */ 23726a09faf2SCraig Rodrigues free(iov[2].iov_base); /* fspath */ 23736a09faf2SCraig Rodrigues free(iov[4].iov_base); /* from */ 23746a09faf2SCraig Rodrigues free(iov[6].iov_base); /* update */ 23756a09faf2SCraig Rodrigues free(iov[8].iov_base); /* export */ 23766a09faf2SCraig Rodrigues free(iov[10].iov_base); /* errmsg */ 23776a09faf2SCraig Rodrigues 23786a09faf2SCraig Rodrigues /* free iov, allocated by realloc() */ 23796a09faf2SCraig Rodrigues free(iov); 23806a09faf2SCraig Rodrigues } 23816a09faf2SCraig Rodrigues return (ret); 23828fae3551SRodney W. Grimes } 23838fae3551SRodney W. Grimes 23848fae3551SRodney W. Grimes /* 23858fae3551SRodney W. Grimes * Translate a net address. 238660caaee2SIan Dowse * 238760caaee2SIan Dowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 23888fae3551SRodney W. Grimes */ 23898fae3551SRodney W. Grimes int 2390a7a7d96cSPhilippe Charnier get_net(char *cp, struct netmsk *net, int maskflg) 23918fae3551SRodney W. Grimes { 2392931c04f1SIan Dowse struct netent *np = NULL; 23938360efbdSAlfred Perlstein char *name, *p, *prefp; 239460caaee2SIan Dowse struct sockaddr_in sin; 2395931c04f1SIan Dowse struct sockaddr *sa = NULL; 23968360efbdSAlfred Perlstein struct addrinfo hints, *ai = NULL; 23978360efbdSAlfred Perlstein char netname[NI_MAXHOST]; 23988360efbdSAlfred Perlstein long preflen; 23998fae3551SRodney W. Grimes 240001709abfSIan Dowse p = prefp = NULL; 24018360efbdSAlfred Perlstein if ((opt_flags & OP_MASKLEN) && !maskflg) { 24028360efbdSAlfred Perlstein p = strchr(cp, '/'); 24038360efbdSAlfred Perlstein *p = '\0'; 24048360efbdSAlfred Perlstein prefp = p + 1; 24058360efbdSAlfred Perlstein } 24068360efbdSAlfred Perlstein 2407931c04f1SIan Dowse /* 2408931c04f1SIan Dowse * Check for a numeric address first. We wish to avoid 2409931c04f1SIan Dowse * possible DNS lookups in getnetbyname(). 2410931c04f1SIan Dowse */ 2411931c04f1SIan Dowse if (isxdigit(*cp) || *cp == ':') { 24128360efbdSAlfred Perlstein memset(&hints, 0, sizeof hints); 241360caaee2SIan Dowse /* Ensure the mask and the network have the same family. */ 241460caaee2SIan Dowse if (maskflg && (opt_flags & OP_NET)) 241560caaee2SIan Dowse hints.ai_family = net->nt_net.ss_family; 241660caaee2SIan Dowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 241760caaee2SIan Dowse hints.ai_family = net->nt_mask.ss_family; 241860caaee2SIan Dowse else 24198360efbdSAlfred Perlstein hints.ai_family = AF_UNSPEC; 24208360efbdSAlfred Perlstein hints.ai_flags = AI_NUMERICHOST; 2421931c04f1SIan Dowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2422931c04f1SIan Dowse sa = ai->ai_addr; 2423931c04f1SIan Dowse if (sa != NULL && ai->ai_family == AF_INET) { 24248fae3551SRodney W. Grimes /* 242560caaee2SIan Dowse * The address in `cp' is really a network address, so 242660caaee2SIan Dowse * use inet_network() to re-interpret this correctly. 242760caaee2SIan Dowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 24288fae3551SRodney W. Grimes */ 242960caaee2SIan Dowse bzero(&sin, sizeof sin); 24308360efbdSAlfred Perlstein sin.sin_family = AF_INET; 24318360efbdSAlfred Perlstein sin.sin_len = sizeof sin; 24328360efbdSAlfred Perlstein sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 24338360efbdSAlfred Perlstein if (debug) 243460caaee2SIan Dowse fprintf(stderr, "get_net: v4 addr %s\n", 243560caaee2SIan Dowse inet_ntoa(sin.sin_addr)); 24368360efbdSAlfred Perlstein sa = (struct sockaddr *)&sin; 2437931c04f1SIan Dowse } 2438931c04f1SIan Dowse } 2439931c04f1SIan Dowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2440931c04f1SIan Dowse bzero(&sin, sizeof sin); 2441931c04f1SIan Dowse sin.sin_family = AF_INET; 2442931c04f1SIan Dowse sin.sin_len = sizeof sin; 2443931c04f1SIan Dowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 2444931c04f1SIan Dowse sa = (struct sockaddr *)&sin; 2445931c04f1SIan Dowse } 2446931c04f1SIan Dowse if (sa == NULL) 24478360efbdSAlfred Perlstein goto fail; 24488360efbdSAlfred Perlstein 244960caaee2SIan Dowse if (maskflg) { 245060caaee2SIan Dowse /* The specified sockaddr is a mask. */ 245160caaee2SIan Dowse if (checkmask(sa) != 0) 24528360efbdSAlfred Perlstein goto fail; 245360caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 245460caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 245560caaee2SIan Dowse } else { 245660caaee2SIan Dowse /* The specified sockaddr is a network address. */ 245760caaee2SIan Dowse bcopy(sa, &net->nt_net, sa->sa_len); 24580f4b7baaSPaul Traina 245960caaee2SIan Dowse /* Get a network name for the export list. */ 246060caaee2SIan Dowse if (np) { 246160caaee2SIan Dowse name = np->n_name; 246260caaee2SIan Dowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 24634f101318SHajimu UMEMOTO NULL, 0, NI_NUMERICHOST) == 0) { 246460caaee2SIan Dowse name = netname; 246560caaee2SIan Dowse } else { 246660caaee2SIan Dowse goto fail; 246760caaee2SIan Dowse } 246860caaee2SIan Dowse if ((net->nt_name = strdup(name)) == NULL) 246960caaee2SIan Dowse out_of_mem(); 247060caaee2SIan Dowse 247160caaee2SIan Dowse /* 247260caaee2SIan Dowse * Extract a mask from either a "/<masklen>" suffix, or 247360caaee2SIan Dowse * from the class of an IPv4 address. 247460caaee2SIan Dowse */ 24758360efbdSAlfred Perlstein if (opt_flags & OP_MASKLEN) { 24768360efbdSAlfred Perlstein preflen = strtol(prefp, NULL, 10); 247760caaee2SIan Dowse if (preflen < 0L || preflen == LONG_MAX) 24788360efbdSAlfred Perlstein goto fail; 247960caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 248060caaee2SIan Dowse if (makemask(&net->nt_mask, (int)preflen) != 0) 248160caaee2SIan Dowse goto fail; 248260caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 24838360efbdSAlfred Perlstein *p = '/'; 248460caaee2SIan Dowse } else if (sa->sa_family == AF_INET && 248560caaee2SIan Dowse (opt_flags & OP_MASK) == 0) { 248660caaee2SIan Dowse in_addr_t addr; 24878360efbdSAlfred Perlstein 248860caaee2SIan Dowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 248960caaee2SIan Dowse if (IN_CLASSA(addr)) 249060caaee2SIan Dowse preflen = 8; 249160caaee2SIan Dowse else if (IN_CLASSB(addr)) 249260caaee2SIan Dowse preflen = 16; 249360caaee2SIan Dowse else if (IN_CLASSC(addr)) 249460caaee2SIan Dowse preflen = 24; 249560caaee2SIan Dowse else if (IN_CLASSD(addr)) 249660caaee2SIan Dowse preflen = 28; 24978360efbdSAlfred Perlstein else 249860caaee2SIan Dowse preflen = 32; /* XXX */ 249960caaee2SIan Dowse 250060caaee2SIan Dowse bcopy(sa, &net->nt_mask, sa->sa_len); 250160caaee2SIan Dowse makemask(&net->nt_mask, (int)preflen); 250260caaee2SIan Dowse opt_flags |= OP_HAVEMASK; 250360caaee2SIan Dowse } 25048360efbdSAlfred Perlstein } 25058360efbdSAlfred Perlstein 25068360efbdSAlfred Perlstein if (ai) 25078360efbdSAlfred Perlstein freeaddrinfo(ai); 25088360efbdSAlfred Perlstein return 0; 25098360efbdSAlfred Perlstein 25108360efbdSAlfred Perlstein fail: 25118360efbdSAlfred Perlstein if (ai) 25128360efbdSAlfred Perlstein freeaddrinfo(ai); 25138360efbdSAlfred Perlstein return 1; 25148fae3551SRodney W. Grimes } 25158fae3551SRodney W. Grimes 25168fae3551SRodney W. Grimes /* 25178fae3551SRodney W. Grimes * Parse out the next white space separated field 25188fae3551SRodney W. Grimes */ 25198fae3551SRodney W. Grimes void 2520a7a7d96cSPhilippe Charnier nextfield(char **cp, char **endcp) 25218fae3551SRodney W. Grimes { 25228fae3551SRodney W. Grimes char *p; 25238fae3551SRodney W. Grimes 25248fae3551SRodney W. Grimes p = *cp; 25258fae3551SRodney W. Grimes while (*p == ' ' || *p == '\t') 25268fae3551SRodney W. Grimes p++; 25278fae3551SRodney W. Grimes if (*p == '\n' || *p == '\0') 25288fae3551SRodney W. Grimes *cp = *endcp = p; 25298fae3551SRodney W. Grimes else { 25308fae3551SRodney W. Grimes *cp = p++; 25318fae3551SRodney W. Grimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 25328fae3551SRodney W. Grimes p++; 25338fae3551SRodney W. Grimes *endcp = p; 25348fae3551SRodney W. Grimes } 25358fae3551SRodney W. Grimes } 25368fae3551SRodney W. Grimes 25378fae3551SRodney W. Grimes /* 25388fae3551SRodney W. Grimes * Get an exports file line. Skip over blank lines and handle line 25398fae3551SRodney W. Grimes * continuations. 25408fae3551SRodney W. Grimes */ 25418fae3551SRodney W. Grimes int 2542a7a7d96cSPhilippe Charnier get_line(void) 25438fae3551SRodney W. Grimes { 25448fae3551SRodney W. Grimes char *p, *cp; 254591ca1a91SIan Dowse size_t len; 25468fae3551SRodney W. Grimes int totlen, cont_line; 25478fae3551SRodney W. Grimes 25488fae3551SRodney W. Grimes /* 25498fae3551SRodney W. Grimes * Loop around ignoring blank lines and getting all continuation lines. 25508fae3551SRodney W. Grimes */ 25518fae3551SRodney W. Grimes p = line; 25528fae3551SRodney W. Grimes totlen = 0; 25538fae3551SRodney W. Grimes do { 255491ca1a91SIan Dowse if ((p = fgetln(exp_file, &len)) == NULL) 25558fae3551SRodney W. Grimes return (0); 25568fae3551SRodney W. Grimes cp = p + len - 1; 25578fae3551SRodney W. Grimes cont_line = 0; 25588fae3551SRodney W. Grimes while (cp >= p && 25598fae3551SRodney W. Grimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 25608fae3551SRodney W. Grimes if (*cp == '\\') 25618fae3551SRodney W. Grimes cont_line = 1; 25628fae3551SRodney W. Grimes cp--; 25638fae3551SRodney W. Grimes len--; 25648fae3551SRodney W. Grimes } 2565376f8390SDima Dorfman if (cont_line) { 2566376f8390SDima Dorfman *++cp = ' '; 2567376f8390SDima Dorfman len++; 2568376f8390SDima Dorfman } 256991ca1a91SIan Dowse if (linesize < len + totlen + 1) { 257091ca1a91SIan Dowse linesize = len + totlen + 1; 257191ca1a91SIan Dowse line = realloc(line, linesize); 257291ca1a91SIan Dowse if (line == NULL) 257391ca1a91SIan Dowse out_of_mem(); 257491ca1a91SIan Dowse } 257591ca1a91SIan Dowse memcpy(line + totlen, p, len); 25768fae3551SRodney W. Grimes totlen += len; 257791ca1a91SIan Dowse line[totlen] = '\0'; 25788fae3551SRodney W. Grimes } while (totlen == 0 || cont_line); 25798fae3551SRodney W. Grimes return (1); 25808fae3551SRodney W. Grimes } 25818fae3551SRodney W. Grimes 25828fae3551SRodney W. Grimes /* 25838fae3551SRodney W. Grimes * Parse a description of a credential. 25848fae3551SRodney W. Grimes */ 25858fae3551SRodney W. Grimes void 2586a7a7d96cSPhilippe Charnier parsecred(char *namelist, struct xucred *cr) 25878fae3551SRodney W. Grimes { 25888fae3551SRodney W. Grimes char *name; 25898fae3551SRodney W. Grimes int cnt; 25908fae3551SRodney W. Grimes char *names; 25918fae3551SRodney W. Grimes struct passwd *pw; 25928fae3551SRodney W. Grimes struct group *gr; 2593838d9858SBrooks Davis gid_t groups[XU_NGROUPS + 1]; 2594950cc395SStefan Farfeleder int ngroups; 25958fae3551SRodney W. Grimes 259676183f34SDima Dorfman cr->cr_version = XUCRED_VERSION; 25978fae3551SRodney W. Grimes /* 259874853402SPhilippe Charnier * Set up the unprivileged user. 25998fae3551SRodney W. Grimes */ 26008fae3551SRodney W. Grimes cr->cr_uid = -2; 26018fae3551SRodney W. Grimes cr->cr_groups[0] = -2; 26028fae3551SRodney W. Grimes cr->cr_ngroups = 1; 26038fae3551SRodney W. Grimes /* 26048fae3551SRodney W. Grimes * Get the user's password table entry. 26058fae3551SRodney W. Grimes */ 26068fae3551SRodney W. Grimes names = strsep(&namelist, " \t\n"); 26078fae3551SRodney W. Grimes name = strsep(&names, ":"); 26088fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') 26098fae3551SRodney W. Grimes pw = getpwuid(atoi(name)); 26108fae3551SRodney W. Grimes else 26118fae3551SRodney W. Grimes pw = getpwnam(name); 26128fae3551SRodney W. Grimes /* 26138fae3551SRodney W. Grimes * Credentials specified as those of a user. 26148fae3551SRodney W. Grimes */ 26158fae3551SRodney W. Grimes if (names == NULL) { 26168fae3551SRodney W. Grimes if (pw == NULL) { 261774853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 26188fae3551SRodney W. Grimes return; 26198fae3551SRodney W. Grimes } 26208fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 2621838d9858SBrooks Davis ngroups = XU_NGROUPS + 1; 26228fae3551SRodney W. Grimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 262374853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 26248fae3551SRodney W. Grimes /* 2625950cc395SStefan Farfeleder * Compress out duplicate. 26268fae3551SRodney W. Grimes */ 26278fae3551SRodney W. Grimes cr->cr_ngroups = ngroups - 1; 26288fae3551SRodney W. Grimes cr->cr_groups[0] = groups[0]; 26298fae3551SRodney W. Grimes for (cnt = 2; cnt < ngroups; cnt++) 26308fae3551SRodney W. Grimes cr->cr_groups[cnt - 1] = groups[cnt]; 26318fae3551SRodney W. Grimes return; 26328fae3551SRodney W. Grimes } 26338fae3551SRodney W. Grimes /* 26348fae3551SRodney W. Grimes * Explicit credential specified as a colon separated list: 26358fae3551SRodney W. Grimes * uid:gid:gid:... 26368fae3551SRodney W. Grimes */ 26378fae3551SRodney W. Grimes if (pw != NULL) 26388fae3551SRodney W. Grimes cr->cr_uid = pw->pw_uid; 26398fae3551SRodney W. Grimes else if (isdigit(*name) || *name == '-') 26408fae3551SRodney W. Grimes cr->cr_uid = atoi(name); 26418fae3551SRodney W. Grimes else { 264274853402SPhilippe Charnier syslog(LOG_ERR, "unknown user: %s", name); 26438fae3551SRodney W. Grimes return; 26448fae3551SRodney W. Grimes } 26458fae3551SRodney W. Grimes cr->cr_ngroups = 0; 2646838d9858SBrooks Davis while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 26478fae3551SRodney W. Grimes name = strsep(&names, ":"); 26488fae3551SRodney W. Grimes if (isdigit(*name) || *name == '-') { 26498fae3551SRodney W. Grimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 26508fae3551SRodney W. Grimes } else { 26518fae3551SRodney W. Grimes if ((gr = getgrnam(name)) == NULL) { 265274853402SPhilippe Charnier syslog(LOG_ERR, "unknown group: %s", name); 26538fae3551SRodney W. Grimes continue; 26548fae3551SRodney W. Grimes } 26558fae3551SRodney W. Grimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 26568fae3551SRodney W. Grimes } 26578fae3551SRodney W. Grimes } 2658838d9858SBrooks Davis if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 265974853402SPhilippe Charnier syslog(LOG_ERR, "too many groups"); 26608fae3551SRodney W. Grimes } 26618fae3551SRodney W. Grimes 26620775314bSDoug Rabson #define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 26638fae3551SRodney W. Grimes /* 26648fae3551SRodney W. Grimes * Routines that maintain the remote mounttab 26658fae3551SRodney W. Grimes */ 26668fae3551SRodney W. Grimes void 2667a7a7d96cSPhilippe Charnier get_mountlist(void) 26688fae3551SRodney W. Grimes { 26698fae3551SRodney W. Grimes struct mountlist *mlp, **mlpp; 267087564113SPeter Wemm char *host, *dirp, *cp; 26718fae3551SRodney W. Grimes char str[STRSIZ]; 26728fae3551SRodney W. Grimes FILE *mlfile; 26738fae3551SRodney W. Grimes 26748fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 267539539916SBill Fumerola if (errno == ENOENT) 267639539916SBill Fumerola return; 267739539916SBill Fumerola else { 267874853402SPhilippe Charnier syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 26798fae3551SRodney W. Grimes return; 26808fae3551SRodney W. Grimes } 268139539916SBill Fumerola } 26828fae3551SRodney W. Grimes mlpp = &mlhead; 26838fae3551SRodney W. Grimes while (fgets(str, STRSIZ, mlfile) != NULL) { 268487564113SPeter Wemm cp = str; 268587564113SPeter Wemm host = strsep(&cp, " \t\n"); 268687564113SPeter Wemm dirp = strsep(&cp, " \t\n"); 268787564113SPeter Wemm if (host == NULL || dirp == NULL) 26888fae3551SRodney W. Grimes continue; 26898fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 269074853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 269174853402SPhilippe Charnier out_of_mem(); 26920775314bSDoug Rabson strncpy(mlp->ml_host, host, MNTNAMLEN); 26930775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 26940775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 26950775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 26968fae3551SRodney W. Grimes mlp->ml_next = (struct mountlist *)NULL; 26978fae3551SRodney W. Grimes *mlpp = mlp; 26988fae3551SRodney W. Grimes mlpp = &mlp->ml_next; 26998fae3551SRodney W. Grimes } 27008fae3551SRodney W. Grimes fclose(mlfile); 27018fae3551SRodney W. Grimes } 27028fae3551SRodney W. Grimes 270301709abfSIan Dowse void 270401709abfSIan Dowse del_mlist(char *hostp, char *dirp) 27058fae3551SRodney W. Grimes { 27068fae3551SRodney W. Grimes struct mountlist *mlp, **mlpp; 27078fae3551SRodney W. Grimes struct mountlist *mlp2; 27088fae3551SRodney W. Grimes FILE *mlfile; 27098fae3551SRodney W. Grimes int fnd = 0; 27108fae3551SRodney W. Grimes 27118fae3551SRodney W. Grimes mlpp = &mlhead; 27128fae3551SRodney W. Grimes mlp = mlhead; 27138fae3551SRodney W. Grimes while (mlp) { 27148fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && 27158fae3551SRodney W. Grimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 27168fae3551SRodney W. Grimes fnd = 1; 27178fae3551SRodney W. Grimes mlp2 = mlp; 27188fae3551SRodney W. Grimes *mlpp = mlp = mlp->ml_next; 27198fae3551SRodney W. Grimes free((caddr_t)mlp2); 27208fae3551SRodney W. Grimes } else { 27218fae3551SRodney W. Grimes mlpp = &mlp->ml_next; 27228fae3551SRodney W. Grimes mlp = mlp->ml_next; 27238fae3551SRodney W. Grimes } 27248fae3551SRodney W. Grimes } 27258fae3551SRodney W. Grimes if (fnd) { 27268fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 272774853402SPhilippe Charnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 27288fae3551SRodney W. Grimes return; 27298fae3551SRodney W. Grimes } 27308fae3551SRodney W. Grimes mlp = mlhead; 27318fae3551SRodney W. Grimes while (mlp) { 27328fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 27338fae3551SRodney W. Grimes mlp = mlp->ml_next; 27348fae3551SRodney W. Grimes } 27358fae3551SRodney W. Grimes fclose(mlfile); 27368fae3551SRodney W. Grimes } 27378fae3551SRodney W. Grimes } 27388fae3551SRodney W. Grimes 27398fae3551SRodney W. Grimes void 2740a7a7d96cSPhilippe Charnier add_mlist(char *hostp, char *dirp) 27418fae3551SRodney W. Grimes { 27428fae3551SRodney W. Grimes struct mountlist *mlp, **mlpp; 27438fae3551SRodney W. Grimes FILE *mlfile; 27448fae3551SRodney W. Grimes 27458fae3551SRodney W. Grimes mlpp = &mlhead; 27468fae3551SRodney W. Grimes mlp = mlhead; 27478fae3551SRodney W. Grimes while (mlp) { 27488fae3551SRodney W. Grimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 27498fae3551SRodney W. Grimes return; 27508fae3551SRodney W. Grimes mlpp = &mlp->ml_next; 27518fae3551SRodney W. Grimes mlp = mlp->ml_next; 27528fae3551SRodney W. Grimes } 27538fae3551SRodney W. Grimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 275474853402SPhilippe Charnier if (mlp == (struct mountlist *)NULL) 275574853402SPhilippe Charnier out_of_mem(); 27560775314bSDoug Rabson strncpy(mlp->ml_host, hostp, MNTNAMLEN); 27570775314bSDoug Rabson mlp->ml_host[MNTNAMLEN] = '\0'; 27580775314bSDoug Rabson strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 27590775314bSDoug Rabson mlp->ml_dirp[MNTPATHLEN] = '\0'; 27608fae3551SRodney W. Grimes mlp->ml_next = (struct mountlist *)NULL; 27618fae3551SRodney W. Grimes *mlpp = mlp; 27628fae3551SRodney W. Grimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 276374853402SPhilippe Charnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 27648fae3551SRodney W. Grimes return; 27658fae3551SRodney W. Grimes } 27668fae3551SRodney W. Grimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 27678fae3551SRodney W. Grimes fclose(mlfile); 27688fae3551SRodney W. Grimes } 27698fae3551SRodney W. Grimes 27708fae3551SRodney W. Grimes /* 27718fae3551SRodney W. Grimes * Free up a group list. 27728fae3551SRodney W. Grimes */ 27738fae3551SRodney W. Grimes void 2774a7a7d96cSPhilippe Charnier free_grp(struct grouplist *grp) 27758fae3551SRodney W. Grimes { 27768fae3551SRodney W. Grimes if (grp->gr_type == GT_HOST) { 27778360efbdSAlfred Perlstein if (grp->gr_ptr.gt_addrinfo != NULL) 27788360efbdSAlfred Perlstein freeaddrinfo(grp->gr_ptr.gt_addrinfo); 27798fae3551SRodney W. Grimes } else if (grp->gr_type == GT_NET) { 27808fae3551SRodney W. Grimes if (grp->gr_ptr.gt_net.nt_name) 27818fae3551SRodney W. Grimes free(grp->gr_ptr.gt_net.nt_name); 27828fae3551SRodney W. Grimes } 27838fae3551SRodney W. Grimes free((caddr_t)grp); 27848fae3551SRodney W. Grimes } 27858fae3551SRodney W. Grimes 27868fae3551SRodney W. Grimes #ifdef DEBUG 27878fae3551SRodney W. Grimes void 27888fae3551SRodney W. Grimes SYSLOG(int pri, const char *fmt, ...) 27898fae3551SRodney W. Grimes { 27908fae3551SRodney W. Grimes va_list ap; 27918fae3551SRodney W. Grimes 27928fae3551SRodney W. Grimes va_start(ap, fmt); 27938fae3551SRodney W. Grimes vfprintf(stderr, fmt, ap); 27948fae3551SRodney W. Grimes va_end(ap); 27958fae3551SRodney W. Grimes } 27968fae3551SRodney W. Grimes #endif /* DEBUG */ 27978fae3551SRodney W. Grimes 27988fae3551SRodney W. Grimes /* 27998fae3551SRodney W. Grimes * Check options for consistency. 28008fae3551SRodney W. Grimes */ 28018fae3551SRodney W. Grimes int 2802a7a7d96cSPhilippe Charnier check_options(struct dirlist *dp) 28038fae3551SRodney W. Grimes { 28048fae3551SRodney W. Grimes 2805bcc1d071SRick Macklem if (v4root_phase == 0 && dp == NULL) 28068fae3551SRodney W. Grimes return (1); 280791196234SPeter Wemm if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 280891196234SPeter Wemm syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 28098fae3551SRodney W. Grimes return (1); 28108fae3551SRodney W. Grimes } 28118fae3551SRodney W. Grimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 281260caaee2SIan Dowse syslog(LOG_ERR, "-mask requires -network"); 281360caaee2SIan Dowse return (1); 281460caaee2SIan Dowse } 281560caaee2SIan Dowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 281660caaee2SIan Dowse syslog(LOG_ERR, "-network requires mask specification"); 281760caaee2SIan Dowse return (1); 281860caaee2SIan Dowse } 281960caaee2SIan Dowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 282060caaee2SIan Dowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 28218fae3551SRodney W. Grimes return (1); 28228fae3551SRodney W. Grimes } 2823bcc1d071SRick Macklem if (v4root_phase > 0 && 2824bcc1d071SRick Macklem (opt_flags & 2825bcc1d071SRick Macklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 2826bcc1d071SRick Macklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 2827bcc1d071SRick Macklem return (1); 2828bcc1d071SRick Macklem } 282956cfc5edSRick Macklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 283056cfc5edSRick Macklem syslog(LOG_ERR, "-alldirs has multiple directories"); 283156cfc5edSRick Macklem return (1); 283256cfc5edSRick Macklem } 28338fae3551SRodney W. Grimes return (0); 28348fae3551SRodney W. Grimes } 28358fae3551SRodney W. Grimes 28368fae3551SRodney W. Grimes /* 28378fae3551SRodney W. Grimes * Check an absolute directory path for any symbolic links. Return true 28388fae3551SRodney W. Grimes */ 28398fae3551SRodney W. Grimes int 2840a7a7d96cSPhilippe Charnier check_dirpath(char *dirp) 28418fae3551SRodney W. Grimes { 28428fae3551SRodney W. Grimes char *cp; 28438fae3551SRodney W. Grimes int ret = 1; 28448fae3551SRodney W. Grimes struct stat sb; 28458fae3551SRodney W. Grimes 28468fae3551SRodney W. Grimes cp = dirp + 1; 28478fae3551SRodney W. Grimes while (*cp && ret) { 28488fae3551SRodney W. Grimes if (*cp == '/') { 28498fae3551SRodney W. Grimes *cp = '\0'; 2850a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 28518fae3551SRodney W. Grimes ret = 0; 28528fae3551SRodney W. Grimes *cp = '/'; 28538fae3551SRodney W. Grimes } 28548fae3551SRodney W. Grimes cp++; 28558fae3551SRodney W. Grimes } 2856a62dc406SDoug Rabson if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 28578fae3551SRodney W. Grimes ret = 0; 28588fae3551SRodney W. Grimes return (ret); 28598fae3551SRodney W. Grimes } 2860a62dc406SDoug Rabson 286160caaee2SIan Dowse /* 286260caaee2SIan Dowse * Make a netmask according to the specified prefix length. The ss_family 286360caaee2SIan Dowse * and other non-address fields must be initialised before calling this. 286460caaee2SIan Dowse */ 286560caaee2SIan Dowse int 286660caaee2SIan Dowse makemask(struct sockaddr_storage *ssp, int bitlen) 28678360efbdSAlfred Perlstein { 286860caaee2SIan Dowse u_char *p; 286960caaee2SIan Dowse int bits, i, len; 28708360efbdSAlfred Perlstein 287160caaee2SIan Dowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 287260caaee2SIan Dowse return (-1); 287389fdc4e1SMike Barcroft if (bitlen > len * CHAR_BIT) 287460caaee2SIan Dowse return (-1); 28758360efbdSAlfred Perlstein 287660caaee2SIan Dowse for (i = 0; i < len; i++) { 287789fdc4e1SMike Barcroft bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2878*58202d89SRuslan Ermilov *p++ = (u_char)~0 << (CHAR_BIT - bits); 287960caaee2SIan Dowse bitlen -= bits; 28808360efbdSAlfred Perlstein } 28818360efbdSAlfred Perlstein return 0; 28828360efbdSAlfred Perlstein } 28838360efbdSAlfred Perlstein 288460caaee2SIan Dowse /* 288560caaee2SIan Dowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 288660caaee2SIan Dowse * is acceptable (i.e. of the form 1...10....0). 288760caaee2SIan Dowse */ 288860caaee2SIan Dowse int 288960caaee2SIan Dowse checkmask(struct sockaddr *sa) 28908360efbdSAlfred Perlstein { 289160caaee2SIan Dowse u_char *mask; 289260caaee2SIan Dowse int i, len; 289360caaee2SIan Dowse 289460caaee2SIan Dowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 289560caaee2SIan Dowse return (-1); 289660caaee2SIan Dowse 289760caaee2SIan Dowse for (i = 0; i < len; i++) 289860caaee2SIan Dowse if (mask[i] != 0xff) 289960caaee2SIan Dowse break; 290060caaee2SIan Dowse if (i < len) { 290160caaee2SIan Dowse if (~mask[i] & (u_char)(~mask[i] + 1)) 290260caaee2SIan Dowse return (-1); 290360caaee2SIan Dowse i++; 290460caaee2SIan Dowse } 290560caaee2SIan Dowse for (; i < len; i++) 290660caaee2SIan Dowse if (mask[i] != 0) 290760caaee2SIan Dowse return (-1); 290860caaee2SIan Dowse return (0); 290960caaee2SIan Dowse } 291060caaee2SIan Dowse 291160caaee2SIan Dowse /* 291260caaee2SIan Dowse * Compare two sockaddrs according to a specified mask. Return zero if 291360caaee2SIan Dowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 291460caaee2SIan Dowse * If samask is NULL, perform a full comparision. 291560caaee2SIan Dowse */ 291660caaee2SIan Dowse int 291760caaee2SIan Dowse sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 291860caaee2SIan Dowse { 291960caaee2SIan Dowse unsigned char *p1, *p2, *mask; 292060caaee2SIan Dowse int len, i; 292160caaee2SIan Dowse 292260caaee2SIan Dowse if (sa1->sa_family != sa2->sa_family || 292360caaee2SIan Dowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 292460caaee2SIan Dowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 292560caaee2SIan Dowse return (1); 292660caaee2SIan Dowse 292760caaee2SIan Dowse switch (sa1->sa_family) { 292860caaee2SIan Dowse case AF_INET6: 292960caaee2SIan Dowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 293060caaee2SIan Dowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 293160caaee2SIan Dowse return (1); 293260caaee2SIan Dowse break; 293360caaee2SIan Dowse } 293460caaee2SIan Dowse 293560caaee2SIan Dowse /* Simple binary comparison if no mask specified. */ 293660caaee2SIan Dowse if (samask == NULL) 293760caaee2SIan Dowse return (memcmp(p1, p2, len)); 293860caaee2SIan Dowse 293960caaee2SIan Dowse /* Set up the mask, and do a mask-based comparison. */ 294060caaee2SIan Dowse if (sa1->sa_family != samask->sa_family || 294160caaee2SIan Dowse (mask = sa_rawaddr(samask, NULL)) == NULL) 294260caaee2SIan Dowse return (1); 294360caaee2SIan Dowse 294460caaee2SIan Dowse for (i = 0; i < len; i++) 294560caaee2SIan Dowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 294660caaee2SIan Dowse return (1); 294760caaee2SIan Dowse return (0); 294860caaee2SIan Dowse } 294960caaee2SIan Dowse 295060caaee2SIan Dowse /* 295160caaee2SIan Dowse * Return a pointer to the part of the sockaddr that contains the 295260caaee2SIan Dowse * raw address, and set *nbytes to its length in bytes. Returns 295360caaee2SIan Dowse * NULL if the address family is unknown. 295460caaee2SIan Dowse */ 295560caaee2SIan Dowse void * 295660caaee2SIan Dowse sa_rawaddr(struct sockaddr *sa, int *nbytes) { 295760caaee2SIan Dowse void *p; 295860caaee2SIan Dowse int len; 29598360efbdSAlfred Perlstein 29608360efbdSAlfred Perlstein switch (sa->sa_family) { 29618360efbdSAlfred Perlstein case AF_INET: 296260caaee2SIan Dowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 296360caaee2SIan Dowse p = &((struct sockaddr_in *)sa)->sin_addr; 29648360efbdSAlfred Perlstein break; 29658360efbdSAlfred Perlstein case AF_INET6: 296660caaee2SIan Dowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 296760caaee2SIan Dowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 29688360efbdSAlfred Perlstein break; 29698360efbdSAlfred Perlstein default: 297060caaee2SIan Dowse p = NULL; 297160caaee2SIan Dowse len = 0; 29728360efbdSAlfred Perlstein } 29738360efbdSAlfred Perlstein 297460caaee2SIan Dowse if (nbytes != NULL) 297560caaee2SIan Dowse *nbytes = len; 297660caaee2SIan Dowse return (p); 29778360efbdSAlfred Perlstein } 29788360efbdSAlfred Perlstein 297969d65572SIan Dowse void 2980a7a7d96cSPhilippe Charnier huphandler(int sig __unused) 298169d65572SIan Dowse { 298269d65572SIan Dowse got_sighup = 1; 298369d65572SIan Dowse } 298469d65572SIan Dowse 2985a7a7d96cSPhilippe Charnier void terminate(int sig __unused) 29868360efbdSAlfred Perlstein { 2987a032b226SPawel Jakub Dawidek pidfile_remove(pfh); 29880775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 29890775314bSDoug Rabson rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 29908360efbdSAlfred Perlstein exit (0); 29918360efbdSAlfred Perlstein } 2992bcc1d071SRick Macklem 2993