mountd.c revision 349756
1331722Seadler/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 331558Srgrimes#ifndef lint 3437663Scharnierstatic const char copyright[] = 351558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 361558Srgrimes The Regents of the University of California. All rights reserved.\n"; 372999Swollman#endif /*not lint*/ 381558Srgrimes 39105267Scharnier#if 0 401558Srgrimes#ifndef lint 4137663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42105267Scharnier#endif /*not lint*/ 4337663Scharnier#endif 441558Srgrimes 45105267Scharnier#include <sys/cdefs.h> 46105267Scharnier__FBSDID("$FreeBSD: stable/11/usr.sbin/mountd/mountd.c 349756 2019-07-05 01:04:58Z rmacklem $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 49192934Srmacklem#include <sys/fcntl.h> 50349756Srmacklem#include <sys/fnv_hash.h> 51192934Srmacklem#include <sys/linker.h> 52192934Srmacklem#include <sys/module.h> 531558Srgrimes#include <sys/mount.h> 54324955Smanu#include <sys/queue.h> 551558Srgrimes#include <sys/stat.h> 56192934Srmacklem#include <sys/sysctl.h> 571558Srgrimes#include <sys/syslog.h> 581558Srgrimes 591558Srgrimes#include <rpc/rpc.h> 60109363Smbr#include <rpc/rpc_com.h> 611558Srgrimes#include <rpc/pmap_clnt.h> 6274462Salfred#include <rpc/pmap_prot.h> 6374462Salfred#include <rpcsvc/mount.h> 649336Sdfr#include <nfs/nfsproto.h> 65192934Srmacklem#include <nfs/nfssvc.h> 6683653Speter#include <nfsserver/nfs.h> 671558Srgrimes 68192934Srmacklem#include <fs/nfs/nfsport.h> 69192934Srmacklem 701558Srgrimes#include <arpa/inet.h> 711558Srgrimes 721558Srgrimes#include <ctype.h> 7337663Scharnier#include <err.h> 741558Srgrimes#include <errno.h> 751558Srgrimes#include <grp.h> 76149433Spjd#include <libutil.h> 77103949Smike#include <limits.h> 781558Srgrimes#include <netdb.h> 791558Srgrimes#include <pwd.h> 801558Srgrimes#include <signal.h> 811558Srgrimes#include <stdio.h> 821558Srgrimes#include <stdlib.h> 831558Srgrimes#include <string.h> 841558Srgrimes#include <unistd.h> 851558Srgrimes#include "pathnames.h" 86158857Srodrigc#include "mntopts.h" 871558Srgrimes 881558Srgrimes#ifdef DEBUG 891558Srgrimes#include <stdarg.h> 901558Srgrimes#endif 911558Srgrimes 921558Srgrimes/* 931558Srgrimes * Structures for keeping the mount list and export list 941558Srgrimes */ 951558Srgrimesstruct mountlist { 96194880Sdfr char ml_host[MNTNAMLEN+1]; 97194880Sdfr char ml_dirp[MNTPATHLEN+1]; 98324955Smanu 99324955Smanu SLIST_ENTRY(mountlist) next; 1001558Srgrimes}; 1011558Srgrimes 1021558Srgrimesstruct dirlist { 1031558Srgrimes struct dirlist *dp_left; 1041558Srgrimes struct dirlist *dp_right; 1051558Srgrimes int dp_flag; 1061558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 107324234Smanu char *dp_dirp; 1081558Srgrimes}; 1091558Srgrimes/* dp_flag bits */ 1101558Srgrimes#define DP_DEFSET 0x1 1119336Sdfr#define DP_HOSTSET 0x2 1121558Srgrimes 1131558Srgrimesstruct exportlist { 1141558Srgrimes struct dirlist *ex_dirl; 1151558Srgrimes struct dirlist *ex_defdir; 116349128Srmacklem struct grouplist *ex_grphead; 1171558Srgrimes int ex_flag; 1181558Srgrimes fsid_t ex_fs; 1191558Srgrimes char *ex_fsdir; 12027447Sdfr char *ex_indexfile; 121184588Sdfr int ex_numsecflavors; 122184588Sdfr int ex_secflavors[MAXSECFLAVORS]; 123240902Srmacklem int ex_defnumsecflavors; 124240902Srmacklem int ex_defsecflavors[MAXSECFLAVORS]; 125324955Smanu 126324955Smanu SLIST_ENTRY(exportlist) entries; 1271558Srgrimes}; 1281558Srgrimes/* ex_flag bits */ 1291558Srgrimes#define EX_LINKED 0x1 1301558Srgrimes 131349124SrmacklemSLIST_HEAD(exportlisthead, exportlist); 132349124Srmacklem 1331558Srgrimesstruct netmsk { 13474462Salfred struct sockaddr_storage nt_net; 13575801Siedowse struct sockaddr_storage nt_mask; 13642144Sdfr char *nt_name; 1371558Srgrimes}; 1381558Srgrimes 1391558Srgrimesunion grouptypes { 14074462Salfred struct addrinfo *gt_addrinfo; 1411558Srgrimes struct netmsk gt_net; 1421558Srgrimes}; 1431558Srgrimes 1441558Srgrimesstruct grouplist { 1451558Srgrimes int gr_type; 1461558Srgrimes union grouptypes gr_ptr; 1471558Srgrimes struct grouplist *gr_next; 148240902Srmacklem int gr_numsecflavors; 149240902Srmacklem int gr_secflavors[MAXSECFLAVORS]; 1501558Srgrimes}; 1511558Srgrimes/* Group types */ 1521558Srgrimes#define GT_NULL 0x0 1531558Srgrimes#define GT_HOST 0x1 1541558Srgrimes#define GT_NET 0x2 15575641Siedowse#define GT_DEFAULT 0x3 1567401Swpaul#define GT_IGNORE 0x5 1571558Srgrimes 1581558Srgrimesstruct hostlist { 1599336Sdfr int ht_flag; /* Uses DP_xx bits */ 1601558Srgrimes struct grouplist *ht_grp; 1611558Srgrimes struct hostlist *ht_next; 1621558Srgrimes}; 1631558Srgrimes 1649336Sdfrstruct fhreturn { 1659336Sdfr int fhr_flag; 1669336Sdfr int fhr_vers; 1679336Sdfr nfsfh_t fhr_fh; 168184588Sdfr int fhr_numsecflavors; 169184588Sdfr int *fhr_secflavors; 1709336Sdfr}; 1719336Sdfr 172222623Srmacklem#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 173222623Srmacklem 1741558Srgrimes/* Global defs */ 175285128Straszstatic char *add_expdir(struct dirlist **, char *, int); 176285128Straszstatic void add_dlist(struct dirlist **, struct dirlist *, 177285128Strasz struct grouplist *, int, struct exportlist *); 178285128Straszstatic void add_mlist(char *, char *); 179285128Straszstatic int check_dirpath(char *); 180285128Straszstatic int check_options(struct dirlist *); 181285128Straszstatic int checkmask(struct sockaddr *sa); 182285128Straszstatic int chk_host(struct dirlist *, struct sockaddr *, int *, int *, 183285128Strasz int *, int **); 184293305Sjpaetzelstatic char *strsep_quote(char **stringp, const char *delim); 185222623Srmacklemstatic int create_service(struct netconfig *nconf); 186222623Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 187222623Srmacklemstatic void clearout_service(void); 188285128Straszstatic void del_mlist(char *hostp, char *dirp); 189285128Straszstatic struct dirlist *dirp_search(struct dirlist *, char *); 190285128Straszstatic int do_mount(struct exportlist *, struct grouplist *, int, 191285128Strasz struct xucred *, char *, int, struct statfs *); 192285128Straszstatic int do_opt(char **, char **, struct exportlist *, 193285128Strasz struct grouplist *, int *, int *, struct xucred *); 194349124Srmacklemstatic struct exportlist *ex_search(fsid_t *, struct exportlisthead *); 195285128Straszstatic struct exportlist *get_exp(void); 196285128Straszstatic void free_dir(struct dirlist *); 197285128Straszstatic void free_exp(struct exportlist *); 198285128Straszstatic void free_grp(struct grouplist *); 199285128Straszstatic void free_host(struct hostlist *); 200285128Straszstatic void get_exportlist(void); 201349124Srmacklemstatic void insert_exports(struct exportlist *, struct exportlisthead *); 202349124Srmacklemstatic void free_exports(struct exportlisthead *); 203349126Srmacklemstatic void read_exportfile(void); 204349126Srmacklemstatic void delete_export(struct iovec *, int, struct statfs *, char *); 205285128Straszstatic int get_host(char *, struct grouplist *, struct grouplist *); 206285128Straszstatic struct hostlist *get_ht(void); 207285128Straszstatic int get_line(void); 208285128Straszstatic void get_mountlist(void); 209285128Straszstatic int get_net(char *, struct netmsk *, int); 210329392Sbrdstatic void getexp_err(struct exportlist *, struct grouplist *, const char *); 211285128Straszstatic struct grouplist *get_grp(void); 212285128Straszstatic void hang_dirp(struct dirlist *, struct grouplist *, 21392882Simp struct exportlist *, int); 214285128Straszstatic void huphandler(int sig); 215285128Straszstatic int makemask(struct sockaddr_storage *ssp, int bitlen); 216285128Straszstatic void mntsrv(struct svc_req *, SVCXPRT *); 217285128Straszstatic void nextfield(char **, char **); 218285128Straszstatic void out_of_mem(void); 219285128Straszstatic void parsecred(char *, struct xucred *); 220285128Straszstatic int parsesec(char *, struct exportlist *); 221285128Straszstatic int put_exlist(struct dirlist *, XDR *, struct dirlist *, 222285128Strasz int *, int); 223285128Straszstatic void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 224285128Straszstatic int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 225285128Strasz struct sockaddr *samask); 226285128Straszstatic int scan_tree(struct dirlist *, struct sockaddr *); 227285128Straszstatic void usage(void); 228285128Straszstatic int xdr_dir(XDR *, char *); 229285128Straszstatic int xdr_explist(XDR *, caddr_t); 230285128Straszstatic int xdr_explist_brief(XDR *, caddr_t); 231285128Straszstatic int xdr_explist_common(XDR *, caddr_t, int); 232285128Straszstatic int xdr_fhs(XDR *, caddr_t); 233285128Straszstatic int xdr_mlist(XDR *, caddr_t); 234285128Straszstatic void terminate(int); 2351558Srgrimes 236349756Srmacklem#define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) 237349756Srmacklemstatic struct exportlisthead *exphead = NULL; 238349756Srmacklemstatic int exphashsize = 0; 239349124Srmacklemstatic SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); 240285128Straszstatic char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 241285128Straszstatic char **exnames; 242285128Straszstatic char **hosts = NULL; 243285128Straszstatic struct xucred def_anon = { 24491354Sdd XUCRED_VERSION, 24572650Sgreen (uid_t)-2, 2461558Srgrimes 1, 24772650Sgreen { (gid_t)-2 }, 24872650Sgreen NULL 2491558Srgrimes}; 250285128Straszstatic int force_v2 = 0; 251285128Straszstatic int resvport_only = 1; 252285128Straszstatic int nhosts = 0; 253285128Straszstatic int dir_only = 1; 254285128Straszstatic int dolog = 0; 255285128Straszstatic int got_sighup = 0; 256285128Straszstatic int xcreated = 0; 25774462Salfred 258285128Straszstatic char *svcport_str = NULL; 259285128Straszstatic int mallocd_svcport = 0; 260285128Straszstatic int *sock_fd; 261285128Straszstatic int sock_fdcnt; 262285128Straszstatic int sock_fdpos; 263285128Straszstatic int suspend_nfsd = 0; 264172827Smatteo 265285128Straszstatic int opt_flags; 26674462Salfredstatic int have_v6 = 1; 26774462Salfred 268285128Straszstatic int v4root_phase = 0; 269285128Straszstatic char v4root_dirpath[PATH_MAX + 1]; 270285128Straszstatic int has_publicfh = 0; 271192934Srmacklem 272285128Straszstatic struct pidfh *pfh = NULL; 27375801Siedowse/* Bits for opt_flags above */ 2741558Srgrimes#define OP_MAPROOT 0x01 2751558Srgrimes#define OP_MAPALL 0x02 27683653Speter/* 0x4 free */ 2771558Srgrimes#define OP_MASK 0x08 2781558Srgrimes#define OP_NET 0x10 2791558Srgrimes#define OP_ALLDIRS 0x40 28075801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 281100336Sjoerg#define OP_QUIET 0x100 28274462Salfred#define OP_MASKLEN 0x200 283184588Sdfr#define OP_SEC 0x400 2841558Srgrimes 2851558Srgrimes#ifdef DEBUG 286285128Straszstatic int debug = 1; 287285128Straszstatic void SYSLOG(int, const char *, ...) __printflike(2, 3); 2881558Srgrimes#define syslog SYSLOG 2891558Srgrimes#else 290285128Straszstatic int debug = 0; 2911558Srgrimes#endif 2921558Srgrimes 2931558Srgrimes/* 294293305Sjpaetzel * Similar to strsep(), but it allows for quoted strings 295293305Sjpaetzel * and escaped characters. 296293305Sjpaetzel * 297293305Sjpaetzel * It returns the string (or NULL, if *stringp is NULL), 298293305Sjpaetzel * which is a de-quoted version of the string if necessary. 299293305Sjpaetzel * 300293305Sjpaetzel * It modifies *stringp in place. 301293305Sjpaetzel */ 302293305Sjpaetzelstatic char * 303293305Sjpaetzelstrsep_quote(char **stringp, const char *delim) 304293305Sjpaetzel{ 305293305Sjpaetzel char *srcptr, *dstptr, *retval; 306293305Sjpaetzel char quot = 0; 307293305Sjpaetzel 308293305Sjpaetzel if (stringp == NULL || *stringp == NULL) 309293305Sjpaetzel return (NULL); 310293305Sjpaetzel 311293305Sjpaetzel srcptr = dstptr = retval = *stringp; 312293305Sjpaetzel 313293305Sjpaetzel while (*srcptr) { 314293305Sjpaetzel /* 315293305Sjpaetzel * We're looking for several edge cases here. 316293305Sjpaetzel * First: if we're in quote state (quot != 0), 317293305Sjpaetzel * then we ignore the delim characters, but otherwise 318293305Sjpaetzel * process as normal, unless it is the quote character. 319293305Sjpaetzel * Second: if the current character is a backslash, 320293305Sjpaetzel * we take the next character as-is, without checking 321293305Sjpaetzel * for delim, quote, or backslash. Exception: if the 322293305Sjpaetzel * next character is a NUL, that's the end of the string. 323293305Sjpaetzel * Third: if the character is a quote character, we toggle 324293305Sjpaetzel * quote state. 325293305Sjpaetzel * Otherwise: check the current character for NUL, or 326293305Sjpaetzel * being in delim, and end the string if either is true. 327293305Sjpaetzel */ 328293305Sjpaetzel if (*srcptr == '\\') { 329293305Sjpaetzel srcptr++; 330293305Sjpaetzel /* 331293305Sjpaetzel * The edge case here is if the next character 332293305Sjpaetzel * is NUL, we want to stop processing. But if 333293305Sjpaetzel * it's not NUL, then we simply want to copy it. 334293305Sjpaetzel */ 335293305Sjpaetzel if (*srcptr) { 336293305Sjpaetzel *dstptr++ = *srcptr++; 337293305Sjpaetzel } 338293305Sjpaetzel continue; 339293305Sjpaetzel } 340293305Sjpaetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 341293305Sjpaetzel quot = *srcptr++; 342293305Sjpaetzel continue; 343293305Sjpaetzel } 344293305Sjpaetzel if (quot && *srcptr == quot) { 345293305Sjpaetzel /* End of the quoted part */ 346293305Sjpaetzel quot = 0; 347293305Sjpaetzel srcptr++; 348293305Sjpaetzel continue; 349293305Sjpaetzel } 350293305Sjpaetzel if (!quot && strchr(delim, *srcptr)) 351293305Sjpaetzel break; 352293305Sjpaetzel *dstptr++ = *srcptr++; 353293305Sjpaetzel } 354293305Sjpaetzel 355349457Smav *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 356293305Sjpaetzel *dstptr = 0; /* Terminate the string */ 357293305Sjpaetzel return (retval); 358293305Sjpaetzel} 359293305Sjpaetzel 360293305Sjpaetzel/* 3611558Srgrimes * Mountd server for NFS mount protocol as described in: 3621558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 3631558Srgrimes * The optional arguments are the exports file name 3641558Srgrimes * default: _PATH_EXPORTS 3651558Srgrimes * and "-n" to allow nonroot mount. 3661558Srgrimes */ 3671558Srgrimesint 368216587Scharniermain(int argc, char **argv) 3691558Srgrimes{ 37075754Siedowse fd_set readfds; 371172827Smatteo struct netconfig *nconf; 372172827Smatteo char *endptr, **hosts_bak; 373172827Smatteo void *nc_handle; 374149433Spjd pid_t otherpid; 375172827Smatteo in_port_t svcport; 376172827Smatteo int c, k, s; 377109363Smbr int maxrec = RPC_MAXDATASIZE; 378222623Srmacklem int attempt_cnt, port_len, port_pos, ret; 379222623Srmacklem char **port_list; 3801558Srgrimes 38174462Salfred /* Check that another mountd isn't already running. */ 382150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 383149433Spjd if (pfh == NULL) { 384149433Spjd if (errno == EEXIST) 385149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 386149433Spjd warn("cannot open or create pidfile"); 387149433Spjd } 38874462Salfred 38974462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 39074462Salfred if (s < 0) 39174462Salfred have_v6 = 0; 39274462Salfred else 39374462Salfred close(s); 3942999Swollman 395282214Strasz while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) 3961558Srgrimes switch (c) { 39725087Sdfr case '2': 39825087Sdfr force_v2 = 1; 39925087Sdfr break; 400192993Srmacklem case 'e': 401220980Srmacklem /* now a no-op, since this is the default */ 402192934Srmacklem break; 4039336Sdfr case 'n': 4049336Sdfr resvport_only = 0; 4059336Sdfr break; 4069336Sdfr case 'r': 4079336Sdfr dir_only = 0; 4089336Sdfr break; 4098688Sphk case 'd': 4108688Sphk debug = debug ? 0 : 1; 4118688Sphk break; 41231656Sguido case 'l': 413121767Speter dolog = 1; 41431656Sguido break; 415126572Sbms case 'p': 416126572Sbms endptr = NULL; 417126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 418126572Sbms if (endptr == NULL || *endptr != '\0' || 419126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 420126572Sbms usage(); 421172827Smatteo svcport_str = strdup(optarg); 422126572Sbms break; 423172827Smatteo case 'h': 424172827Smatteo ++nhosts; 425172827Smatteo hosts_bak = hosts; 426172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 427172827Smatteo if (hosts_bak == NULL) { 428172827Smatteo if (hosts != NULL) { 429172827Smatteo for (k = 0; k < nhosts; k++) 430172827Smatteo free(hosts[k]); 431172827Smatteo free(hosts); 432172827Smatteo out_of_mem(); 433172827Smatteo } 434172827Smatteo } 435172827Smatteo hosts = hosts_bak; 436172827Smatteo hosts[nhosts - 1] = strdup(optarg); 437172827Smatteo if (hosts[nhosts - 1] == NULL) { 438172827Smatteo for (k = 0; k < (nhosts - 1); k++) 439172827Smatteo free(hosts[k]); 440172827Smatteo free(hosts); 441172827Smatteo out_of_mem(); 442172827Smatteo } 443172827Smatteo break; 444241568Srmacklem case 'S': 445241568Srmacklem suspend_nfsd = 1; 446241568Srmacklem break; 4471558Srgrimes default: 44837663Scharnier usage(); 449298089Spfg } 450192934Srmacklem 451282214Strasz if (modfind("nfsd") < 0) { 452192934Srmacklem /* Not present in kernel, try loading it */ 453282214Strasz if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 454192934Srmacklem errx(1, "NFS server is not available"); 455192934Srmacklem } 456192934Srmacklem 4571558Srgrimes argc -= optind; 4581558Srgrimes argv += optind; 459166440Spjd if (argc > 0) 460166440Spjd exnames = argv; 461166440Spjd else 462166440Spjd exnames = exnames_default; 4631558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 4641558Srgrimes if (debug) 46537663Scharnier warnx("getting export list"); 4661558Srgrimes get_exportlist(); 4671558Srgrimes if (debug) 46837663Scharnier warnx("getting mount list"); 4691558Srgrimes get_mountlist(); 4701558Srgrimes if (debug) 47137663Scharnier warnx("here we go"); 4721558Srgrimes if (debug == 0) { 4731558Srgrimes daemon(0, 0); 4741558Srgrimes signal(SIGINT, SIG_IGN); 4751558Srgrimes signal(SIGQUIT, SIG_IGN); 4761558Srgrimes } 47775754Siedowse signal(SIGHUP, huphandler); 47874462Salfred signal(SIGTERM, terminate); 479164394Srodrigc signal(SIGPIPE, SIG_IGN); 480149433Spjd 481149433Spjd pidfile_write(pfh); 482149433Spjd 483194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 484194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 485109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 486109363Smbr 48724759Sguido if (!resvport_only) { 488308449Srmacklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL, 48983687Speter &resvport_only, sizeof(resvport_only)) != 0 && 49083687Speter errno != ENOENT) { 49124759Sguido syslog(LOG_ERR, "sysctl: %m"); 49224759Sguido exit(1); 49324759Sguido } 49424330Sguido } 495126572Sbms 496172827Smatteo /* 497172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 498172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 499172827Smatteo * list. 500172827Smatteo */ 501172827Smatteo if (nhosts == 0) { 502292864Suqs hosts = malloc(sizeof(char *)); 503172827Smatteo if (hosts == NULL) 504172827Smatteo out_of_mem(); 505172827Smatteo hosts[0] = "*"; 506172827Smatteo nhosts = 1; 507172827Smatteo } else { 508172827Smatteo hosts_bak = hosts; 509172827Smatteo if (have_v6) { 510172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 511172827Smatteo sizeof(char *)); 512172827Smatteo if (hosts_bak == NULL) { 513172827Smatteo for (k = 0; k < nhosts; k++) 514172827Smatteo free(hosts[k]); 515172827Smatteo free(hosts); 516172827Smatteo out_of_mem(); 517172827Smatteo } else 518172827Smatteo hosts = hosts_bak; 519172827Smatteo nhosts += 2; 520172827Smatteo hosts[nhosts - 2] = "::1"; 521172827Smatteo } else { 522172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 523172827Smatteo if (hosts_bak == NULL) { 524172827Smatteo for (k = 0; k < nhosts; k++) 525172827Smatteo free(hosts[k]); 526172827Smatteo free(hosts); 527172827Smatteo out_of_mem(); 528172827Smatteo } else { 529172827Smatteo nhosts += 1; 530172827Smatteo hosts = hosts_bak; 531126572Sbms } 532172827Smatteo } 53374462Salfred 534172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 53574462Salfred } 53674462Salfred 537222623Srmacklem attempt_cnt = 1; 538222623Srmacklem sock_fdcnt = 0; 539222623Srmacklem sock_fd = NULL; 540222623Srmacklem port_list = NULL; 541222623Srmacklem port_len = 0; 542172827Smatteo nc_handle = setnetconfig(); 543172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 544172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 545172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 546172827Smatteo "inet6") == 0) { 547172827Smatteo /* DO NOTHING */ 548222623Srmacklem } else { 549222623Srmacklem ret = create_service(nconf); 550222623Srmacklem if (ret == 1) 551222623Srmacklem /* Ignore this call */ 552222623Srmacklem continue; 553222623Srmacklem if (ret < 0) { 554222623Srmacklem /* 555222623Srmacklem * Failed to bind port, so close off 556222623Srmacklem * all sockets created and try again 557222623Srmacklem * if the port# was dynamically 558222623Srmacklem * assigned via bind(2). 559222623Srmacklem */ 560222623Srmacklem clearout_service(); 561222623Srmacklem if (mallocd_svcport != 0 && 562222623Srmacklem attempt_cnt < GETPORT_MAXTRY) { 563222623Srmacklem free(svcport_str); 564222623Srmacklem svcport_str = NULL; 565222623Srmacklem mallocd_svcport = 0; 566222623Srmacklem } else { 567222623Srmacklem errno = EADDRINUSE; 568222623Srmacklem syslog(LOG_ERR, 569222623Srmacklem "bindresvport_sa: %m"); 570222623Srmacklem exit(1); 571222623Srmacklem } 572222623Srmacklem 573222623Srmacklem /* Start over at the first service. */ 574222623Srmacklem free(sock_fd); 575222623Srmacklem sock_fdcnt = 0; 576222623Srmacklem sock_fd = NULL; 577222623Srmacklem nc_handle = setnetconfig(); 578222623Srmacklem attempt_cnt++; 579222623Srmacklem } else if (mallocd_svcport != 0 && 580222623Srmacklem attempt_cnt == GETPORT_MAXTRY) { 581222623Srmacklem /* 582222623Srmacklem * For the last attempt, allow 583222623Srmacklem * different port #s for each nconf 584222623Srmacklem * by saving the svcport_str and 585222623Srmacklem * setting it back to NULL. 586222623Srmacklem */ 587222623Srmacklem port_list = realloc(port_list, 588222623Srmacklem (port_len + 1) * sizeof(char *)); 589222623Srmacklem if (port_list == NULL) 590222623Srmacklem out_of_mem(); 591222623Srmacklem port_list[port_len++] = svcport_str; 592222623Srmacklem svcport_str = NULL; 593222623Srmacklem mallocd_svcport = 0; 594222623Srmacklem } 595222623Srmacklem } 596222623Srmacklem } 597222623Srmacklem } 598222623Srmacklem 599222623Srmacklem /* 600222623Srmacklem * Successfully bound the ports, so call complete_service() to 601222623Srmacklem * do the rest of the setup on the service(s). 602222623Srmacklem */ 603222623Srmacklem sock_fdpos = 0; 604222623Srmacklem port_pos = 0; 605222623Srmacklem nc_handle = setnetconfig(); 606222623Srmacklem while ((nconf = getnetconfig(nc_handle))) { 607222623Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 608222623Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 609222623Srmacklem "inet6") == 0) { 610222623Srmacklem /* DO NOTHING */ 611222623Srmacklem } else if (port_list != NULL) { 612222623Srmacklem if (port_pos >= port_len) { 613222623Srmacklem syslog(LOG_ERR, "too many port#s"); 614222623Srmacklem exit(1); 615222623Srmacklem } 616222623Srmacklem complete_service(nconf, port_list[port_pos++]); 617172827Smatteo } else 618222623Srmacklem complete_service(nconf, svcport_str); 619172827Smatteo } 62074462Salfred } 621172827Smatteo endnetconfig(nc_handle); 622222623Srmacklem free(sock_fd); 623222623Srmacklem if (port_list != NULL) { 624222623Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 625222623Srmacklem free(port_list[port_pos]); 626222623Srmacklem free(port_list); 627222623Srmacklem } 62874462Salfred 62974462Salfred if (xcreated == 0) { 63074462Salfred syslog(LOG_ERR, "could not create any services"); 6311558Srgrimes exit(1); 6321558Srgrimes } 63375754Siedowse 63475754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 63575754Siedowse for (;;) { 63675754Siedowse if (got_sighup) { 63775754Siedowse get_exportlist(); 63875754Siedowse got_sighup = 0; 63975754Siedowse } 64075754Siedowse readfds = svc_fdset; 64175754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 64275754Siedowse case -1: 64375754Siedowse if (errno == EINTR) 64475754Siedowse continue; 64575754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 64675754Siedowse exit(1); 64775754Siedowse case 0: 64875754Siedowse continue; 64975754Siedowse default: 65075754Siedowse svc_getreqset(&readfds); 65175754Siedowse } 65275754Siedowse } 653172827Smatteo} 654172827Smatteo 655172827Smatteo/* 656172827Smatteo * This routine creates and binds sockets on the appropriate 657222623Srmacklem * addresses. It gets called one time for each transport. 658222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 659222623Srmacklem * bind failed with EADDRINUSE. 660222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and 661222623Srmacklem * the total count of them is maintained in sock_fdcnt. 662172827Smatteo */ 663222623Srmacklemstatic int 664172827Smatteocreate_service(struct netconfig *nconf) 665172827Smatteo{ 666172827Smatteo struct addrinfo hints, *res = NULL; 667172827Smatteo struct sockaddr_in *sin; 668172827Smatteo struct sockaddr_in6 *sin6; 669172827Smatteo struct __rpc_sockinfo si; 670172827Smatteo int aicode; 671172827Smatteo int fd; 672172827Smatteo int nhostsbak; 673172827Smatteo int one = 1; 674172827Smatteo int r; 675172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 676222623Srmacklem int mallocd_res; 677172827Smatteo 678172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 679172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 680172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 681222623Srmacklem return (1); /* not my type */ 682172827Smatteo 683172827Smatteo /* 684172827Smatteo * XXX - using RPC library internal functions. 685172827Smatteo */ 686172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 687172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 688172827Smatteo nconf->nc_netid); 689222623Srmacklem return (1); 690172827Smatteo } 691172827Smatteo 692172827Smatteo /* Get mountd's address on this transport */ 693172827Smatteo memset(&hints, 0, sizeof hints); 694172827Smatteo hints.ai_family = si.si_af; 695172827Smatteo hints.ai_socktype = si.si_socktype; 696172827Smatteo hints.ai_protocol = si.si_proto; 697172827Smatteo 698172827Smatteo /* 699172827Smatteo * Bind to specific IPs if asked to 700172827Smatteo */ 701172827Smatteo nhostsbak = nhosts; 702172827Smatteo while (nhostsbak > 0) { 703172827Smatteo --nhostsbak; 704222623Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 705222623Srmacklem if (sock_fd == NULL) 706222623Srmacklem out_of_mem(); 707222623Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 708222623Srmacklem mallocd_res = 0; 709222623Srmacklem 710277352Srstone hints.ai_flags = AI_PASSIVE; 711277352Srstone 712172827Smatteo /* 713172827Smatteo * XXX - using RPC library internal functions. 714172827Smatteo */ 715172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 716172827Smatteo int non_fatal = 0; 717244538Skevlo if (errno == EAFNOSUPPORT && 718172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 719172827Smatteo non_fatal = 1; 720172827Smatteo 721172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 722172827Smatteo "cannot create socket for %s", nconf->nc_netid); 723222623Srmacklem if (non_fatal != 0) 724222623Srmacklem continue; 725222623Srmacklem exit(1); 726172827Smatteo } 727172827Smatteo 728172827Smatteo switch (hints.ai_family) { 729172827Smatteo case AF_INET: 730172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 731172827Smatteo host_addr) == 1) { 732222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 733172827Smatteo } else { 734172827Smatteo /* 735172827Smatteo * Skip if we have an AF_INET6 address. 736172827Smatteo */ 737172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 738172827Smatteo host_addr) == 1) { 739172827Smatteo close(fd); 740172827Smatteo continue; 741172827Smatteo } 742172827Smatteo } 743172827Smatteo break; 744172827Smatteo case AF_INET6: 745172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 746172827Smatteo host_addr) == 1) { 747222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 748172827Smatteo } else { 749172827Smatteo /* 750172827Smatteo * Skip if we have an AF_INET address. 751172827Smatteo */ 752172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 753172827Smatteo host_addr) == 1) { 754172827Smatteo close(fd); 755172827Smatteo continue; 756172827Smatteo } 757172827Smatteo } 758172827Smatteo 759172827Smatteo /* 760172827Smatteo * We're doing host-based access checks here, so don't 761172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 762172827Smatteo * disable it by default on NFS sockets too. 763172827Smatteo */ 764172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 765172827Smatteo sizeof one) < 0) { 766172827Smatteo syslog(LOG_ERR, 767172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 768172827Smatteo exit(1); 769172827Smatteo } 770172827Smatteo break; 771172827Smatteo default: 772172827Smatteo break; 773172827Smatteo } 774172827Smatteo 775172827Smatteo /* 776172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 777172827Smatteo */ 778172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 779172827Smatteo if (svcport_str == NULL) { 780172827Smatteo res = malloc(sizeof(struct addrinfo)); 781172827Smatteo if (res == NULL) 782172827Smatteo out_of_mem(); 783222623Srmacklem mallocd_res = 1; 784172827Smatteo res->ai_flags = hints.ai_flags; 785172827Smatteo res->ai_family = hints.ai_family; 786172827Smatteo res->ai_protocol = hints.ai_protocol; 787172827Smatteo switch (res->ai_family) { 788172827Smatteo case AF_INET: 789172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 790172827Smatteo if (sin == NULL) 791172827Smatteo out_of_mem(); 792172827Smatteo sin->sin_family = AF_INET; 793172827Smatteo sin->sin_port = htons(0); 794172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 795172827Smatteo res->ai_addr = (struct sockaddr*) sin; 796172827Smatteo res->ai_addrlen = (socklen_t) 797222623Srmacklem sizeof(struct sockaddr_in); 798172827Smatteo break; 799172827Smatteo case AF_INET6: 800172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 801173056Ssimon if (sin6 == NULL) 802172827Smatteo out_of_mem(); 803172827Smatteo sin6->sin6_family = AF_INET6; 804172827Smatteo sin6->sin6_port = htons(0); 805172827Smatteo sin6->sin6_addr = in6addr_any; 806172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 807172827Smatteo res->ai_addrlen = (socklen_t) 808222623Srmacklem sizeof(struct sockaddr_in6); 809222623Srmacklem break; 810172827Smatteo default: 811222623Srmacklem syslog(LOG_ERR, "bad addr fam %d", 812222623Srmacklem res->ai_family); 813222623Srmacklem exit(1); 814172827Smatteo } 815172827Smatteo } else { 816172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 817172827Smatteo &hints, &res)) != 0) { 818172827Smatteo syslog(LOG_ERR, 819172827Smatteo "cannot get local address for %s: %s", 820172827Smatteo nconf->nc_netid, 821172827Smatteo gai_strerror(aicode)); 822222623Srmacklem close(fd); 823172827Smatteo continue; 824172827Smatteo } 825172827Smatteo } 826172827Smatteo } else { 827172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 828172827Smatteo &hints, &res)) != 0) { 829172827Smatteo syslog(LOG_ERR, 830172827Smatteo "cannot get local address for %s: %s", 831172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 832222623Srmacklem close(fd); 833172827Smatteo continue; 834172827Smatteo } 835172827Smatteo } 836172827Smatteo 837222623Srmacklem /* Store the fd. */ 838222623Srmacklem sock_fd[sock_fdcnt - 1] = fd; 839222623Srmacklem 840222623Srmacklem /* Now, attempt the bind. */ 841172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 842172827Smatteo if (r != 0) { 843222623Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 844222623Srmacklem if (mallocd_res != 0) { 845222623Srmacklem free(res->ai_addr); 846222623Srmacklem free(res); 847222623Srmacklem } else 848222623Srmacklem freeaddrinfo(res); 849222623Srmacklem return (-1); 850222623Srmacklem } 851172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 852172827Smatteo exit(1); 853172827Smatteo } 854172827Smatteo 855222623Srmacklem if (svcport_str == NULL) { 856222623Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 857222623Srmacklem if (svcport_str == NULL) 858222623Srmacklem out_of_mem(); 859222623Srmacklem mallocd_svcport = 1; 860222623Srmacklem 861222623Srmacklem if (getnameinfo(res->ai_addr, 862222623Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 863222623Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 864222623Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 865222623Srmacklem errx(1, "Cannot get port number"); 866222623Srmacklem } 867222623Srmacklem if (mallocd_res != 0) { 868222623Srmacklem free(res->ai_addr); 869222623Srmacklem free(res); 870222623Srmacklem } else 871222623Srmacklem freeaddrinfo(res); 872222623Srmacklem res = NULL; 873222623Srmacklem } 874222623Srmacklem return (0); 875222623Srmacklem} 876222623Srmacklem 877222623Srmacklem/* 878222623Srmacklem * Called after all the create_service() calls have succeeded, to complete 879222623Srmacklem * the setup and registration. 880222623Srmacklem */ 881222623Srmacklemstatic void 882222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 883222623Srmacklem{ 884222623Srmacklem struct addrinfo hints, *res = NULL; 885222623Srmacklem struct __rpc_sockinfo si; 886222623Srmacklem struct netbuf servaddr; 887222623Srmacklem SVCXPRT *transp = NULL; 888222623Srmacklem int aicode, fd, nhostsbak; 889222623Srmacklem int registered = 0; 890222623Srmacklem 891222623Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 892222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 893222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 894222623Srmacklem return; /* not my type */ 895222623Srmacklem 896222623Srmacklem /* 897222623Srmacklem * XXX - using RPC library internal functions. 898222623Srmacklem */ 899222623Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 900222623Srmacklem syslog(LOG_ERR, "cannot get information for %s", 901222623Srmacklem nconf->nc_netid); 902222623Srmacklem return; 903222623Srmacklem } 904222623Srmacklem 905222623Srmacklem nhostsbak = nhosts; 906222623Srmacklem while (nhostsbak > 0) { 907222623Srmacklem --nhostsbak; 908222623Srmacklem if (sock_fdpos >= sock_fdcnt) { 909222623Srmacklem /* Should never happen. */ 910222623Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 911222623Srmacklem return; 912222623Srmacklem } 913222623Srmacklem fd = sock_fd[sock_fdpos++]; 914222623Srmacklem if (fd < 0) 915222623Srmacklem continue; 916222623Srmacklem 917341171Ssef /* 918341171Ssef * Using -1 tells listen(2) to use 919341171Ssef * kern.ipc.soacceptqueue for the backlog. 920341171Ssef */ 921172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 922341171Ssef listen(fd, -1); 923172827Smatteo 924172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 925172827Smatteo transp = svc_dg_create(fd, 0, 0); 926172827Smatteo else 927172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 928172827Smatteo RPC_MAXDATASIZE); 929172827Smatteo 930172827Smatteo if (transp != (SVCXPRT *) NULL) { 931194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 932172827Smatteo NULL)) 933172827Smatteo syslog(LOG_ERR, 934194880Sdfr "can't register %s MOUNTVERS service", 935172827Smatteo nconf->nc_netid); 936172827Smatteo if (!force_v2) { 937194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 938172827Smatteo mntsrv, NULL)) 939172827Smatteo syslog(LOG_ERR, 940194880Sdfr "can't register %s MOUNTVERS3 service", 941172827Smatteo nconf->nc_netid); 942172827Smatteo } 943172827Smatteo } else 944172827Smatteo syslog(LOG_WARNING, "can't create %s services", 945172827Smatteo nconf->nc_netid); 946172827Smatteo 947172827Smatteo if (registered == 0) { 948172827Smatteo registered = 1; 949172827Smatteo memset(&hints, 0, sizeof hints); 950172827Smatteo hints.ai_flags = AI_PASSIVE; 951172827Smatteo hints.ai_family = si.si_af; 952172827Smatteo hints.ai_socktype = si.si_socktype; 953172827Smatteo hints.ai_protocol = si.si_proto; 954172827Smatteo 955222623Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 956172827Smatteo &res)) != 0) { 957172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 958172827Smatteo gai_strerror(aicode)); 959172827Smatteo exit(1); 960172827Smatteo } 961172827Smatteo 962172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 963172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 964172827Smatteo servaddr.len = res->ai_addrlen; 965172827Smatteo 966194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 967194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 968172827Smatteo 969172827Smatteo xcreated++; 970172827Smatteo freeaddrinfo(res); 971172827Smatteo } 972172827Smatteo } /* end while */ 9731558Srgrimes} 9741558Srgrimes 975222623Srmacklem/* 976222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the 977222623Srmacklem * cycle of socket creation/binding can start anew. 978222623Srmacklem */ 97937663Scharnierstatic void 980222623Srmacklemclearout_service(void) 981222623Srmacklem{ 982222623Srmacklem int i; 983222623Srmacklem 984222623Srmacklem for (i = 0; i < sock_fdcnt; i++) { 985222623Srmacklem if (sock_fd[i] >= 0) { 986222623Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 987222623Srmacklem close(sock_fd[i]); 988222623Srmacklem } 989222623Srmacklem } 990222623Srmacklem} 991222623Srmacklem 992222623Srmacklemstatic void 993216587Scharnierusage(void) 99437663Scharnier{ 99537663Scharnier fprintf(stderr, 996192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 997241568Srmacklem "[-S] [-h <bindip>] [export_file ...]\n"); 99837663Scharnier exit(1); 99937663Scharnier} 100037663Scharnier 10011558Srgrimes/* 10021558Srgrimes * The mount rpc service 10031558Srgrimes */ 10041558Srgrimesvoid 1005216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp) 10061558Srgrimes{ 10071558Srgrimes struct exportlist *ep; 10081558Srgrimes struct dirlist *dp; 10099336Sdfr struct fhreturn fhr; 10101558Srgrimes struct stat stb; 10111558Srgrimes struct statfs fsb; 101274462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 101374462Salfred int lookup_failed = 1; 101474462Salfred struct sockaddr *saddr; 10159336Sdfr u_short sport; 1016194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 101728911Sguido int bad = 0, defset, hostset; 10189336Sdfr sigset_t sighup_mask; 1019240902Srmacklem int numsecflavors, *secflavorsp; 10201558Srgrimes 10219336Sdfr sigemptyset(&sighup_mask); 10229336Sdfr sigaddset(&sighup_mask, SIGHUP); 102374462Salfred saddr = svc_getrpccaller(transp)->buf; 102474462Salfred switch (saddr->sa_family) { 102574462Salfred case AF_INET6: 102675635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 102774462Salfred break; 102874462Salfred case AF_INET: 102975635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 103074462Salfred break; 103174462Salfred default: 103274462Salfred syslog(LOG_ERR, "request from unknown address family"); 103374462Salfred return; 103474462Salfred } 1035346769Smav switch (rqstp->rq_proc) { 1036346769Smav case MOUNTPROC_MNT: 1037346769Smav case MOUNTPROC_UMNT: 1038346769Smav case MOUNTPROC_UMNTALL: 1039346769Smav lookup_failed = getnameinfo(saddr, saddr->sa_len, host, 1040346769Smav sizeof host, NULL, 0, 0); 1041346769Smav } 104274462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 104374462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 10441558Srgrimes switch (rqstp->rq_proc) { 10451558Srgrimes case NULLPROC: 1046121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 104737663Scharnier syslog(LOG_ERR, "can't send reply"); 10481558Srgrimes return; 1049194880Sdfr case MOUNTPROC_MNT: 10509336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 105131656Sguido syslog(LOG_NOTICE, 105231656Sguido "mount request from %s from unprivileged port", 105374462Salfred numerichost); 10541558Srgrimes svcerr_weakauth(transp); 10551558Srgrimes return; 10561558Srgrimes } 1057121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 105831656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 105974462Salfred numerichost); 10601558Srgrimes svcerr_decode(transp); 10611558Srgrimes return; 10621558Srgrimes } 10631558Srgrimes 10641558Srgrimes /* 10651558Srgrimes * Get the real pathname and make sure it is a directory 10669336Sdfr * or a regular file if the -r option was specified 10679336Sdfr * and it exists. 10681558Srgrimes */ 106951968Salfred if (realpath(rpcpath, dirpath) == NULL || 10701558Srgrimes stat(dirpath, &stb) < 0 || 10711558Srgrimes statfs(dirpath, &fsb) < 0) { 10721558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 107331656Sguido syslog(LOG_NOTICE, 107437663Scharnier "mount request from %s for non existent path %s", 107574462Salfred numerichost, dirpath); 10761558Srgrimes if (debug) 107737663Scharnier warnx("stat failed on %s", dirpath); 107828911Sguido bad = ENOENT; /* We will send error reply later */ 10791558Srgrimes } 1080330092Srpokala if (!bad && 1081330092Srpokala !S_ISDIR(stb.st_mode) && 1082330092Srpokala (dir_only || !S_ISREG(stb.st_mode))) { 1083330092Srpokala syslog(LOG_NOTICE, 1084330092Srpokala "mount request from %s for non-directory path %s", 1085330092Srpokala numerichost, dirpath); 1086330092Srpokala if (debug) 1087330092Srpokala warnx("mounting non-directory %s", dirpath); 1088330092Srpokala bad = ENOTDIR; /* We will send error reply later */ 1089330092Srpokala } 10901558Srgrimes 10911558Srgrimes /* Check in the exports list */ 10929336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1093330092Srpokala if (bad) 1094330092Srpokala ep = NULL; 1095330092Srpokala else 1096349756Srmacklem ep = ex_search(&fsb.f_fsid, exphead); 10979336Sdfr hostset = defset = 0; 1098240902Srmacklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1099240902Srmacklem &numsecflavors, &secflavorsp) || 11001558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1101240902Srmacklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1102240902Srmacklem &secflavorsp)) || 110374462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 110474462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 110528911Sguido if (bad) { 1106121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 110728911Sguido (caddr_t)&bad)) 110837663Scharnier syslog(LOG_ERR, "can't send reply"); 110928911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 111028911Sguido return; 111128911Sguido } 1112240902Srmacklem if (hostset & DP_HOSTSET) { 11139336Sdfr fhr.fhr_flag = hostset; 1114240902Srmacklem fhr.fhr_numsecflavors = numsecflavors; 1115240902Srmacklem fhr.fhr_secflavors = secflavorsp; 1116240902Srmacklem } else { 11179336Sdfr fhr.fhr_flag = defset; 1118240902Srmacklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1119240902Srmacklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1120240902Srmacklem } 11219336Sdfr fhr.fhr_vers = rqstp->rq_vers; 11221558Srgrimes /* Get the file handle */ 112323681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 11249336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 11251558Srgrimes bad = errno; 112637663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1127121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 11281558Srgrimes (caddr_t)&bad)) 112937663Scharnier syslog(LOG_ERR, "can't send reply"); 11309336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11311558Srgrimes return; 11321558Srgrimes } 1133121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1134121556Speter (caddr_t)&fhr)) 113537663Scharnier syslog(LOG_ERR, "can't send reply"); 113674462Salfred if (!lookup_failed) 113774462Salfred add_mlist(host, dirpath); 11381558Srgrimes else 113974462Salfred add_mlist(numerichost, dirpath); 11401558Srgrimes if (debug) 114137663Scharnier warnx("mount successful"); 1142121767Speter if (dolog) 114331656Sguido syslog(LOG_NOTICE, 114431656Sguido "mount request succeeded from %s for %s", 114574462Salfred numerichost, dirpath); 114631656Sguido } else { 1147330092Srpokala if (!bad) 1148330092Srpokala bad = EACCES; 114931656Sguido syslog(LOG_NOTICE, 115031656Sguido "mount request denied from %s for %s", 115174462Salfred numerichost, dirpath); 115231656Sguido } 115328911Sguido 1154121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1155121556Speter (caddr_t)&bad)) 115637663Scharnier syslog(LOG_ERR, "can't send reply"); 11579336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11581558Srgrimes return; 1159194880Sdfr case MOUNTPROC_DUMP: 1160121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 116137663Scharnier syslog(LOG_ERR, "can't send reply"); 1162121767Speter else if (dolog) 116331656Sguido syslog(LOG_NOTICE, 116431656Sguido "dump request succeeded from %s", 116574462Salfred numerichost); 11661558Srgrimes return; 1167194880Sdfr case MOUNTPROC_UMNT: 11689336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 116931656Sguido syslog(LOG_NOTICE, 117031656Sguido "umount request from %s from unprivileged port", 117174462Salfred numerichost); 11721558Srgrimes svcerr_weakauth(transp); 11731558Srgrimes return; 11741558Srgrimes } 1175121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 117631656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 117774462Salfred numerichost); 11781558Srgrimes svcerr_decode(transp); 11791558Srgrimes return; 11801558Srgrimes } 118151968Salfred if (realpath(rpcpath, dirpath) == NULL) { 118251968Salfred syslog(LOG_NOTICE, "umount request from %s " 118351968Salfred "for non existent path %s", 118474462Salfred numerichost, dirpath); 118551968Salfred } 1186121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 118737663Scharnier syslog(LOG_ERR, "can't send reply"); 118874462Salfred if (!lookup_failed) 118975635Siedowse del_mlist(host, dirpath); 119075635Siedowse del_mlist(numerichost, dirpath); 1191121767Speter if (dolog) 119231656Sguido syslog(LOG_NOTICE, 119331656Sguido "umount request succeeded from %s for %s", 119474462Salfred numerichost, dirpath); 11951558Srgrimes return; 1196194880Sdfr case MOUNTPROC_UMNTALL: 11979336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 119831656Sguido syslog(LOG_NOTICE, 119931656Sguido "umountall request from %s from unprivileged port", 120074462Salfred numerichost); 12011558Srgrimes svcerr_weakauth(transp); 12021558Srgrimes return; 12031558Srgrimes } 1204121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 120537663Scharnier syslog(LOG_ERR, "can't send reply"); 120674462Salfred if (!lookup_failed) 120775635Siedowse del_mlist(host, NULL); 120875635Siedowse del_mlist(numerichost, NULL); 1209121767Speter if (dolog) 121031656Sguido syslog(LOG_NOTICE, 121131656Sguido "umountall request succeeded from %s", 121274462Salfred numerichost); 12131558Srgrimes return; 1214194880Sdfr case MOUNTPROC_EXPORT: 1215121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1216121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1217121556Speter (caddr_t)NULL)) 1218100117Salfred syslog(LOG_ERR, "can't send reply"); 1219121767Speter if (dolog) 122031656Sguido syslog(LOG_NOTICE, 122131656Sguido "export request succeeded from %s", 122274462Salfred numerichost); 12231558Srgrimes return; 12241558Srgrimes default: 12251558Srgrimes svcerr_noproc(transp); 12261558Srgrimes return; 12271558Srgrimes } 12281558Srgrimes} 12291558Srgrimes 12301558Srgrimes/* 12311558Srgrimes * Xdr conversion for a dirpath string 12321558Srgrimes */ 1233285128Straszstatic int 1234216587Scharnierxdr_dir(XDR *xdrsp, char *dirp) 12351558Srgrimes{ 1236194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 12371558Srgrimes} 12381558Srgrimes 12391558Srgrimes/* 12409336Sdfr * Xdr routine to generate file handle reply 12411558Srgrimes */ 1242285128Straszstatic int 1243216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp) 12441558Srgrimes{ 124592806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 12469336Sdfr u_long ok = 0, len, auth; 1247184588Sdfr int i; 12481558Srgrimes 12491558Srgrimes if (!xdr_long(xdrsp, &ok)) 12501558Srgrimes return (0); 12519336Sdfr switch (fhrp->fhr_vers) { 12529336Sdfr case 1: 12539336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 12549336Sdfr case 3: 12559336Sdfr len = NFSX_V3FH; 12569336Sdfr if (!xdr_long(xdrsp, &len)) 12579336Sdfr return (0); 12589336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 12599336Sdfr return (0); 1260184588Sdfr if (fhrp->fhr_numsecflavors) { 1261184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1262184588Sdfr return (0); 1263184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1264184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1265184588Sdfr return (0); 1266184588Sdfr return (1); 1267184588Sdfr } else { 1268184588Sdfr auth = AUTH_SYS; 1269184588Sdfr len = 1; 1270184588Sdfr if (!xdr_long(xdrsp, &len)) 1271184588Sdfr return (0); 1272184588Sdfr return (xdr_long(xdrsp, &auth)); 1273184588Sdfr } 1274298089Spfg } 12759336Sdfr return (0); 12761558Srgrimes} 12771558Srgrimes 1278285128Straszstatic int 1279216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 12801558Srgrimes{ 12811558Srgrimes struct mountlist *mlp; 12821558Srgrimes int true = 1; 12831558Srgrimes int false = 0; 12841558Srgrimes char *strp; 12851558Srgrimes 1286324955Smanu SLIST_FOREACH(mlp, &mlhead, next) { 12871558Srgrimes if (!xdr_bool(xdrsp, &true)) 12881558Srgrimes return (0); 12891558Srgrimes strp = &mlp->ml_host[0]; 1290194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 12911558Srgrimes return (0); 12921558Srgrimes strp = &mlp->ml_dirp[0]; 1293194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12941558Srgrimes return (0); 12951558Srgrimes } 12961558Srgrimes if (!xdr_bool(xdrsp, &false)) 12971558Srgrimes return (0); 12981558Srgrimes return (1); 12991558Srgrimes} 13001558Srgrimes 13011558Srgrimes/* 13021558Srgrimes * Xdr conversion for export list 13031558Srgrimes */ 1304285128Straszstatic int 1305216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 13061558Srgrimes{ 13071558Srgrimes struct exportlist *ep; 13081558Srgrimes int false = 0; 13099336Sdfr int putdef; 13109336Sdfr sigset_t sighup_mask; 1311349756Srmacklem int i; 13121558Srgrimes 13139336Sdfr sigemptyset(&sighup_mask); 13149336Sdfr sigaddset(&sighup_mask, SIGHUP); 13159336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1316324955Smanu 1317349756Srmacklem for (i = 0; i < exphashsize; i++) 1318349756Srmacklem SLIST_FOREACH(ep, &exphead[i], entries) { 1319349756Srmacklem putdef = 0; 1320349756Srmacklem if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1321349756Srmacklem &putdef, brief)) 1322349756Srmacklem goto errout; 1323349756Srmacklem if (ep->ex_defdir && putdef == 0 && 1324349756Srmacklem put_exlist(ep->ex_defdir, xdrsp, NULL, 1325349756Srmacklem &putdef, brief)) 1326349756Srmacklem goto errout; 1327349756Srmacklem } 13289336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13291558Srgrimes if (!xdr_bool(xdrsp, &false)) 13301558Srgrimes return (0); 13311558Srgrimes return (1); 13321558Srgrimeserrout: 13339336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13341558Srgrimes return (0); 13351558Srgrimes} 13361558Srgrimes 13371558Srgrimes/* 13381558Srgrimes * Called from xdr_explist() to traverse the tree and export the 13391558Srgrimes * directory paths. 13401558Srgrimes */ 1341285128Straszstatic int 1342216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1343216587Scharnier int brief) 13441558Srgrimes{ 13451558Srgrimes struct grouplist *grp; 13461558Srgrimes struct hostlist *hp; 13471558Srgrimes int true = 1; 13481558Srgrimes int false = 0; 13491558Srgrimes int gotalldir = 0; 13501558Srgrimes char *strp; 13511558Srgrimes 13521558Srgrimes if (dp) { 1353100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 13541558Srgrimes return (1); 13551558Srgrimes if (!xdr_bool(xdrsp, &true)) 13561558Srgrimes return (1); 13571558Srgrimes strp = dp->dp_dirp; 1358194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 13591558Srgrimes return (1); 13601558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 13611558Srgrimes gotalldir = 1; 13621558Srgrimes *putdefp = 1; 13631558Srgrimes } 1364100117Salfred if (brief) { 1365100117Salfred if (!xdr_bool(xdrsp, &true)) 1366100117Salfred return (1); 1367100117Salfred strp = "(...)"; 1368194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1369100117Salfred return (1); 1370100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 13711558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 13721558Srgrimes hp = dp->dp_hosts; 13731558Srgrimes while (hp) { 13741558Srgrimes grp = hp->ht_grp; 13751558Srgrimes if (grp->gr_type == GT_HOST) { 13761558Srgrimes if (!xdr_bool(xdrsp, &true)) 13771558Srgrimes return (1); 137874462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 13798871Srgrimes if (!xdr_string(xdrsp, &strp, 1380194880Sdfr MNTNAMLEN)) 13811558Srgrimes return (1); 13821558Srgrimes } else if (grp->gr_type == GT_NET) { 13831558Srgrimes if (!xdr_bool(xdrsp, &true)) 13841558Srgrimes return (1); 13851558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 13868871Srgrimes if (!xdr_string(xdrsp, &strp, 1387194880Sdfr MNTNAMLEN)) 13881558Srgrimes return (1); 13891558Srgrimes } 13901558Srgrimes hp = hp->ht_next; 13911558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 13921558Srgrimes hp = adp->dp_hosts; 13931558Srgrimes gotalldir = 0; 13941558Srgrimes } 13951558Srgrimes } 13961558Srgrimes } 13971558Srgrimes if (!xdr_bool(xdrsp, &false)) 13981558Srgrimes return (1); 1399100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 14001558Srgrimes return (1); 14011558Srgrimes } 14021558Srgrimes return (0); 14031558Srgrimes} 14041558Srgrimes 1405285128Straszstatic int 1406216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp) 1407100117Salfred{ 1408100117Salfred 1409100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1410100117Salfred} 1411100117Salfred 1412285128Straszstatic int 1413216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1414100117Salfred{ 1415100117Salfred 1416100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1417100117Salfred} 1418100117Salfred 1419285128Straszstatic char *line; 1420285128Straszstatic size_t linesize; 1421285128Straszstatic FILE *exp_file; 14221558Srgrimes 14231558Srgrimes/* 1424166440Spjd * Get the export list from one, currently open file 14251558Srgrimes */ 1426166440Spjdstatic void 1427216587Scharnierget_exportlist_one(void) 14281558Srgrimes{ 1429324955Smanu struct exportlist *ep; 14301558Srgrimes struct grouplist *grp, *tgrp; 14311558Srgrimes struct dirlist *dirhead; 1432166440Spjd struct statfs fsb; 143372650Sgreen struct xucred anon; 14341558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1435166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 14361558Srgrimes 1437192934Srmacklem v4root_phase = 0; 14381558Srgrimes dirhead = (struct dirlist *)NULL; 14391558Srgrimes while (get_line()) { 14401558Srgrimes if (debug) 144137663Scharnier warnx("got line %s", line); 14421558Srgrimes cp = line; 14431558Srgrimes nextfield(&cp, &endcp); 14441558Srgrimes if (*cp == '#') 14451558Srgrimes goto nextline; 14461558Srgrimes 14471558Srgrimes /* 14481558Srgrimes * Set defaults. 14491558Srgrimes */ 14501558Srgrimes has_host = FALSE; 14511558Srgrimes anon = def_anon; 14521558Srgrimes exflags = MNT_EXPORTED; 14531558Srgrimes got_nondir = 0; 14541558Srgrimes opt_flags = 0; 14551558Srgrimes ep = (struct exportlist *)NULL; 1456192934Srmacklem dirp = NULL; 14571558Srgrimes 14581558Srgrimes /* 1459192934Srmacklem * Handle the V4 root dir. 1460192934Srmacklem */ 1461192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1462192934Srmacklem /* 1463192934Srmacklem * V4: just indicates that it is the v4 root point, 1464192934Srmacklem * so skip over that and set v4root_phase. 1465192934Srmacklem */ 1466192934Srmacklem if (v4root_phase > 0) { 1467192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1468192934Srmacklem goto nextline; 1469192934Srmacklem } 1470192934Srmacklem v4root_phase = 1; 1471192934Srmacklem cp += 3; 1472192934Srmacklem nextfield(&cp, &endcp); 1473192934Srmacklem } 1474192934Srmacklem 1475192934Srmacklem /* 14761558Srgrimes * Create new exports list entry 14771558Srgrimes */ 14781558Srgrimes len = endcp-cp; 14791558Srgrimes tgrp = grp = get_grp(); 14801558Srgrimes while (len > 0) { 1481194880Sdfr if (len > MNTNAMLEN) { 1482329392Sbrd getexp_err(ep, tgrp, "mountpoint too long"); 14831558Srgrimes goto nextline; 14841558Srgrimes } 14851558Srgrimes if (*cp == '-') { 14861558Srgrimes if (ep == (struct exportlist *)NULL) { 1487329392Sbrd getexp_err(ep, tgrp, 1488329392Sbrd "flag before export path definition"); 14891558Srgrimes goto nextline; 14901558Srgrimes } 14911558Srgrimes if (debug) 149237663Scharnier warnx("doing opt %s", cp); 14931558Srgrimes got_nondir = 1; 14941558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 14951558Srgrimes &exflags, &anon)) { 1496329392Sbrd getexp_err(ep, tgrp, NULL); 14971558Srgrimes goto nextline; 14981558Srgrimes } 14991558Srgrimes } else if (*cp == '/') { 15001558Srgrimes savedc = *endcp; 15011558Srgrimes *endcp = '\0'; 1502192934Srmacklem if (v4root_phase > 1) { 1503192934Srmacklem if (dirp != NULL) { 1504329392Sbrd getexp_err(ep, tgrp, "Multiple V4 dirs"); 1505192934Srmacklem goto nextline; 1506192934Srmacklem } 1507192934Srmacklem } 15081558Srgrimes if (check_dirpath(cp) && 15091558Srgrimes statfs(cp, &fsb) >= 0) { 1510283008Srmacklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 1511283008Srmacklem syslog(LOG_ERR, "Warning: exporting of " 1512283008Srmacklem "automounted fs %s not supported", cp); 15131558Srgrimes if (got_nondir) { 1514329392Sbrd getexp_err(ep, tgrp, "dirs must be first"); 15151558Srgrimes goto nextline; 15161558Srgrimes } 1517192934Srmacklem if (v4root_phase == 1) { 1518192934Srmacklem if (dirp != NULL) { 1519329392Sbrd getexp_err(ep, tgrp, "Multiple V4 dirs"); 15201558Srgrimes goto nextline; 15211558Srgrimes } 1522192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1523192934Srmacklem strlcpy(v4root_dirpath, cp, 1524192934Srmacklem sizeof (v4root_dirpath)); 1525192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1526192934Srmacklem != 0) { 1527192934Srmacklem syslog(LOG_ERR, 1528192934Srmacklem "different V4 dirpath %s", cp); 1529329392Sbrd getexp_err(ep, tgrp, NULL); 1530192934Srmacklem goto nextline; 1531192934Srmacklem } 1532192934Srmacklem dirp = cp; 1533192934Srmacklem v4root_phase = 2; 1534192934Srmacklem got_nondir = 1; 1535192934Srmacklem ep = get_exp(); 15361558Srgrimes } else { 1537192934Srmacklem if (ep) { 1538192934Srmacklem if (ep->ex_fs.val[0] != 1539192934Srmacklem fsb.f_fsid.val[0] || 1540192934Srmacklem ep->ex_fs.val[1] != 1541192934Srmacklem fsb.f_fsid.val[1]) { 1542329392Sbrd getexp_err(ep, tgrp, 1543329392Sbrd "fsid mismatch"); 1544192934Srmacklem goto nextline; 1545192934Srmacklem } 1546192934Srmacklem } else { 1547192934Srmacklem /* 1548192934Srmacklem * See if this directory is already 1549192934Srmacklem * in the list. 1550192934Srmacklem */ 1551349756Srmacklem ep = ex_search(&fsb.f_fsid, exphead); 1552192934Srmacklem if (ep == (struct exportlist *)NULL) { 1553192934Srmacklem ep = get_exp(); 1554192934Srmacklem ep->ex_fs = fsb.f_fsid; 1555324234Smanu ep->ex_fsdir = strdup(fsb.f_mntonname); 1556324234Smanu if (ep->ex_fsdir == NULL) 1557192934Srmacklem out_of_mem(); 1558192934Srmacklem if (debug) 1559192934Srmacklem warnx( 1560192934Srmacklem "making new ep fs=0x%x,0x%x", 1561192934Srmacklem fsb.f_fsid.val[0], 1562192934Srmacklem fsb.f_fsid.val[1]); 1563192934Srmacklem } else if (debug) 1564192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1565192934Srmacklem fsb.f_fsid.val[0], 1566192934Srmacklem fsb.f_fsid.val[1]); 1567192934Srmacklem } 1568192934Srmacklem 15691558Srgrimes /* 1570192934Srmacklem * Add dirpath to export mount point. 15711558Srgrimes */ 1572192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1573192934Srmacklem dirplen = len; 15741558Srgrimes } 15751558Srgrimes } else { 1576329392Sbrd getexp_err(ep, tgrp, 1577329392Sbrd "symbolic link in export path or statfs failed"); 15781558Srgrimes goto nextline; 15791558Srgrimes } 15801558Srgrimes *endcp = savedc; 15811558Srgrimes } else { 15821558Srgrimes savedc = *endcp; 15831558Srgrimes *endcp = '\0'; 15841558Srgrimes got_nondir = 1; 15851558Srgrimes if (ep == (struct exportlist *)NULL) { 1586329392Sbrd getexp_err(ep, tgrp, 1587329392Sbrd "host(s) before export path definition"); 15881558Srgrimes goto nextline; 15891558Srgrimes } 15901558Srgrimes 15911558Srgrimes /* 15921558Srgrimes * Get the host or netgroup. 15931558Srgrimes */ 15941558Srgrimes setnetgrent(cp); 15951558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 15961558Srgrimes do { 15971558Srgrimes if (has_host) { 15981558Srgrimes grp->gr_next = get_grp(); 15991558Srgrimes grp = grp->gr_next; 16001558Srgrimes } 16011558Srgrimes if (netgrp) { 160237003Sjoerg if (hst == 0) { 160337663Scharnier syslog(LOG_ERR, 160437663Scharnier "null hostname in netgroup %s, skipping", cp); 160537004Sjoerg grp->gr_type = GT_IGNORE; 160637003Sjoerg } else if (get_host(hst, grp, tgrp)) { 160737663Scharnier syslog(LOG_ERR, 160837663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 160929317Sjlemon grp->gr_type = GT_IGNORE; 16101558Srgrimes } 16117401Swpaul } else if (get_host(cp, grp, tgrp)) { 161237663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 161329317Sjlemon grp->gr_type = GT_IGNORE; 16141558Srgrimes } 16151558Srgrimes has_host = TRUE; 16161558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 16171558Srgrimes endnetgrent(); 16181558Srgrimes *endcp = savedc; 16191558Srgrimes } 16201558Srgrimes cp = endcp; 16211558Srgrimes nextfield(&cp, &endcp); 16221558Srgrimes len = endcp - cp; 16231558Srgrimes } 16241558Srgrimes if (check_options(dirhead)) { 1625329392Sbrd getexp_err(ep, tgrp, NULL); 16261558Srgrimes goto nextline; 16271558Srgrimes } 16281558Srgrimes if (!has_host) { 162975641Siedowse grp->gr_type = GT_DEFAULT; 16301558Srgrimes if (debug) 163137663Scharnier warnx("adding a default entry"); 16321558Srgrimes 16331558Srgrimes /* 16341558Srgrimes * Don't allow a network export coincide with a list of 16351558Srgrimes * host(s) on the same line. 16361558Srgrimes */ 16371558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1638329392Sbrd getexp_err(ep, tgrp, "network/host conflict"); 16391558Srgrimes goto nextline; 164029317Sjlemon 164174462Salfred /* 164274462Salfred * If an export list was specified on this line, make sure 164329317Sjlemon * that we have at least one valid entry, otherwise skip it. 164429317Sjlemon */ 164529317Sjlemon } else { 164629317Sjlemon grp = tgrp; 164774462Salfred while (grp && grp->gr_type == GT_IGNORE) 164829317Sjlemon grp = grp->gr_next; 164929317Sjlemon if (! grp) { 1650329392Sbrd getexp_err(ep, tgrp, "no valid entries"); 165129317Sjlemon goto nextline; 165229317Sjlemon } 16531558Srgrimes } 16541558Srgrimes 1655192934Srmacklem if (v4root_phase == 1) { 1656329392Sbrd getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); 1657192934Srmacklem goto nextline; 1658192934Srmacklem } 1659192934Srmacklem 16601558Srgrimes /* 16611558Srgrimes * Loop through hosts, pushing the exports into the kernel. 16621558Srgrimes * After loop, tgrp points to the start of the list and 16631558Srgrimes * grp points to the last entry in the list. 16641558Srgrimes */ 16651558Srgrimes grp = tgrp; 16661558Srgrimes do { 166775635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 166875635Siedowse &fsb)) { 1669329392Sbrd getexp_err(ep, tgrp, NULL); 167075635Siedowse goto nextline; 167175635Siedowse } 16721558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 16731558Srgrimes 16741558Srgrimes /* 1675192934Srmacklem * For V4: don't enter in mount lists. 1676192934Srmacklem */ 1677194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1678194773Srmacklem /* 1679194773Srmacklem * Since these structures aren't used by mountd, 1680194773Srmacklem * free them up now. 1681194773Srmacklem */ 1682194773Srmacklem if (ep != NULL) 1683194773Srmacklem free_exp(ep); 1684194773Srmacklem while (tgrp != NULL) { 1685194773Srmacklem grp = tgrp; 1686194773Srmacklem tgrp = tgrp->gr_next; 1687194773Srmacklem free_grp(grp); 1688194773Srmacklem } 1689192934Srmacklem goto nextline; 1690194773Srmacklem } 1691192934Srmacklem 1692192934Srmacklem /* 16931558Srgrimes * Success. Update the data structures. 16941558Srgrimes */ 16951558Srgrimes if (has_host) { 16969336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 1697349128Srmacklem grp->gr_next = ep->ex_grphead; 1698349128Srmacklem ep->ex_grphead = tgrp; 16991558Srgrimes } else { 17001558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 17019336Sdfr opt_flags); 17021558Srgrimes free_grp(grp); 17031558Srgrimes } 17041558Srgrimes dirhead = (struct dirlist *)NULL; 17051558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 1706349756Srmacklem insert_exports(ep, exphead); 17071558Srgrimes 17081558Srgrimes ep->ex_flag |= EX_LINKED; 17091558Srgrimes } 17101558Srgrimesnextline: 1711192934Srmacklem v4root_phase = 0; 17121558Srgrimes if (dirhead) { 17131558Srgrimes free_dir(dirhead); 17141558Srgrimes dirhead = (struct dirlist *)NULL; 17151558Srgrimes } 17161558Srgrimes } 17171558Srgrimes} 17181558Srgrimes 17191558Srgrimes/* 1720166440Spjd * Get the export list from all specified files 1721166440Spjd */ 1722285128Straszstatic void 1723216587Scharnierget_exportlist(void) 1724166440Spjd{ 1725166440Spjd struct export_args export; 1726166440Spjd struct iovec *iov; 1727349126Srmacklem struct statfs *mntbufp; 1728166440Spjd char errmsg[255]; 1729230352Seadler int num, i; 1730166440Spjd int iovlen; 1731192934Srmacklem struct nfsex_args eargs; 1732166440Spjd 1733241568Srmacklem if (suspend_nfsd != 0) 1734241568Srmacklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 1735192934Srmacklem v4root_dirpath[0] = '\0'; 1736166440Spjd bzero(&export, sizeof(export)); 1737166440Spjd export.ex_flags = MNT_DELEXPORT; 1738166440Spjd iov = NULL; 1739166440Spjd iovlen = 0; 1740166440Spjd bzero(errmsg, sizeof(errmsg)); 1741166440Spjd 1742166440Spjd /* 1743166440Spjd * First, get rid of the old list 1744166440Spjd */ 1745349756Srmacklem if (exphead != NULL) 1746349756Srmacklem free_exports(exphead); 1747166440Spjd 1748166440Spjd /* 1749192934Srmacklem * and the old V4 root dir. 1750192934Srmacklem */ 1751192934Srmacklem bzero(&eargs, sizeof (eargs)); 1752192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1753282214Strasz if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1754192934Srmacklem errno != ENOENT) 1755192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1756192934Srmacklem 1757192934Srmacklem /* 1758192934Srmacklem * and clear flag that notes if a public fh has been exported. 1759192934Srmacklem */ 1760192934Srmacklem has_publicfh = 0; 1761192934Srmacklem 1762192934Srmacklem /* 1763166440Spjd * And delete exports that are in the kernel for all local 1764166440Spjd * filesystems. 1765166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1766166440Spjd */ 1767166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1768166440Spjd 1769349756Srmacklem /* Allocate hash tables, for first call. */ 1770349756Srmacklem if (exphead == NULL) { 1771349756Srmacklem /* Target an average linked list length of 10. */ 1772349756Srmacklem exphashsize = num / 10; 1773349756Srmacklem if (exphashsize < 1) 1774349756Srmacklem exphashsize = 1; 1775349756Srmacklem else if (exphashsize > 100000) 1776349756Srmacklem exphashsize = 100000; 1777349756Srmacklem exphead = malloc(exphashsize * sizeof(*exphead)); 1778349756Srmacklem if (exphead == NULL) 1779349756Srmacklem errx(1, "Can't malloc hash table"); 1780349756Srmacklem 1781349756Srmacklem for (i = 0; i < exphashsize; i++) 1782349756Srmacklem SLIST_INIT(&exphead[i]); 1783349756Srmacklem } 1784166440Spjd if (num > 0) { 1785166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1786166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1787166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1788166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1789166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1790166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1791166440Spjd } 1792166440Spjd 1793349126Srmacklem for (i = 0; i < num; i++) 1794349126Srmacklem delete_export(iov, iovlen, &mntbufp[i], errmsg); 1795166440Spjd 1796166440Spjd if (iov != NULL) { 1797166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1798166440Spjd free(iov[0].iov_base); /* fstype */ 1799166440Spjd free(iov[2].iov_base); /* fspath */ 1800166440Spjd free(iov[4].iov_base); /* from */ 1801166440Spjd free(iov[6].iov_base); /* update */ 1802166440Spjd free(iov[8].iov_base); /* export */ 1803166440Spjd free(iov[10].iov_base); /* errmsg */ 1804166440Spjd 1805166440Spjd /* free iov, allocated by realloc() */ 1806166440Spjd free(iov); 1807166440Spjd iovlen = 0; 1808166440Spjd } 1809166440Spjd 1810349126Srmacklem read_exportfile(); 1811192934Srmacklem 1812192934Srmacklem /* 1813192934Srmacklem * If there was no public fh, clear any previous one set. 1814192934Srmacklem */ 1815282214Strasz if (has_publicfh == 0) 1816192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1817241568Srmacklem 1818241568Srmacklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1819241568Srmacklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 1820166440Spjd} 1821166440Spjd 1822166440Spjd/* 1823349124Srmacklem * Insert an export entry in the appropriate list. 1824349124Srmacklem */ 1825349124Srmacklemstatic void 1826349124Srmackleminsert_exports(struct exportlist *ep, struct exportlisthead *exhp) 1827349124Srmacklem{ 1828349756Srmacklem uint32_t i; 1829349124Srmacklem 1830349756Srmacklem i = EXPHASH(&ep->ex_fs); 1831349756Srmacklem SLIST_INSERT_HEAD(&exhp[i], ep, entries); 1832349124Srmacklem} 1833349124Srmacklem 1834349124Srmacklem/* 1835349124Srmacklem * Free up the exports lists passed in as arguments. 1836349124Srmacklem */ 1837349124Srmacklemstatic void 1838349124Srmacklemfree_exports(struct exportlisthead *exhp) 1839349124Srmacklem{ 1840349124Srmacklem struct exportlist *ep, *ep2; 1841349756Srmacklem int i; 1842349124Srmacklem 1843349756Srmacklem for (i = 0; i < exphashsize; i++) { 1844349756Srmacklem SLIST_FOREACH_SAFE(ep, &exhp[i], entries, ep2) { 1845349756Srmacklem SLIST_REMOVE(&exhp[i], ep, exportlist, entries); 1846349756Srmacklem free_exp(ep); 1847349756Srmacklem } 1848349756Srmacklem SLIST_INIT(&exhp[i]); 1849349124Srmacklem } 1850349124Srmacklem} 1851349124Srmacklem 1852349124Srmacklem/* 1853349126Srmacklem * Read the exports file(s) and call get_exportlist_one() for each line. 1854349126Srmacklem */ 1855349126Srmacklemstatic void 1856349126Srmacklemread_exportfile(void) 1857349126Srmacklem{ 1858349126Srmacklem int done, i; 1859349126Srmacklem 1860349126Srmacklem /* 1861349126Srmacklem * Read in the exports file and build the list, calling 1862349126Srmacklem * nmount() as we go along to push the export rules into the kernel. 1863349126Srmacklem */ 1864349126Srmacklem done = 0; 1865349126Srmacklem for (i = 0; exnames[i] != NULL; i++) { 1866349126Srmacklem if (debug) 1867349126Srmacklem warnx("reading exports from %s", exnames[i]); 1868349126Srmacklem if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1869349126Srmacklem syslog(LOG_WARNING, "can't open %s", exnames[i]); 1870349126Srmacklem continue; 1871349126Srmacklem } 1872349126Srmacklem get_exportlist_one(); 1873349126Srmacklem fclose(exp_file); 1874349126Srmacklem done++; 1875349126Srmacklem } 1876349126Srmacklem if (done == 0) { 1877349126Srmacklem syslog(LOG_ERR, "can't open any exports file"); 1878349126Srmacklem exit(2); 1879349126Srmacklem } 1880349126Srmacklem} 1881349126Srmacklem 1882349126Srmacklem/* 1883349126Srmacklem * Delete an exports entry. 1884349126Srmacklem */ 1885349126Srmacklemstatic void 1886349126Srmacklemdelete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) 1887349126Srmacklem{ 1888349126Srmacklem struct xvfsconf vfc; 1889349126Srmacklem 1890349126Srmacklem if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1891349126Srmacklem syslog(LOG_ERR, "getvfsbyname() failed for %s", 1892349126Srmacklem fsp->f_fstypename); 1893349126Srmacklem return; 1894349126Srmacklem } 1895349126Srmacklem 1896349126Srmacklem /* 1897349126Srmacklem * We do not need to delete "export" flag from 1898349126Srmacklem * filesystems that do not have it set. 1899349126Srmacklem */ 1900349126Srmacklem if (!(fsp->f_flags & MNT_EXPORTED)) 1901349126Srmacklem return; 1902349126Srmacklem /* 1903349126Srmacklem * Do not delete export for network filesystem by 1904349126Srmacklem * passing "export" arg to nmount(). 1905349126Srmacklem * It only makes sense to do this for local filesystems. 1906349126Srmacklem */ 1907349126Srmacklem if (vfc.vfc_flags & VFCF_NETWORK) 1908349126Srmacklem return; 1909349126Srmacklem 1910349126Srmacklem iov[1].iov_base = fsp->f_fstypename; 1911349126Srmacklem iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1912349126Srmacklem iov[3].iov_base = fsp->f_mntonname; 1913349126Srmacklem iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1914349126Srmacklem iov[5].iov_base = fsp->f_mntfromname; 1915349126Srmacklem iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1916349126Srmacklem errmsg[0] = '\0'; 1917349126Srmacklem 1918349126Srmacklem /* 1919349126Srmacklem * EXDEV is returned when path exists but is not a 1920349126Srmacklem * mount point. May happens if raced with unmount. 1921349126Srmacklem */ 1922349126Srmacklem if (nmount(iov, iovlen, fsp->f_flags) < 0 && errno != ENOENT && 1923349126Srmacklem errno != ENOTSUP && errno != EXDEV) { 1924349126Srmacklem syslog(LOG_ERR, 1925349126Srmacklem "can't delete exports for %s: %m %s", 1926349126Srmacklem fsp->f_mntonname, errmsg); 1927349126Srmacklem } 1928349126Srmacklem} 1929349126Srmacklem 1930349126Srmacklem/* 19311558Srgrimes * Allocate an export list element 19321558Srgrimes */ 1933285128Straszstatic struct exportlist * 1934216587Scharnierget_exp(void) 19351558Srgrimes{ 19361558Srgrimes struct exportlist *ep; 19371558Srgrimes 1938224003Sdelphij ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 19391558Srgrimes if (ep == (struct exportlist *)NULL) 19401558Srgrimes out_of_mem(); 19411558Srgrimes return (ep); 19421558Srgrimes} 19431558Srgrimes 19441558Srgrimes/* 19451558Srgrimes * Allocate a group list element 19461558Srgrimes */ 1947285128Straszstatic struct grouplist * 1948216587Scharnierget_grp(void) 19491558Srgrimes{ 19501558Srgrimes struct grouplist *gp; 19511558Srgrimes 1952224003Sdelphij gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 19531558Srgrimes if (gp == (struct grouplist *)NULL) 19541558Srgrimes out_of_mem(); 19551558Srgrimes return (gp); 19561558Srgrimes} 19571558Srgrimes 19581558Srgrimes/* 19591558Srgrimes * Clean up upon an error in get_exportlist(). 19601558Srgrimes */ 1961285128Straszstatic void 1962329392Sbrdgetexp_err(struct exportlist *ep, struct grouplist *grp, const char *reason) 19631558Srgrimes{ 19641558Srgrimes struct grouplist *tgrp; 19651558Srgrimes 1966329392Sbrd if (!(opt_flags & OP_QUIET)) { 1967329392Sbrd if (reason != NULL) 1968329392Sbrd syslog(LOG_ERR, "bad exports list line '%s': %s", line, 1969329392Sbrd reason); 1970329392Sbrd else 1971329392Sbrd syslog(LOG_ERR, "bad exports list line '%s'", line); 1972329392Sbrd } 19731558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 19741558Srgrimes free_exp(ep); 19751558Srgrimes while (grp) { 19761558Srgrimes tgrp = grp; 19771558Srgrimes grp = grp->gr_next; 19781558Srgrimes free_grp(tgrp); 19791558Srgrimes } 19801558Srgrimes} 19811558Srgrimes 19821558Srgrimes/* 19831558Srgrimes * Search the export list for a matching fs. 19841558Srgrimes */ 1985285128Straszstatic struct exportlist * 1986349124Srmacklemex_search(fsid_t *fsid, struct exportlisthead *exhp) 19871558Srgrimes{ 19881558Srgrimes struct exportlist *ep; 1989349756Srmacklem uint32_t i; 19901558Srgrimes 1991349756Srmacklem i = EXPHASH(fsid); 1992349756Srmacklem SLIST_FOREACH(ep, &exhp[i], entries) { 19931558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 19941558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 19951558Srgrimes return (ep); 19961558Srgrimes } 1997324955Smanu 19981558Srgrimes return (ep); 19991558Srgrimes} 20001558Srgrimes 20011558Srgrimes/* 20021558Srgrimes * Add a directory path to the list. 20031558Srgrimes */ 2004285128Straszstatic char * 2005216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len) 20061558Srgrimes{ 20071558Srgrimes struct dirlist *dp; 20081558Srgrimes 2009324234Smanu dp = malloc(sizeof (struct dirlist)); 201037663Scharnier if (dp == (struct dirlist *)NULL) 201137663Scharnier out_of_mem(); 20121558Srgrimes dp->dp_left = *dpp; 20131558Srgrimes dp->dp_right = (struct dirlist *)NULL; 20141558Srgrimes dp->dp_flag = 0; 20151558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 2016324234Smanu dp->dp_dirp = strndup(cp, len); 2017324234Smanu if (dp->dp_dirp == NULL) 2018324234Smanu out_of_mem(); 20191558Srgrimes *dpp = dp; 20201558Srgrimes return (dp->dp_dirp); 20211558Srgrimes} 20221558Srgrimes 20231558Srgrimes/* 20241558Srgrimes * Hang the dir list element off the dirpath binary tree as required 20251558Srgrimes * and update the entry for host. 20261558Srgrimes */ 2027285128Straszstatic void 2028216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 2029216587Scharnier int flags) 20301558Srgrimes{ 20311558Srgrimes struct hostlist *hp; 20321558Srgrimes struct dirlist *dp2; 20331558Srgrimes 20349336Sdfr if (flags & OP_ALLDIRS) { 20351558Srgrimes if (ep->ex_defdir) 20361558Srgrimes free((caddr_t)dp); 20371558Srgrimes else 20381558Srgrimes ep->ex_defdir = dp; 20399336Sdfr if (grp == (struct grouplist *)NULL) { 20401558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 2041240902Srmacklem /* Save the default security flavors list. */ 2042240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2043240902Srmacklem if (ep->ex_numsecflavors > 0) 2044240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2045240902Srmacklem sizeof(ep->ex_secflavors)); 20469336Sdfr } else while (grp) { 20471558Srgrimes hp = get_ht(); 20481558Srgrimes hp->ht_grp = grp; 20491558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 20501558Srgrimes ep->ex_defdir->dp_hosts = hp; 2051240902Srmacklem /* Save the security flavors list for this host set. */ 2052240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2053240902Srmacklem if (ep->ex_numsecflavors > 0) 2054240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2055240902Srmacklem sizeof(ep->ex_secflavors)); 20561558Srgrimes grp = grp->gr_next; 20571558Srgrimes } 20581558Srgrimes } else { 20591558Srgrimes 20601558Srgrimes /* 206137663Scharnier * Loop through the directories adding them to the tree. 20621558Srgrimes */ 20631558Srgrimes while (dp) { 20641558Srgrimes dp2 = dp->dp_left; 2065240902Srmacklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep); 20661558Srgrimes dp = dp2; 20671558Srgrimes } 20681558Srgrimes } 20691558Srgrimes} 20701558Srgrimes 20711558Srgrimes/* 20721558Srgrimes * Traverse the binary tree either updating a node that is already there 20731558Srgrimes * for the new directory or adding the new node. 20741558Srgrimes */ 2075285128Straszstatic void 2076216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2077240902Srmacklem int flags, struct exportlist *ep) 20781558Srgrimes{ 20791558Srgrimes struct dirlist *dp; 20801558Srgrimes struct hostlist *hp; 20811558Srgrimes int cmp; 20821558Srgrimes 20831558Srgrimes dp = *dpp; 20841558Srgrimes if (dp) { 20851558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 20861558Srgrimes if (cmp > 0) { 2087240902Srmacklem add_dlist(&dp->dp_left, newdp, grp, flags, ep); 20881558Srgrimes return; 20891558Srgrimes } else if (cmp < 0) { 2090240902Srmacklem add_dlist(&dp->dp_right, newdp, grp, flags, ep); 20911558Srgrimes return; 20921558Srgrimes } else 20931558Srgrimes free((caddr_t)newdp); 20941558Srgrimes } else { 20951558Srgrimes dp = newdp; 20961558Srgrimes dp->dp_left = (struct dirlist *)NULL; 20971558Srgrimes *dpp = dp; 20981558Srgrimes } 20991558Srgrimes if (grp) { 21001558Srgrimes 21011558Srgrimes /* 21021558Srgrimes * Hang all of the host(s) off of the directory point. 21031558Srgrimes */ 21041558Srgrimes do { 21051558Srgrimes hp = get_ht(); 21061558Srgrimes hp->ht_grp = grp; 21071558Srgrimes hp->ht_next = dp->dp_hosts; 21081558Srgrimes dp->dp_hosts = hp; 2109240902Srmacklem /* Save the security flavors list for this host set. */ 2110240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2111240902Srmacklem if (ep->ex_numsecflavors > 0) 2112240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2113240902Srmacklem sizeof(ep->ex_secflavors)); 21141558Srgrimes grp = grp->gr_next; 21151558Srgrimes } while (grp); 21169336Sdfr } else { 21171558Srgrimes dp->dp_flag |= DP_DEFSET; 2118240902Srmacklem /* Save the default security flavors list. */ 2119240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2120240902Srmacklem if (ep->ex_numsecflavors > 0) 2121240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2122240902Srmacklem sizeof(ep->ex_secflavors)); 21239336Sdfr } 21241558Srgrimes} 21251558Srgrimes 21261558Srgrimes/* 21271558Srgrimes * Search for a dirpath on the export point. 21281558Srgrimes */ 2129285128Straszstatic struct dirlist * 2130216587Scharnierdirp_search(struct dirlist *dp, char *dirp) 21311558Srgrimes{ 21321558Srgrimes int cmp; 21331558Srgrimes 21341558Srgrimes if (dp) { 213574462Salfred cmp = strcmp(dp->dp_dirp, dirp); 21361558Srgrimes if (cmp > 0) 213774462Salfred return (dirp_search(dp->dp_left, dirp)); 21381558Srgrimes else if (cmp < 0) 213974462Salfred return (dirp_search(dp->dp_right, dirp)); 21401558Srgrimes else 21411558Srgrimes return (dp); 21421558Srgrimes } 21431558Srgrimes return (dp); 21441558Srgrimes} 21451558Srgrimes 21461558Srgrimes/* 21471558Srgrimes * Scan for a host match in a directory tree. 21481558Srgrimes */ 2149285128Straszstatic int 2150216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2151240902Srmacklem int *hostsetp, int *numsecflavors, int **secflavorsp) 21521558Srgrimes{ 21531558Srgrimes struct hostlist *hp; 21541558Srgrimes struct grouplist *grp; 215574462Salfred struct addrinfo *ai; 21561558Srgrimes 21571558Srgrimes if (dp) { 21581558Srgrimes if (dp->dp_flag & DP_DEFSET) 21599336Sdfr *defsetp = dp->dp_flag; 21601558Srgrimes hp = dp->dp_hosts; 21611558Srgrimes while (hp) { 21621558Srgrimes grp = hp->ht_grp; 21631558Srgrimes switch (grp->gr_type) { 21641558Srgrimes case GT_HOST: 216574462Salfred ai = grp->gr_ptr.gt_addrinfo; 216674462Salfred for (; ai; ai = ai->ai_next) { 216775801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 216874462Salfred *hostsetp = 216974462Salfred (hp->ht_flag | DP_HOSTSET); 2170240902Srmacklem if (numsecflavors != NULL) { 2171240902Srmacklem *numsecflavors = 2172240902Srmacklem grp->gr_numsecflavors; 2173240902Srmacklem *secflavorsp = 2174240902Srmacklem grp->gr_secflavors; 2175240902Srmacklem } 217674462Salfred return (1); 217774462Salfred } 21789336Sdfr } 217975801Siedowse break; 21801558Srgrimes case GT_NET: 218175801Siedowse if (!sacmp(saddr, (struct sockaddr *) 218275801Siedowse &grp->gr_ptr.gt_net.nt_net, 218375801Siedowse (struct sockaddr *) 218475801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 218574462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 2186240902Srmacklem if (numsecflavors != NULL) { 2187240902Srmacklem *numsecflavors = 2188240902Srmacklem grp->gr_numsecflavors; 2189240902Srmacklem *secflavorsp = 2190240902Srmacklem grp->gr_secflavors; 2191240902Srmacklem } 219274462Salfred return (1); 219374462Salfred } 219475801Siedowse break; 219575801Siedowse } 21961558Srgrimes hp = hp->ht_next; 21971558Srgrimes } 21981558Srgrimes } 21991558Srgrimes return (0); 22001558Srgrimes} 22011558Srgrimes 22021558Srgrimes/* 22031558Srgrimes * Scan tree for a host that matches the address. 22041558Srgrimes */ 2205285128Straszstatic int 2206216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr) 22071558Srgrimes{ 22089336Sdfr int defset, hostset; 22091558Srgrimes 22101558Srgrimes if (dp) { 22111558Srgrimes if (scan_tree(dp->dp_left, saddr)) 22121558Srgrimes return (1); 2213240902Srmacklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 22141558Srgrimes return (1); 22151558Srgrimes if (scan_tree(dp->dp_right, saddr)) 22161558Srgrimes return (1); 22171558Srgrimes } 22181558Srgrimes return (0); 22191558Srgrimes} 22201558Srgrimes 22211558Srgrimes/* 22221558Srgrimes * Traverse the dirlist tree and free it up. 22231558Srgrimes */ 2224285128Straszstatic void 2225216587Scharnierfree_dir(struct dirlist *dp) 22261558Srgrimes{ 22271558Srgrimes 22281558Srgrimes if (dp) { 22291558Srgrimes free_dir(dp->dp_left); 22301558Srgrimes free_dir(dp->dp_right); 22311558Srgrimes free_host(dp->dp_hosts); 2232324234Smanu free(dp->dp_dirp); 2233324234Smanu free(dp); 22341558Srgrimes } 22351558Srgrimes} 22361558Srgrimes 22371558Srgrimes/* 2238184588Sdfr * Parse a colon separated list of security flavors 2239184588Sdfr */ 2240285128Straszstatic int 2241216587Scharnierparsesec(char *seclist, struct exportlist *ep) 2242184588Sdfr{ 2243184588Sdfr char *cp, savedc; 2244184588Sdfr int flavor; 2245184588Sdfr 2246184588Sdfr ep->ex_numsecflavors = 0; 2247184588Sdfr for (;;) { 2248184588Sdfr cp = strchr(seclist, ':'); 2249184588Sdfr if (cp) { 2250184588Sdfr savedc = *cp; 2251184588Sdfr *cp = '\0'; 2252184588Sdfr } 2253184588Sdfr 2254184588Sdfr if (!strcmp(seclist, "sys")) 2255184588Sdfr flavor = AUTH_SYS; 2256184588Sdfr else if (!strcmp(seclist, "krb5")) 2257184588Sdfr flavor = RPCSEC_GSS_KRB5; 2258184588Sdfr else if (!strcmp(seclist, "krb5i")) 2259184588Sdfr flavor = RPCSEC_GSS_KRB5I; 2260184588Sdfr else if (!strcmp(seclist, "krb5p")) 2261184588Sdfr flavor = RPCSEC_GSS_KRB5P; 2262184588Sdfr else { 2263184588Sdfr if (cp) 2264184588Sdfr *cp = savedc; 2265184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2266184588Sdfr return (1); 2267184588Sdfr } 2268184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2269184588Sdfr if (cp) 2270184588Sdfr *cp = savedc; 2271184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2272184588Sdfr return (1); 2273184588Sdfr } 2274184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2275184588Sdfr ep->ex_numsecflavors++; 2276184588Sdfr if (cp) { 2277184588Sdfr *cp = savedc; 2278184588Sdfr seclist = cp + 1; 2279184588Sdfr } else { 2280184588Sdfr break; 2281184588Sdfr } 2282184588Sdfr } 2283184588Sdfr return (0); 2284184588Sdfr} 2285184588Sdfr 2286184588Sdfr/* 22871558Srgrimes * Parse the option string and update fields. 22881558Srgrimes * Option arguments may either be -<option>=<value> or 22891558Srgrimes * -<option> <value> 22901558Srgrimes */ 2291285128Straszstatic int 2292216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2293216587Scharnier int *has_hostp, int *exflagsp, struct xucred *cr) 22941558Srgrimes{ 22951558Srgrimes char *cpoptarg, *cpoptend; 22961558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 22971558Srgrimes int allflag, usedarg; 22981558Srgrimes 229951968Salfred savedc2 = '\0'; 23001558Srgrimes cpopt = *cpp; 23011558Srgrimes cpopt++; 23021558Srgrimes cp = *endcpp; 23031558Srgrimes savedc = *cp; 23041558Srgrimes *cp = '\0'; 23051558Srgrimes while (cpopt && *cpopt) { 23061558Srgrimes allflag = 1; 23071558Srgrimes usedarg = -2; 230837663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 23091558Srgrimes *cpoptend++ = '\0'; 231037663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 23111558Srgrimes *cpoptarg++ = '\0'; 23121558Srgrimes } else { 231337663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 23141558Srgrimes *cpoptarg++ = '\0'; 23151558Srgrimes else { 23161558Srgrimes *cp = savedc; 23171558Srgrimes nextfield(&cp, &endcp); 23181558Srgrimes **endcpp = '\0'; 23191558Srgrimes if (endcp > cp && *cp != '-') { 23201558Srgrimes cpoptarg = cp; 23211558Srgrimes savedc2 = *endcp; 23221558Srgrimes *endcp = '\0'; 23231558Srgrimes usedarg = 0; 23241558Srgrimes } 23251558Srgrimes } 23261558Srgrimes } 23271558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 23281558Srgrimes *exflagsp |= MNT_EXRDONLY; 23291558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 23301558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 23311558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 23321558Srgrimes usedarg++; 23331558Srgrimes parsecred(cpoptarg, cr); 23341558Srgrimes if (allflag == 0) { 23351558Srgrimes *exflagsp |= MNT_EXPORTANON; 23361558Srgrimes opt_flags |= OP_MAPALL; 23371558Srgrimes } else 23381558Srgrimes opt_flags |= OP_MAPROOT; 23391558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 234075801Siedowse !strcmp(cpopt, "m"))) { 23411558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 234237663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 23431558Srgrimes return (1); 23441558Srgrimes } 23451558Srgrimes usedarg++; 23461558Srgrimes opt_flags |= OP_MASK; 23471558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 23481558Srgrimes !strcmp(cpopt, "n"))) { 234974462Salfred if (strchr(cpoptarg, '/') != NULL) { 235074462Salfred if (debug) 235174462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 235274462Salfred opt_flags |= OP_MASKLEN; 235374462Salfred } 23541558Srgrimes if (grp->gr_type != GT_NULL) { 235537663Scharnier syslog(LOG_ERR, "network/host conflict"); 23561558Srgrimes return (1); 23571558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 235837663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 23591558Srgrimes return (1); 23601558Srgrimes } 23611558Srgrimes grp->gr_type = GT_NET; 23621558Srgrimes *has_hostp = 1; 23631558Srgrimes usedarg++; 23641558Srgrimes opt_flags |= OP_NET; 23651558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 23661558Srgrimes opt_flags |= OP_ALLDIRS; 236727447Sdfr } else if (!strcmp(cpopt, "public")) { 236827447Sdfr *exflagsp |= MNT_EXPUBLIC; 236927447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 237027447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 237127447Sdfr opt_flags |= OP_MAPALL; 237227447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 237327447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2374100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2375100336Sjoerg opt_flags |= OP_QUIET; 2376247034Spluknet } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2377184588Sdfr if (parsesec(cpoptarg, ep)) 2378184588Sdfr return (1); 2379184588Sdfr opt_flags |= OP_SEC; 2380184588Sdfr usedarg++; 23811558Srgrimes } else { 238237663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 23831558Srgrimes return (1); 23841558Srgrimes } 23851558Srgrimes if (usedarg >= 0) { 23861558Srgrimes *endcp = savedc2; 23871558Srgrimes **endcpp = savedc; 23881558Srgrimes if (usedarg > 0) { 23891558Srgrimes *cpp = cp; 23901558Srgrimes *endcpp = endcp; 23911558Srgrimes } 23921558Srgrimes return (0); 23931558Srgrimes } 23941558Srgrimes cpopt = cpoptend; 23951558Srgrimes } 23961558Srgrimes **endcpp = savedc; 23971558Srgrimes return (0); 23981558Srgrimes} 23991558Srgrimes 24001558Srgrimes/* 24011558Srgrimes * Translate a character string to the corresponding list of network 24021558Srgrimes * addresses for a hostname. 24031558Srgrimes */ 2404285128Straszstatic int 2405216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 24061558Srgrimes{ 24077401Swpaul struct grouplist *checkgrp; 240875635Siedowse struct addrinfo *ai, *tai, hints; 240974462Salfred int ecode; 241074462Salfred char host[NI_MAXHOST]; 24111558Srgrimes 241274462Salfred if (grp->gr_type != GT_NULL) { 241374462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 24141558Srgrimes return (1); 24151558Srgrimes } 241674462Salfred memset(&hints, 0, sizeof hints); 241774462Salfred hints.ai_flags = AI_CANONNAME; 241874462Salfred hints.ai_protocol = IPPROTO_UDP; 241974462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 242074462Salfred if (ecode != 0) { 242175635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 242274462Salfred return 1; 242374462Salfred } 242474462Salfred grp->gr_ptr.gt_addrinfo = ai; 242574462Salfred while (ai != NULL) { 242674462Salfred if (ai->ai_canonname == NULL) { 242774462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2428146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 242974462Salfred strlcpy(host, "?", sizeof(host)); 243074462Salfred ai->ai_canonname = strdup(host); 243174462Salfred ai->ai_flags |= AI_CANONNAME; 243275641Siedowse } 243374462Salfred if (debug) 243475635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 243575635Siedowse /* 243675635Siedowse * Sanity check: make sure we don't already have an entry 243775635Siedowse * for this host in the grouplist. 243875635Siedowse */ 243975635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 244075635Siedowse checkgrp = checkgrp->gr_next) { 244175635Siedowse if (checkgrp->gr_type != GT_HOST) 244275635Siedowse continue; 244375635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 244475635Siedowse tai = tai->ai_next) { 244575801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 244675635Siedowse continue; 244775635Siedowse if (debug) 244875635Siedowse fprintf(stderr, 244975635Siedowse "ignoring duplicate host %s\n", 245075635Siedowse ai->ai_canonname); 245175635Siedowse grp->gr_type = GT_IGNORE; 245275635Siedowse return (0); 245375635Siedowse } 245475635Siedowse } 245574462Salfred ai = ai->ai_next; 24561558Srgrimes } 245775635Siedowse grp->gr_type = GT_HOST; 24581558Srgrimes return (0); 24591558Srgrimes} 24601558Srgrimes 24611558Srgrimes/* 24621558Srgrimes * Free up an exports list component 24631558Srgrimes */ 2464285128Straszstatic void 2465216587Scharnierfree_exp(struct exportlist *ep) 24661558Srgrimes{ 2467349128Srmacklem struct grouplist *grp, *tgrp; 24681558Srgrimes 24691558Srgrimes if (ep->ex_defdir) { 24701558Srgrimes free_host(ep->ex_defdir->dp_hosts); 24711558Srgrimes free((caddr_t)ep->ex_defdir); 24721558Srgrimes } 24731558Srgrimes if (ep->ex_fsdir) 24741558Srgrimes free(ep->ex_fsdir); 247527447Sdfr if (ep->ex_indexfile) 247627447Sdfr free(ep->ex_indexfile); 24771558Srgrimes free_dir(ep->ex_dirl); 2478349128Srmacklem grp = ep->ex_grphead; 2479349128Srmacklem while (grp) { 2480349128Srmacklem tgrp = grp; 2481349128Srmacklem grp = grp->gr_next; 2482349128Srmacklem free_grp(tgrp); 2483349128Srmacklem } 24841558Srgrimes free((caddr_t)ep); 24851558Srgrimes} 24861558Srgrimes 24871558Srgrimes/* 24881558Srgrimes * Free hosts. 24891558Srgrimes */ 2490285128Straszstatic void 2491216587Scharnierfree_host(struct hostlist *hp) 24921558Srgrimes{ 24931558Srgrimes struct hostlist *hp2; 24941558Srgrimes 24951558Srgrimes while (hp) { 24961558Srgrimes hp2 = hp; 24971558Srgrimes hp = hp->ht_next; 24981558Srgrimes free((caddr_t)hp2); 24991558Srgrimes } 25001558Srgrimes} 25011558Srgrimes 2502285128Straszstatic struct hostlist * 2503216587Scharnierget_ht(void) 25041558Srgrimes{ 25051558Srgrimes struct hostlist *hp; 25061558Srgrimes 25071558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 25081558Srgrimes if (hp == (struct hostlist *)NULL) 25091558Srgrimes out_of_mem(); 25101558Srgrimes hp->ht_next = (struct hostlist *)NULL; 25119336Sdfr hp->ht_flag = 0; 25121558Srgrimes return (hp); 25131558Srgrimes} 25141558Srgrimes 25151558Srgrimes/* 25161558Srgrimes * Out of memory, fatal 25171558Srgrimes */ 2518285128Straszstatic void 2519216587Scharnierout_of_mem(void) 25201558Srgrimes{ 25211558Srgrimes 252237663Scharnier syslog(LOG_ERR, "out of memory"); 25231558Srgrimes exit(2); 25241558Srgrimes} 25251558Srgrimes 25261558Srgrimes/* 2527158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 25281558Srgrimes * the kernel. 25291558Srgrimes */ 2530285128Straszstatic int 2531158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2532158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 25331558Srgrimes{ 253475841Siedowse struct statfs fsb1; 253574462Salfred struct addrinfo *ai; 2536282214Strasz struct export_args *eap; 2537158857Srodrigc char errmsg[255]; 2538158857Srodrigc char *cp; 25391558Srgrimes int done; 2540158857Srodrigc char savedc; 2541158857Srodrigc struct iovec *iov; 2542184588Sdfr int i, iovlen; 2543158857Srodrigc int ret; 2544192934Srmacklem struct nfsex_args nfsea; 25451558Srgrimes 2546282214Strasz eap = &nfsea.export; 2547192934Srmacklem 2548158857Srodrigc cp = NULL; 2549158857Srodrigc savedc = '\0'; 2550158857Srodrigc iov = NULL; 2551158857Srodrigc iovlen = 0; 2552158857Srodrigc ret = 0; 255375801Siedowse 2554192934Srmacklem bzero(eap, sizeof (struct export_args)); 2555158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2556192934Srmacklem eap->ex_flags = exflags; 2557192934Srmacklem eap->ex_anon = *anoncrp; 2558192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 255975641Siedowse if (grp->gr_type == GT_HOST) 256074462Salfred ai = grp->gr_ptr.gt_addrinfo; 256175641Siedowse else 256275641Siedowse ai = NULL; 2563192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2564192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2565192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2566192934Srmacklem if (eap->ex_numsecflavors == 0) { 2567192934Srmacklem eap->ex_numsecflavors = 1; 2568192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2569184588Sdfr } 25701558Srgrimes done = FALSE; 2571158857Srodrigc 2572192934Srmacklem if (v4root_phase == 0) { 2573192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2574192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2575192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2576192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2577192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2578192934Srmacklem sizeof (struct export_args)); 2579192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2580192934Srmacklem } 2581158857Srodrigc 25821558Srgrimes while (!done) { 25831558Srgrimes switch (grp->gr_type) { 25841558Srgrimes case GT_HOST: 258575641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 258674462Salfred goto skip; 2587192934Srmacklem eap->ex_addr = ai->ai_addr; 2588192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2589192934Srmacklem eap->ex_masklen = 0; 25901558Srgrimes break; 25911558Srgrimes case GT_NET: 259275801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 259374462Salfred have_v6 == 0) 259474462Salfred goto skip; 2595192934Srmacklem eap->ex_addr = 259675801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2597192934Srmacklem eap->ex_addrlen = 2598158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2599192934Srmacklem eap->ex_mask = 260075801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2601192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 26021558Srgrimes break; 260375641Siedowse case GT_DEFAULT: 2604192934Srmacklem eap->ex_addr = NULL; 2605192934Srmacklem eap->ex_addrlen = 0; 2606192934Srmacklem eap->ex_mask = NULL; 2607192934Srmacklem eap->ex_masklen = 0; 260875641Siedowse break; 26097401Swpaul case GT_IGNORE: 2610158857Srodrigc ret = 0; 2611158857Srodrigc goto error_exit; 26127401Swpaul break; 26131558Srgrimes default: 261437663Scharnier syslog(LOG_ERR, "bad grouptype"); 26151558Srgrimes if (cp) 26161558Srgrimes *cp = savedc; 2617158857Srodrigc ret = 1; 2618158857Srodrigc goto error_exit; 2619298089Spfg } 26201558Srgrimes 26211558Srgrimes /* 2622192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 26231558Srgrimes */ 2624192934Srmacklem if (v4root_phase == 2) { 2625192934Srmacklem nfsea.fspec = v4root_dirpath; 2626282214Strasz if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2627192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2628192934Srmacklem return (2); 2629158857Srodrigc } 2630192934Srmacklem } else { 2631192934Srmacklem /* 2632192934Srmacklem * XXX: 2633192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2634192934Srmacklem * instead of looping back up the dirp to the mount 2635192934Srmacklem * point?? 2636192934Srmacklem * Also, needs to know how to export all types of local 2637192934Srmacklem * exportable filesystems and not just "ufs". 2638192934Srmacklem */ 2639192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2640192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2641192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2642192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2643192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2644192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2645270183Sbdrewery errmsg[0] = '\0'; 2646192934Srmacklem 2647192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2648192934Srmacklem if (cp) 2649192934Srmacklem *cp-- = savedc; 2650192934Srmacklem else 2651192934Srmacklem cp = dirp + dirplen - 1; 2652192934Srmacklem if (opt_flags & OP_QUIET) { 2653192934Srmacklem ret = 1; 2654192934Srmacklem goto error_exit; 2655192934Srmacklem } 2656192934Srmacklem if (errno == EPERM) { 2657192934Srmacklem if (debug) 2658239744Sdelphij warnx("can't change attributes for %s: %s", 2659239744Sdelphij dirp, errmsg); 2660192934Srmacklem syslog(LOG_ERR, 2661239744Sdelphij "can't change attributes for %s: %s", 2662239744Sdelphij dirp, errmsg); 2663192934Srmacklem ret = 1; 2664192934Srmacklem goto error_exit; 2665192934Srmacklem } 2666192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2667192934Srmacklem if (errno == EINVAL) 2668192934Srmacklem syslog(LOG_ERR, 2669100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2670192934Srmacklem dirp); 2671192934Srmacklem else 2672192934Srmacklem syslog(LOG_ERR, 2673192934Srmacklem "could not remount %s: %m", 2674192934Srmacklem dirp); 2675192934Srmacklem ret = 1; 2676192934Srmacklem goto error_exit; 2677192934Srmacklem } 2678192934Srmacklem /* back up over the last component */ 2679192934Srmacklem while (*cp == '/' && cp > dirp) 2680192934Srmacklem cp--; 2681192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2682192934Srmacklem cp--; 2683192934Srmacklem if (cp == dirp) { 2684192934Srmacklem if (debug) 2685192934Srmacklem warnx("mnt unsucc"); 2686192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2687192934Srmacklem dirp, errmsg); 2688192934Srmacklem ret = 1; 2689192934Srmacklem goto error_exit; 2690192934Srmacklem } 2691192934Srmacklem savedc = *cp; 2692192934Srmacklem *cp = '\0'; 2693192934Srmacklem /* 2694192934Srmacklem * Check that we're still on the same 2695192934Srmacklem * filesystem. 2696192934Srmacklem */ 2697192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2698192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2699192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2700192934Srmacklem *cp = savedc; 2701100336Sjoerg syslog(LOG_ERR, 2702192934Srmacklem "can't export %s %s", dirp, 2703192934Srmacklem errmsg); 2704192934Srmacklem ret = 1; 2705192934Srmacklem goto error_exit; 2706192934Srmacklem } 27071558Srgrimes } 27081558Srgrimes } 2709192934Srmacklem 2710192934Srmacklem /* 2711192934Srmacklem * For the experimental server: 2712192934Srmacklem * If this is the public directory, get the file handle 2713192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2714192934Srmacklem */ 2715282214Strasz if ((exflags & MNT_EXPUBLIC) != 0) { 2716192934Srmacklem fhandle_t fh; 2717192934Srmacklem char *public_name; 2718192934Srmacklem 2719192934Srmacklem if (eap->ex_indexfile != NULL) 2720192934Srmacklem public_name = eap->ex_indexfile; 2721192934Srmacklem else 2722192934Srmacklem public_name = dirp; 2723192934Srmacklem if (getfh(public_name, &fh) < 0) 2724192934Srmacklem syslog(LOG_ERR, 2725192934Srmacklem "Can't get public fh for %s", public_name); 2726192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2727192934Srmacklem syslog(LOG_ERR, 2728192934Srmacklem "Can't set public fh for %s", public_name); 2729192934Srmacklem else 2730192934Srmacklem has_publicfh = 1; 2731192934Srmacklem } 273274462Salfredskip: 273375641Siedowse if (ai != NULL) 273474462Salfred ai = ai->ai_next; 273575641Siedowse if (ai == NULL) 27361558Srgrimes done = TRUE; 27371558Srgrimes } 27381558Srgrimes if (cp) 27391558Srgrimes *cp = savedc; 2740158857Srodrigcerror_exit: 2741158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2742158857Srodrigc if (iov != NULL) { 2743158857Srodrigc free(iov[0].iov_base); /* fstype */ 2744158857Srodrigc free(iov[2].iov_base); /* fspath */ 2745158857Srodrigc free(iov[4].iov_base); /* from */ 2746158857Srodrigc free(iov[6].iov_base); /* update */ 2747158857Srodrigc free(iov[8].iov_base); /* export */ 2748158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2749158857Srodrigc 2750158857Srodrigc /* free iov, allocated by realloc() */ 2751158857Srodrigc free(iov); 2752158857Srodrigc } 2753158857Srodrigc return (ret); 27541558Srgrimes} 27551558Srgrimes 27561558Srgrimes/* 27571558Srgrimes * Translate a net address. 275875801Siedowse * 275975801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 27601558Srgrimes */ 2761285128Straszstatic int 2762216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg) 27631558Srgrimes{ 276475861Siedowse struct netent *np = NULL; 276574462Salfred char *name, *p, *prefp; 276675801Siedowse struct sockaddr_in sin; 276775861Siedowse struct sockaddr *sa = NULL; 276874462Salfred struct addrinfo hints, *ai = NULL; 276974462Salfred char netname[NI_MAXHOST]; 277074462Salfred long preflen; 27711558Srgrimes 277275635Siedowse p = prefp = NULL; 277374462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 277474462Salfred p = strchr(cp, '/'); 277574462Salfred *p = '\0'; 277674462Salfred prefp = p + 1; 277774462Salfred } 277874462Salfred 277975861Siedowse /* 278075861Siedowse * Check for a numeric address first. We wish to avoid 278175861Siedowse * possible DNS lookups in getnetbyname(). 278275861Siedowse */ 278375861Siedowse if (isxdigit(*cp) || *cp == ':') { 278474462Salfred memset(&hints, 0, sizeof hints); 278575801Siedowse /* Ensure the mask and the network have the same family. */ 278675801Siedowse if (maskflg && (opt_flags & OP_NET)) 278775801Siedowse hints.ai_family = net->nt_net.ss_family; 278875801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 278975801Siedowse hints.ai_family = net->nt_mask.ss_family; 279075801Siedowse else 279175801Siedowse hints.ai_family = AF_UNSPEC; 279274462Salfred hints.ai_flags = AI_NUMERICHOST; 279375861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 279475861Siedowse sa = ai->ai_addr; 279575861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 279674462Salfred /* 279775801Siedowse * The address in `cp' is really a network address, so 279875801Siedowse * use inet_network() to re-interpret this correctly. 279975801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 280074462Salfred */ 280175801Siedowse bzero(&sin, sizeof sin); 280274462Salfred sin.sin_family = AF_INET; 280374462Salfred sin.sin_len = sizeof sin; 280475801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 280574462Salfred if (debug) 280675801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 280775801Siedowse inet_ntoa(sin.sin_addr)); 280874462Salfred sa = (struct sockaddr *)&sin; 280975861Siedowse } 281075861Siedowse } 281175861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 281275861Siedowse bzero(&sin, sizeof sin); 281375861Siedowse sin.sin_family = AF_INET; 281475861Siedowse sin.sin_len = sizeof sin; 281575861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 281675861Siedowse sa = (struct sockaddr *)&sin; 281775861Siedowse } 281875861Siedowse if (sa == NULL) 281974462Salfred goto fail; 282025318Spst 282175801Siedowse if (maskflg) { 282275801Siedowse /* The specified sockaddr is a mask. */ 282375801Siedowse if (checkmask(sa) != 0) 282475801Siedowse goto fail; 282575801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 282675801Siedowse opt_flags |= OP_HAVEMASK; 282775801Siedowse } else { 282875801Siedowse /* The specified sockaddr is a network address. */ 282975801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 283074462Salfred 283175801Siedowse /* Get a network name for the export list. */ 283275801Siedowse if (np) { 283375801Siedowse name = np->n_name; 283475801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2835146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 283675801Siedowse name = netname; 283775801Siedowse } else { 283875801Siedowse goto fail; 283975801Siedowse } 284075801Siedowse if ((net->nt_name = strdup(name)) == NULL) 284175801Siedowse out_of_mem(); 284275801Siedowse 284375801Siedowse /* 284475801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 284575801Siedowse * from the class of an IPv4 address. 284675801Siedowse */ 284774462Salfred if (opt_flags & OP_MASKLEN) { 284874462Salfred preflen = strtol(prefp, NULL, 10); 284975801Siedowse if (preflen < 0L || preflen == LONG_MAX) 285074462Salfred goto fail; 285175801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 285275801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 285375801Siedowse goto fail; 285475801Siedowse opt_flags |= OP_HAVEMASK; 285574462Salfred *p = '/'; 285675801Siedowse } else if (sa->sa_family == AF_INET && 285775801Siedowse (opt_flags & OP_MASK) == 0) { 285875801Siedowse in_addr_t addr; 285974462Salfred 286075801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 286175801Siedowse if (IN_CLASSA(addr)) 286275801Siedowse preflen = 8; 286375801Siedowse else if (IN_CLASSB(addr)) 286475801Siedowse preflen = 16; 286575801Siedowse else if (IN_CLASSC(addr)) 286675801Siedowse preflen = 24; 286775801Siedowse else if (IN_CLASSD(addr)) 286875801Siedowse preflen = 28; 286975801Siedowse else 287075801Siedowse preflen = 32; /* XXX */ 287175801Siedowse 287275801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 287375801Siedowse makemask(&net->nt_mask, (int)preflen); 287475801Siedowse opt_flags |= OP_HAVEMASK; 287574462Salfred } 287674462Salfred } 287774462Salfred 287874462Salfred if (ai) 287974462Salfred freeaddrinfo(ai); 288074462Salfred return 0; 288174462Salfred 288274462Salfredfail: 288374462Salfred if (ai) 288474462Salfred freeaddrinfo(ai); 288574462Salfred return 1; 28861558Srgrimes} 28871558Srgrimes 28881558Srgrimes/* 28891558Srgrimes * Parse out the next white space separated field 28901558Srgrimes */ 2891285128Straszstatic void 2892216587Scharniernextfield(char **cp, char **endcp) 28931558Srgrimes{ 28941558Srgrimes char *p; 2895347341Smav char quot = 0; 28961558Srgrimes 28971558Srgrimes p = *cp; 28981558Srgrimes while (*p == ' ' || *p == '\t') 28991558Srgrimes p++; 2900347341Smav *cp = p; 2901347341Smav while (*p != '\0') { 2902347341Smav if (quot) { 2903347341Smav if (*p == quot) 2904347341Smav quot = 0; 2905347341Smav } else { 2906347341Smav if (*p == '\\' && *(p + 1) != '\0') 2907347341Smav p++; 2908347341Smav else if (*p == '\'' || *p == '"') 2909347341Smav quot = *p; 2910347341Smav else if (*p == ' ' || *p == '\t') 2911347341Smav break; 2912347341Smav } 2913347341Smav p++; 2914347341Smav }; 2915347341Smav *endcp = p; 29161558Srgrimes} 29171558Srgrimes 29181558Srgrimes/* 29191558Srgrimes * Get an exports file line. Skip over blank lines and handle line 29201558Srgrimes * continuations. 29211558Srgrimes */ 2922285128Straszstatic int 2923216587Scharnierget_line(void) 29241558Srgrimes{ 29251558Srgrimes char *p, *cp; 292696622Siedowse size_t len; 29271558Srgrimes int totlen, cont_line; 29281558Srgrimes 29291558Srgrimes /* 29301558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 29311558Srgrimes */ 29321558Srgrimes p = line; 29331558Srgrimes totlen = 0; 29341558Srgrimes do { 293596622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 29361558Srgrimes return (0); 29371558Srgrimes cp = p + len - 1; 29381558Srgrimes cont_line = 0; 29391558Srgrimes while (cp >= p && 29401558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 29411558Srgrimes if (*cp == '\\') 29421558Srgrimes cont_line = 1; 29431558Srgrimes cp--; 29441558Srgrimes len--; 29451558Srgrimes } 294679117Sdd if (cont_line) { 294779117Sdd *++cp = ' '; 294879117Sdd len++; 294979117Sdd } 295096622Siedowse if (linesize < len + totlen + 1) { 295196622Siedowse linesize = len + totlen + 1; 295296622Siedowse line = realloc(line, linesize); 295396622Siedowse if (line == NULL) 295496622Siedowse out_of_mem(); 29551558Srgrimes } 295696622Siedowse memcpy(line + totlen, p, len); 295796622Siedowse totlen += len; 295896622Siedowse line[totlen] = '\0'; 29591558Srgrimes } while (totlen == 0 || cont_line); 29601558Srgrimes return (1); 29611558Srgrimes} 29621558Srgrimes 29631558Srgrimes/* 29641558Srgrimes * Parse a description of a credential. 29651558Srgrimes */ 2966285128Straszstatic void 2967216587Scharnierparsecred(char *namelist, struct xucred *cr) 29681558Srgrimes{ 29691558Srgrimes char *name; 29701558Srgrimes int cnt; 29711558Srgrimes char *names; 29721558Srgrimes struct passwd *pw; 29731558Srgrimes struct group *gr; 2974194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2975136051Sstefanf int ngroups; 29761558Srgrimes 297791354Sdd cr->cr_version = XUCRED_VERSION; 29781558Srgrimes /* 297937663Scharnier * Set up the unprivileged user. 29801558Srgrimes */ 29811558Srgrimes cr->cr_uid = -2; 29821558Srgrimes cr->cr_groups[0] = -2; 29831558Srgrimes cr->cr_ngroups = 1; 29841558Srgrimes /* 29851558Srgrimes * Get the user's password table entry. 29861558Srgrimes */ 2987347341Smav names = namelist; 2988347341Smav name = strsep_quote(&names, ":"); 2989293305Sjpaetzel /* Bug? name could be NULL here */ 29901558Srgrimes if (isdigit(*name) || *name == '-') 29911558Srgrimes pw = getpwuid(atoi(name)); 29921558Srgrimes else 29931558Srgrimes pw = getpwnam(name); 29941558Srgrimes /* 29951558Srgrimes * Credentials specified as those of a user. 29961558Srgrimes */ 29971558Srgrimes if (names == NULL) { 29981558Srgrimes if (pw == NULL) { 299937663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 30001558Srgrimes return; 30011558Srgrimes } 30021558Srgrimes cr->cr_uid = pw->pw_uid; 3003194498Sbrooks ngroups = XU_NGROUPS + 1; 3004333197Savg if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { 300537663Scharnier syslog(LOG_ERR, "too many groups"); 3006333197Savg ngroups = XU_NGROUPS + 1; 3007333197Savg } 3008333197Savg 30091558Srgrimes /* 3010136051Sstefanf * Compress out duplicate. 30111558Srgrimes */ 30121558Srgrimes cr->cr_ngroups = ngroups - 1; 30131558Srgrimes cr->cr_groups[0] = groups[0]; 30141558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 30151558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 30161558Srgrimes return; 30171558Srgrimes } 30181558Srgrimes /* 30191558Srgrimes * Explicit credential specified as a colon separated list: 30201558Srgrimes * uid:gid:gid:... 30211558Srgrimes */ 30221558Srgrimes if (pw != NULL) 30231558Srgrimes cr->cr_uid = pw->pw_uid; 30241558Srgrimes else if (isdigit(*name) || *name == '-') 30251558Srgrimes cr->cr_uid = atoi(name); 30261558Srgrimes else { 302737663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 30281558Srgrimes return; 30291558Srgrimes } 30301558Srgrimes cr->cr_ngroups = 0; 3031194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 3032347341Smav name = strsep_quote(&names, ":"); 30331558Srgrimes if (isdigit(*name) || *name == '-') { 30341558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 30351558Srgrimes } else { 30361558Srgrimes if ((gr = getgrnam(name)) == NULL) { 303737663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 30381558Srgrimes continue; 30391558Srgrimes } 30401558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 30411558Srgrimes } 30421558Srgrimes } 3043194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 304437663Scharnier syslog(LOG_ERR, "too many groups"); 30451558Srgrimes} 30461558Srgrimes 3047194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 30481558Srgrimes/* 30491558Srgrimes * Routines that maintain the remote mounttab 30501558Srgrimes */ 3051285128Straszstatic void 3052216587Scharnierget_mountlist(void) 30531558Srgrimes{ 3054324955Smanu struct mountlist *mlp; 305523681Speter char *host, *dirp, *cp; 30561558Srgrimes char str[STRSIZ]; 30571558Srgrimes FILE *mlfile; 30581558Srgrimes 30591558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 306053117Sbillf if (errno == ENOENT) 306153117Sbillf return; 306253117Sbillf else { 306353117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 306453117Sbillf return; 306553117Sbillf } 30661558Srgrimes } 30671558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 306823681Speter cp = str; 306923681Speter host = strsep(&cp, " \t\n"); 307023681Speter dirp = strsep(&cp, " \t\n"); 307123681Speter if (host == NULL || dirp == NULL) 30721558Srgrimes continue; 30731558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 307437663Scharnier if (mlp == (struct mountlist *)NULL) 307537663Scharnier out_of_mem(); 3076194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 3077194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 3078194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 3079194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 3080324955Smanu 3081324955Smanu SLIST_INSERT_HEAD(&mlhead, mlp, next); 30821558Srgrimes } 30831558Srgrimes fclose(mlfile); 30841558Srgrimes} 30851558Srgrimes 3086285128Straszstatic void 308775635Siedowsedel_mlist(char *hostp, char *dirp) 30881558Srgrimes{ 3089324955Smanu struct mountlist *mlp, *mlp2; 30901558Srgrimes FILE *mlfile; 30911558Srgrimes int fnd = 0; 30921558Srgrimes 3093324955Smanu SLIST_FOREACH_SAFE(mlp, &mlhead, next, mlp2) { 30941558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 30951558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 30961558Srgrimes fnd = 1; 3097324955Smanu SLIST_REMOVE(&mlhead, mlp, mountlist, next); 3098324955Smanu free((caddr_t)mlp); 30991558Srgrimes } 31001558Srgrimes } 31011558Srgrimes if (fnd) { 31021558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 310337663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 31041558Srgrimes return; 31051558Srgrimes } 3106324955Smanu SLIST_FOREACH(mlp, &mlhead, next) { 31071558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 31081558Srgrimes } 31091558Srgrimes fclose(mlfile); 31101558Srgrimes } 31111558Srgrimes} 31121558Srgrimes 3113285128Straszstatic void 3114216587Scharnieradd_mlist(char *hostp, char *dirp) 31151558Srgrimes{ 3116324955Smanu struct mountlist *mlp; 31171558Srgrimes FILE *mlfile; 31181558Srgrimes 3119324955Smanu SLIST_FOREACH(mlp, &mlhead, next) { 31201558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 31211558Srgrimes return; 31221558Srgrimes } 3123324955Smanu 31241558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 312537663Scharnier if (mlp == (struct mountlist *)NULL) 312637663Scharnier out_of_mem(); 3127194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 3128194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 3129194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 3130194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 3131324955Smanu SLIST_INSERT_HEAD(&mlhead, mlp, next); 31321558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 313337663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 31341558Srgrimes return; 31351558Srgrimes } 31361558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 31371558Srgrimes fclose(mlfile); 31381558Srgrimes} 31391558Srgrimes 31401558Srgrimes/* 31411558Srgrimes * Free up a group list. 31421558Srgrimes */ 3143285128Straszstatic void 3144216587Scharnierfree_grp(struct grouplist *grp) 31451558Srgrimes{ 31461558Srgrimes if (grp->gr_type == GT_HOST) { 314774462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 314874462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 31491558Srgrimes } else if (grp->gr_type == GT_NET) { 31501558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 31511558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 31521558Srgrimes } 31531558Srgrimes free((caddr_t)grp); 31541558Srgrimes} 31551558Srgrimes 31561558Srgrimes#ifdef DEBUG 3157285128Straszstatic void 31581558SrgrimesSYSLOG(int pri, const char *fmt, ...) 31591558Srgrimes{ 31601558Srgrimes va_list ap; 31611558Srgrimes 31621558Srgrimes va_start(ap, fmt); 31631558Srgrimes vfprintf(stderr, fmt, ap); 31641558Srgrimes va_end(ap); 31651558Srgrimes} 31661558Srgrimes#endif /* DEBUG */ 31671558Srgrimes 31681558Srgrimes/* 31691558Srgrimes * Check options for consistency. 31701558Srgrimes */ 3171285128Straszstatic int 3172216587Scharniercheck_options(struct dirlist *dp) 31731558Srgrimes{ 31741558Srgrimes 3175192934Srmacklem if (v4root_phase == 0 && dp == NULL) 31761558Srgrimes return (1); 317783653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 317883653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 31791558Srgrimes return (1); 31801558Srgrimes } 31811558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 318275801Siedowse syslog(LOG_ERR, "-mask requires -network"); 318375801Siedowse return (1); 31841558Srgrimes } 318575801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 318675801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 318775801Siedowse return (1); 318875801Siedowse } 318975801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 319075801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 319175801Siedowse return (1); 319275801Siedowse } 3193192934Srmacklem if (v4root_phase > 0 && 3194192934Srmacklem (opt_flags & 3195192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3196192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3197192934Srmacklem return (1); 3198192934Srmacklem } 3199207689Srmacklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 3200207689Srmacklem syslog(LOG_ERR, "-alldirs has multiple directories"); 3201207689Srmacklem return (1); 3202207689Srmacklem } 32031558Srgrimes return (0); 32041558Srgrimes} 32051558Srgrimes 32061558Srgrimes/* 32071558Srgrimes * Check an absolute directory path for any symbolic links. Return true 32081558Srgrimes */ 3209285128Straszstatic int 3210216587Scharniercheck_dirpath(char *dirp) 32111558Srgrimes{ 32121558Srgrimes char *cp; 32131558Srgrimes int ret = 1; 32141558Srgrimes struct stat sb; 32151558Srgrimes 32161558Srgrimes cp = dirp + 1; 32171558Srgrimes while (*cp && ret) { 32181558Srgrimes if (*cp == '/') { 32191558Srgrimes *cp = '\0'; 32209336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 32211558Srgrimes ret = 0; 32221558Srgrimes *cp = '/'; 32231558Srgrimes } 32241558Srgrimes cp++; 32251558Srgrimes } 32269336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 32271558Srgrimes ret = 0; 32281558Srgrimes return (ret); 32291558Srgrimes} 32309336Sdfr 323175801Siedowse/* 323275801Siedowse * Make a netmask according to the specified prefix length. The ss_family 323375801Siedowse * and other non-address fields must be initialised before calling this. 323475801Siedowse */ 3235285128Straszstatic int 323675801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 323774462Salfred{ 323875801Siedowse u_char *p; 323975801Siedowse int bits, i, len; 324074462Salfred 324175801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 324275801Siedowse return (-1); 3243103949Smike if (bitlen > len * CHAR_BIT) 324475801Siedowse return (-1); 324574462Salfred 324675801Siedowse for (i = 0; i < len; i++) { 3247298912Saraujo bits = MIN(CHAR_BIT, bitlen); 3248219125Sru *p++ = (u_char)~0 << (CHAR_BIT - bits); 324975801Siedowse bitlen -= bits; 325074462Salfred } 325175801Siedowse return 0; 325274462Salfred} 325374462Salfred 325475801Siedowse/* 325575801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 325675801Siedowse * is acceptable (i.e. of the form 1...10....0). 325775801Siedowse */ 3258285128Straszstatic int 325975801Siedowsecheckmask(struct sockaddr *sa) 326074462Salfred{ 326175801Siedowse u_char *mask; 326275801Siedowse int i, len; 326374462Salfred 326475801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 326575801Siedowse return (-1); 326675801Siedowse 326775801Siedowse for (i = 0; i < len; i++) 326875801Siedowse if (mask[i] != 0xff) 326975801Siedowse break; 327075801Siedowse if (i < len) { 327175801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 327275801Siedowse return (-1); 327375801Siedowse i++; 327474462Salfred } 327575801Siedowse for (; i < len; i++) 327675801Siedowse if (mask[i] != 0) 327775801Siedowse return (-1); 327875801Siedowse return (0); 327974462Salfred} 328074462Salfred 328175801Siedowse/* 328275801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 328375801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 3284228990Suqs * If samask is NULL, perform a full comparison. 328575801Siedowse */ 3286285128Straszstatic int 328775801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 328874462Salfred{ 328975801Siedowse unsigned char *p1, *p2, *mask; 329075801Siedowse int len, i; 329174462Salfred 329275801Siedowse if (sa1->sa_family != sa2->sa_family || 329375801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 329475801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 329575801Siedowse return (1); 329675801Siedowse 329775801Siedowse switch (sa1->sa_family) { 329874462Salfred case AF_INET6: 329975801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 330075801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 330175801Siedowse return (1); 330274462Salfred break; 330374462Salfred } 330474462Salfred 330575801Siedowse /* Simple binary comparison if no mask specified. */ 330675801Siedowse if (samask == NULL) 330775801Siedowse return (memcmp(p1, p2, len)); 330874462Salfred 330975801Siedowse /* Set up the mask, and do a mask-based comparison. */ 331075801Siedowse if (sa1->sa_family != samask->sa_family || 331175801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 331275801Siedowse return (1); 331374462Salfred 331475801Siedowse for (i = 0; i < len; i++) 331575801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 331675801Siedowse return (1); 331775801Siedowse return (0); 331874462Salfred} 331974462Salfred 332075801Siedowse/* 332175801Siedowse * Return a pointer to the part of the sockaddr that contains the 332275801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 332375801Siedowse * NULL if the address family is unknown. 332475801Siedowse */ 3325285128Straszstatic void * 332675801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 332775801Siedowse void *p; 332874462Salfred int len; 332974462Salfred 333075801Siedowse switch (sa->sa_family) { 333174462Salfred case AF_INET: 333275801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 333375801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 333474462Salfred break; 333574462Salfred case AF_INET6: 333675801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 333775801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 333874462Salfred break; 333974462Salfred default: 334075801Siedowse p = NULL; 334175801Siedowse len = 0; 334274462Salfred } 334374462Salfred 334475801Siedowse if (nbytes != NULL) 334575801Siedowse *nbytes = len; 334675801Siedowse return (p); 334774462Salfred} 334874462Salfred 3349285128Straszstatic void 3350216587Scharnierhuphandler(int sig __unused) 335175754Siedowse{ 3352285128Strasz 335375754Siedowse got_sighup = 1; 335475754Siedowse} 335575754Siedowse 3356285128Straszstatic void 3357285128Straszterminate(int sig __unused) 335874462Salfred{ 3359149433Spjd pidfile_remove(pfh); 3360194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3361194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 336274462Salfred exit (0); 336374462Salfred} 3364