mountd.c revision 298912
11558Srgrimes/* 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: head/usr.sbin/mountd/mountd.c 298912 2016-05-02 01:49:42Z araujo $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 49192934Srmacklem#include <sys/fcntl.h> 50192934Srmacklem#include <sys/linker.h> 51192934Srmacklem#include <sys/module.h> 521558Srgrimes#include <sys/mount.h> 531558Srgrimes#include <sys/stat.h> 54192934Srmacklem#include <sys/sysctl.h> 551558Srgrimes#include <sys/syslog.h> 561558Srgrimes 571558Srgrimes#include <rpc/rpc.h> 58109363Smbr#include <rpc/rpc_com.h> 591558Srgrimes#include <rpc/pmap_clnt.h> 6074462Salfred#include <rpc/pmap_prot.h> 6174462Salfred#include <rpcsvc/mount.h> 629336Sdfr#include <nfs/nfsproto.h> 63192934Srmacklem#include <nfs/nfssvc.h> 6483653Speter#include <nfsserver/nfs.h> 651558Srgrimes 66192934Srmacklem#include <fs/nfs/nfsport.h> 67192934Srmacklem 681558Srgrimes#include <arpa/inet.h> 691558Srgrimes 701558Srgrimes#include <ctype.h> 7137663Scharnier#include <err.h> 721558Srgrimes#include <errno.h> 731558Srgrimes#include <grp.h> 74149433Spjd#include <libutil.h> 75103949Smike#include <limits.h> 761558Srgrimes#include <netdb.h> 771558Srgrimes#include <pwd.h> 781558Srgrimes#include <signal.h> 791558Srgrimes#include <stdio.h> 801558Srgrimes#include <stdlib.h> 811558Srgrimes#include <string.h> 821558Srgrimes#include <unistd.h> 831558Srgrimes#include "pathnames.h" 84158857Srodrigc#include "mntopts.h" 851558Srgrimes 861558Srgrimes#ifdef DEBUG 871558Srgrimes#include <stdarg.h> 881558Srgrimes#endif 891558Srgrimes 901558Srgrimes/* 911558Srgrimes * Structures for keeping the mount list and export list 921558Srgrimes */ 931558Srgrimesstruct mountlist { 941558Srgrimes struct mountlist *ml_next; 95194880Sdfr char ml_host[MNTNAMLEN+1]; 96194880Sdfr char ml_dirp[MNTPATHLEN+1]; 971558Srgrimes}; 981558Srgrimes 991558Srgrimesstruct dirlist { 1001558Srgrimes struct dirlist *dp_left; 1011558Srgrimes struct dirlist *dp_right; 1021558Srgrimes int dp_flag; 1031558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1041558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1051558Srgrimes}; 1061558Srgrimes/* dp_flag bits */ 1071558Srgrimes#define DP_DEFSET 0x1 1089336Sdfr#define DP_HOSTSET 0x2 1091558Srgrimes 1101558Srgrimesstruct exportlist { 1111558Srgrimes struct exportlist *ex_next; 1121558Srgrimes struct dirlist *ex_dirl; 1131558Srgrimes struct dirlist *ex_defdir; 1141558Srgrimes int ex_flag; 1151558Srgrimes fsid_t ex_fs; 1161558Srgrimes char *ex_fsdir; 11727447Sdfr char *ex_indexfile; 118184588Sdfr int ex_numsecflavors; 119184588Sdfr int ex_secflavors[MAXSECFLAVORS]; 120240902Srmacklem int ex_defnumsecflavors; 121240902Srmacklem int ex_defsecflavors[MAXSECFLAVORS]; 1221558Srgrimes}; 1231558Srgrimes/* ex_flag bits */ 1241558Srgrimes#define EX_LINKED 0x1 1251558Srgrimes 1261558Srgrimesstruct netmsk { 12774462Salfred struct sockaddr_storage nt_net; 12875801Siedowse struct sockaddr_storage nt_mask; 12942144Sdfr char *nt_name; 1301558Srgrimes}; 1311558Srgrimes 1321558Srgrimesunion grouptypes { 13374462Salfred struct addrinfo *gt_addrinfo; 1341558Srgrimes struct netmsk gt_net; 1351558Srgrimes}; 1361558Srgrimes 1371558Srgrimesstruct grouplist { 1381558Srgrimes int gr_type; 1391558Srgrimes union grouptypes gr_ptr; 1401558Srgrimes struct grouplist *gr_next; 141240902Srmacklem int gr_numsecflavors; 142240902Srmacklem int gr_secflavors[MAXSECFLAVORS]; 1431558Srgrimes}; 1441558Srgrimes/* Group types */ 1451558Srgrimes#define GT_NULL 0x0 1461558Srgrimes#define GT_HOST 0x1 1471558Srgrimes#define GT_NET 0x2 14875641Siedowse#define GT_DEFAULT 0x3 1497401Swpaul#define GT_IGNORE 0x5 1501558Srgrimes 1511558Srgrimesstruct hostlist { 1529336Sdfr int ht_flag; /* Uses DP_xx bits */ 1531558Srgrimes struct grouplist *ht_grp; 1541558Srgrimes struct hostlist *ht_next; 1551558Srgrimes}; 1561558Srgrimes 1579336Sdfrstruct fhreturn { 1589336Sdfr int fhr_flag; 1599336Sdfr int fhr_vers; 1609336Sdfr nfsfh_t fhr_fh; 161184588Sdfr int fhr_numsecflavors; 162184588Sdfr int *fhr_secflavors; 1639336Sdfr}; 1649336Sdfr 165222623Srmacklem#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 166222623Srmacklem 1671558Srgrimes/* Global defs */ 168285128Straszstatic char *add_expdir(struct dirlist **, char *, int); 169285128Straszstatic void add_dlist(struct dirlist **, struct dirlist *, 170285128Strasz struct grouplist *, int, struct exportlist *); 171285128Straszstatic void add_mlist(char *, char *); 172285128Straszstatic int check_dirpath(char *); 173285128Straszstatic int check_options(struct dirlist *); 174285128Straszstatic int checkmask(struct sockaddr *sa); 175285128Straszstatic int chk_host(struct dirlist *, struct sockaddr *, int *, int *, 176285128Strasz int *, int **); 177293305Sjpaetzelstatic char *strsep_quote(char **stringp, const char *delim); 178222623Srmacklemstatic int create_service(struct netconfig *nconf); 179222623Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 180222623Srmacklemstatic void clearout_service(void); 181285128Straszstatic void del_mlist(char *hostp, char *dirp); 182285128Straszstatic struct dirlist *dirp_search(struct dirlist *, char *); 183285128Straszstatic int do_mount(struct exportlist *, struct grouplist *, int, 184285128Strasz struct xucred *, char *, int, struct statfs *); 185285128Straszstatic int do_opt(char **, char **, struct exportlist *, 186285128Strasz struct grouplist *, int *, int *, struct xucred *); 187285128Straszstatic struct exportlist *ex_search(fsid_t *); 188285128Straszstatic struct exportlist *get_exp(void); 189285128Straszstatic void free_dir(struct dirlist *); 190285128Straszstatic void free_exp(struct exportlist *); 191285128Straszstatic void free_grp(struct grouplist *); 192285128Straszstatic void free_host(struct hostlist *); 193285128Straszstatic void get_exportlist(void); 194285128Straszstatic int get_host(char *, struct grouplist *, struct grouplist *); 195285128Straszstatic struct hostlist *get_ht(void); 196285128Straszstatic int get_line(void); 197285128Straszstatic void get_mountlist(void); 198285128Straszstatic int get_net(char *, struct netmsk *, int); 199285128Straszstatic void getexp_err(struct exportlist *, struct grouplist *); 200285128Straszstatic struct grouplist *get_grp(void); 201285128Straszstatic void hang_dirp(struct dirlist *, struct grouplist *, 20292882Simp struct exportlist *, int); 203285128Straszstatic void huphandler(int sig); 204285128Straszstatic int makemask(struct sockaddr_storage *ssp, int bitlen); 205285128Straszstatic void mntsrv(struct svc_req *, SVCXPRT *); 206285128Straszstatic void nextfield(char **, char **); 207285128Straszstatic void out_of_mem(void); 208285128Straszstatic void parsecred(char *, struct xucred *); 209285128Straszstatic int parsesec(char *, struct exportlist *); 210285128Straszstatic int put_exlist(struct dirlist *, XDR *, struct dirlist *, 211285128Strasz int *, int); 212285128Straszstatic void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 213285128Straszstatic int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 214285128Strasz struct sockaddr *samask); 215285128Straszstatic int scan_tree(struct dirlist *, struct sockaddr *); 216285128Straszstatic void usage(void); 217285128Straszstatic int xdr_dir(XDR *, char *); 218285128Straszstatic int xdr_explist(XDR *, caddr_t); 219285128Straszstatic int xdr_explist_brief(XDR *, caddr_t); 220285128Straszstatic int xdr_explist_common(XDR *, caddr_t, int); 221285128Straszstatic int xdr_fhs(XDR *, caddr_t); 222285128Straszstatic int xdr_mlist(XDR *, caddr_t); 223285128Straszstatic void terminate(int); 2241558Srgrimes 225285128Straszstatic struct exportlist *exphead; 226285128Straszstatic struct mountlist *mlhead; 227285128Straszstatic struct grouplist *grphead; 228285128Straszstatic char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 229285128Straszstatic char **exnames; 230285128Straszstatic char **hosts = NULL; 231285128Straszstatic struct xucred def_anon = { 23291354Sdd XUCRED_VERSION, 23372650Sgreen (uid_t)-2, 2341558Srgrimes 1, 23572650Sgreen { (gid_t)-2 }, 23672650Sgreen NULL 2371558Srgrimes}; 238285128Straszstatic int force_v2 = 0; 239285128Straszstatic int resvport_only = 1; 240285128Straszstatic int nhosts = 0; 241285128Straszstatic int dir_only = 1; 242285128Straszstatic int dolog = 0; 243285128Straszstatic int got_sighup = 0; 244285128Straszstatic int xcreated = 0; 24574462Salfred 246285128Straszstatic char *svcport_str = NULL; 247285128Straszstatic int mallocd_svcport = 0; 248285128Straszstatic int *sock_fd; 249285128Straszstatic int sock_fdcnt; 250285128Straszstatic int sock_fdpos; 251285128Straszstatic int suspend_nfsd = 0; 252172827Smatteo 253285128Straszstatic int opt_flags; 25474462Salfredstatic int have_v6 = 1; 25574462Salfred 256285128Straszstatic int v4root_phase = 0; 257285128Straszstatic char v4root_dirpath[PATH_MAX + 1]; 258285128Straszstatic int has_publicfh = 0; 259192934Srmacklem 260285128Straszstatic struct pidfh *pfh = NULL; 26175801Siedowse/* Bits for opt_flags above */ 2621558Srgrimes#define OP_MAPROOT 0x01 2631558Srgrimes#define OP_MAPALL 0x02 26483653Speter/* 0x4 free */ 2651558Srgrimes#define OP_MASK 0x08 2661558Srgrimes#define OP_NET 0x10 2671558Srgrimes#define OP_ALLDIRS 0x40 26875801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 269100336Sjoerg#define OP_QUIET 0x100 27074462Salfred#define OP_MASKLEN 0x200 271184588Sdfr#define OP_SEC 0x400 2721558Srgrimes 2731558Srgrimes#ifdef DEBUG 274285128Straszstatic int debug = 1; 275285128Straszstatic void SYSLOG(int, const char *, ...) __printflike(2, 3); 2761558Srgrimes#define syslog SYSLOG 2771558Srgrimes#else 278285128Straszstatic int debug = 0; 2791558Srgrimes#endif 2801558Srgrimes 2811558Srgrimes/* 282293305Sjpaetzel * Similar to strsep(), but it allows for quoted strings 283293305Sjpaetzel * and escaped characters. 284293305Sjpaetzel * 285293305Sjpaetzel * It returns the string (or NULL, if *stringp is NULL), 286293305Sjpaetzel * which is a de-quoted version of the string if necessary. 287293305Sjpaetzel * 288293305Sjpaetzel * It modifies *stringp in place. 289293305Sjpaetzel */ 290293305Sjpaetzelstatic char * 291293305Sjpaetzelstrsep_quote(char **stringp, const char *delim) 292293305Sjpaetzel{ 293293305Sjpaetzel char *srcptr, *dstptr, *retval; 294293305Sjpaetzel char quot = 0; 295293305Sjpaetzel 296293305Sjpaetzel if (stringp == NULL || *stringp == NULL) 297293305Sjpaetzel return (NULL); 298293305Sjpaetzel 299293305Sjpaetzel srcptr = dstptr = retval = *stringp; 300293305Sjpaetzel 301293305Sjpaetzel while (*srcptr) { 302293305Sjpaetzel /* 303293305Sjpaetzel * We're looking for several edge cases here. 304293305Sjpaetzel * First: if we're in quote state (quot != 0), 305293305Sjpaetzel * then we ignore the delim characters, but otherwise 306293305Sjpaetzel * process as normal, unless it is the quote character. 307293305Sjpaetzel * Second: if the current character is a backslash, 308293305Sjpaetzel * we take the next character as-is, without checking 309293305Sjpaetzel * for delim, quote, or backslash. Exception: if the 310293305Sjpaetzel * next character is a NUL, that's the end of the string. 311293305Sjpaetzel * Third: if the character is a quote character, we toggle 312293305Sjpaetzel * quote state. 313293305Sjpaetzel * Otherwise: check the current character for NUL, or 314293305Sjpaetzel * being in delim, and end the string if either is true. 315293305Sjpaetzel */ 316293305Sjpaetzel if (*srcptr == '\\') { 317293305Sjpaetzel srcptr++; 318293305Sjpaetzel /* 319293305Sjpaetzel * The edge case here is if the next character 320293305Sjpaetzel * is NUL, we want to stop processing. But if 321293305Sjpaetzel * it's not NUL, then we simply want to copy it. 322293305Sjpaetzel */ 323293305Sjpaetzel if (*srcptr) { 324293305Sjpaetzel *dstptr++ = *srcptr++; 325293305Sjpaetzel } 326293305Sjpaetzel continue; 327293305Sjpaetzel } 328293305Sjpaetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 329293305Sjpaetzel quot = *srcptr++; 330293305Sjpaetzel continue; 331293305Sjpaetzel } 332293305Sjpaetzel if (quot && *srcptr == quot) { 333293305Sjpaetzel /* End of the quoted part */ 334293305Sjpaetzel quot = 0; 335293305Sjpaetzel srcptr++; 336293305Sjpaetzel continue; 337293305Sjpaetzel } 338293305Sjpaetzel if (!quot && strchr(delim, *srcptr)) 339293305Sjpaetzel break; 340293305Sjpaetzel *dstptr++ = *srcptr++; 341293305Sjpaetzel } 342293305Sjpaetzel 343293305Sjpaetzel *dstptr = 0; /* Terminate the string */ 344293305Sjpaetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 345293305Sjpaetzel return (retval); 346293305Sjpaetzel} 347293305Sjpaetzel 348293305Sjpaetzel/* 3491558Srgrimes * Mountd server for NFS mount protocol as described in: 3501558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 3511558Srgrimes * The optional arguments are the exports file name 3521558Srgrimes * default: _PATH_EXPORTS 3531558Srgrimes * and "-n" to allow nonroot mount. 3541558Srgrimes */ 3551558Srgrimesint 356216587Scharniermain(int argc, char **argv) 3571558Srgrimes{ 35875754Siedowse fd_set readfds; 359172827Smatteo struct netconfig *nconf; 360172827Smatteo char *endptr, **hosts_bak; 361172827Smatteo void *nc_handle; 362149433Spjd pid_t otherpid; 363172827Smatteo in_port_t svcport; 364172827Smatteo int c, k, s; 365109363Smbr int maxrec = RPC_MAXDATASIZE; 366222623Srmacklem int attempt_cnt, port_len, port_pos, ret; 367222623Srmacklem char **port_list; 3681558Srgrimes 36974462Salfred /* Check that another mountd isn't already running. */ 370150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 371149433Spjd if (pfh == NULL) { 372149433Spjd if (errno == EEXIST) 373149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 374149433Spjd warn("cannot open or create pidfile"); 375149433Spjd } 37674462Salfred 37774462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 37874462Salfred if (s < 0) 37974462Salfred have_v6 = 0; 38074462Salfred else 38174462Salfred close(s); 3822999Swollman 383282214Strasz while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) 3841558Srgrimes switch (c) { 38525087Sdfr case '2': 38625087Sdfr force_v2 = 1; 38725087Sdfr break; 388192993Srmacklem case 'e': 389220980Srmacklem /* now a no-op, since this is the default */ 390192934Srmacklem break; 3919336Sdfr case 'n': 3929336Sdfr resvport_only = 0; 3939336Sdfr break; 3949336Sdfr case 'r': 3959336Sdfr dir_only = 0; 3969336Sdfr break; 3978688Sphk case 'd': 3988688Sphk debug = debug ? 0 : 1; 3998688Sphk break; 40031656Sguido case 'l': 401121767Speter dolog = 1; 40231656Sguido break; 403126572Sbms case 'p': 404126572Sbms endptr = NULL; 405126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 406126572Sbms if (endptr == NULL || *endptr != '\0' || 407126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 408126572Sbms usage(); 409172827Smatteo svcport_str = strdup(optarg); 410126572Sbms break; 411172827Smatteo case 'h': 412172827Smatteo ++nhosts; 413172827Smatteo hosts_bak = hosts; 414172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 415172827Smatteo if (hosts_bak == NULL) { 416172827Smatteo if (hosts != NULL) { 417172827Smatteo for (k = 0; k < nhosts; k++) 418172827Smatteo free(hosts[k]); 419172827Smatteo free(hosts); 420172827Smatteo out_of_mem(); 421172827Smatteo } 422172827Smatteo } 423172827Smatteo hosts = hosts_bak; 424172827Smatteo hosts[nhosts - 1] = strdup(optarg); 425172827Smatteo if (hosts[nhosts - 1] == NULL) { 426172827Smatteo for (k = 0; k < (nhosts - 1); k++) 427172827Smatteo free(hosts[k]); 428172827Smatteo free(hosts); 429172827Smatteo out_of_mem(); 430172827Smatteo } 431172827Smatteo break; 432241568Srmacklem case 'S': 433241568Srmacklem suspend_nfsd = 1; 434241568Srmacklem break; 4351558Srgrimes default: 43637663Scharnier usage(); 437298089Spfg } 438192934Srmacklem 439282214Strasz if (modfind("nfsd") < 0) { 440192934Srmacklem /* Not present in kernel, try loading it */ 441282214Strasz if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 442192934Srmacklem errx(1, "NFS server is not available"); 443192934Srmacklem } 444192934Srmacklem 4451558Srgrimes argc -= optind; 4461558Srgrimes argv += optind; 4471558Srgrimes grphead = (struct grouplist *)NULL; 4481558Srgrimes exphead = (struct exportlist *)NULL; 4491558Srgrimes mlhead = (struct mountlist *)NULL; 450166440Spjd if (argc > 0) 451166440Spjd exnames = argv; 452166440Spjd else 453166440Spjd exnames = exnames_default; 4541558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 4551558Srgrimes if (debug) 45637663Scharnier warnx("getting export list"); 4571558Srgrimes get_exportlist(); 4581558Srgrimes if (debug) 45937663Scharnier warnx("getting mount list"); 4601558Srgrimes get_mountlist(); 4611558Srgrimes if (debug) 46237663Scharnier warnx("here we go"); 4631558Srgrimes if (debug == 0) { 4641558Srgrimes daemon(0, 0); 4651558Srgrimes signal(SIGINT, SIG_IGN); 4661558Srgrimes signal(SIGQUIT, SIG_IGN); 4671558Srgrimes } 46875754Siedowse signal(SIGHUP, huphandler); 46974462Salfred signal(SIGTERM, terminate); 470164394Srodrigc signal(SIGPIPE, SIG_IGN); 471149433Spjd 472149433Spjd pidfile_write(pfh); 473149433Spjd 474194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 475194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 476109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 477109363Smbr 47824759Sguido if (!resvport_only) { 47983687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 48083687Speter &resvport_only, sizeof(resvport_only)) != 0 && 48183687Speter errno != ENOENT) { 48224759Sguido syslog(LOG_ERR, "sysctl: %m"); 48324759Sguido exit(1); 48424759Sguido } 48524330Sguido } 486126572Sbms 487172827Smatteo /* 488172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 489172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 490172827Smatteo * list. 491172827Smatteo */ 492172827Smatteo if (nhosts == 0) { 493292864Suqs hosts = malloc(sizeof(char *)); 494172827Smatteo if (hosts == NULL) 495172827Smatteo out_of_mem(); 496172827Smatteo hosts[0] = "*"; 497172827Smatteo nhosts = 1; 498172827Smatteo } else { 499172827Smatteo hosts_bak = hosts; 500172827Smatteo if (have_v6) { 501172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 502172827Smatteo sizeof(char *)); 503172827Smatteo if (hosts_bak == NULL) { 504172827Smatteo for (k = 0; k < nhosts; k++) 505172827Smatteo free(hosts[k]); 506172827Smatteo free(hosts); 507172827Smatteo out_of_mem(); 508172827Smatteo } else 509172827Smatteo hosts = hosts_bak; 510172827Smatteo nhosts += 2; 511172827Smatteo hosts[nhosts - 2] = "::1"; 512172827Smatteo } else { 513172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 514172827Smatteo if (hosts_bak == NULL) { 515172827Smatteo for (k = 0; k < nhosts; k++) 516172827Smatteo free(hosts[k]); 517172827Smatteo free(hosts); 518172827Smatteo out_of_mem(); 519172827Smatteo } else { 520172827Smatteo nhosts += 1; 521172827Smatteo hosts = hosts_bak; 522126572Sbms } 523172827Smatteo } 52474462Salfred 525172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 52674462Salfred } 52774462Salfred 528222623Srmacklem attempt_cnt = 1; 529222623Srmacklem sock_fdcnt = 0; 530222623Srmacklem sock_fd = NULL; 531222623Srmacklem port_list = NULL; 532222623Srmacklem port_len = 0; 533172827Smatteo nc_handle = setnetconfig(); 534172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 535172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 536172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 537172827Smatteo "inet6") == 0) { 538172827Smatteo /* DO NOTHING */ 539222623Srmacklem } else { 540222623Srmacklem ret = create_service(nconf); 541222623Srmacklem if (ret == 1) 542222623Srmacklem /* Ignore this call */ 543222623Srmacklem continue; 544222623Srmacklem if (ret < 0) { 545222623Srmacklem /* 546222623Srmacklem * Failed to bind port, so close off 547222623Srmacklem * all sockets created and try again 548222623Srmacklem * if the port# was dynamically 549222623Srmacklem * assigned via bind(2). 550222623Srmacklem */ 551222623Srmacklem clearout_service(); 552222623Srmacklem if (mallocd_svcport != 0 && 553222623Srmacklem attempt_cnt < GETPORT_MAXTRY) { 554222623Srmacklem free(svcport_str); 555222623Srmacklem svcport_str = NULL; 556222623Srmacklem mallocd_svcport = 0; 557222623Srmacklem } else { 558222623Srmacklem errno = EADDRINUSE; 559222623Srmacklem syslog(LOG_ERR, 560222623Srmacklem "bindresvport_sa: %m"); 561222623Srmacklem exit(1); 562222623Srmacklem } 563222623Srmacklem 564222623Srmacklem /* Start over at the first service. */ 565222623Srmacklem free(sock_fd); 566222623Srmacklem sock_fdcnt = 0; 567222623Srmacklem sock_fd = NULL; 568222623Srmacklem nc_handle = setnetconfig(); 569222623Srmacklem attempt_cnt++; 570222623Srmacklem } else if (mallocd_svcport != 0 && 571222623Srmacklem attempt_cnt == GETPORT_MAXTRY) { 572222623Srmacklem /* 573222623Srmacklem * For the last attempt, allow 574222623Srmacklem * different port #s for each nconf 575222623Srmacklem * by saving the svcport_str and 576222623Srmacklem * setting it back to NULL. 577222623Srmacklem */ 578222623Srmacklem port_list = realloc(port_list, 579222623Srmacklem (port_len + 1) * sizeof(char *)); 580222623Srmacklem if (port_list == NULL) 581222623Srmacklem out_of_mem(); 582222623Srmacklem port_list[port_len++] = svcport_str; 583222623Srmacklem svcport_str = NULL; 584222623Srmacklem mallocd_svcport = 0; 585222623Srmacklem } 586222623Srmacklem } 587222623Srmacklem } 588222623Srmacklem } 589222623Srmacklem 590222623Srmacklem /* 591222623Srmacklem * Successfully bound the ports, so call complete_service() to 592222623Srmacklem * do the rest of the setup on the service(s). 593222623Srmacklem */ 594222623Srmacklem sock_fdpos = 0; 595222623Srmacklem port_pos = 0; 596222623Srmacklem nc_handle = setnetconfig(); 597222623Srmacklem while ((nconf = getnetconfig(nc_handle))) { 598222623Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 599222623Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 600222623Srmacklem "inet6") == 0) { 601222623Srmacklem /* DO NOTHING */ 602222623Srmacklem } else if (port_list != NULL) { 603222623Srmacklem if (port_pos >= port_len) { 604222623Srmacklem syslog(LOG_ERR, "too many port#s"); 605222623Srmacklem exit(1); 606222623Srmacklem } 607222623Srmacklem complete_service(nconf, port_list[port_pos++]); 608172827Smatteo } else 609222623Srmacklem complete_service(nconf, svcport_str); 610172827Smatteo } 61174462Salfred } 612172827Smatteo endnetconfig(nc_handle); 613222623Srmacklem free(sock_fd); 614222623Srmacklem if (port_list != NULL) { 615222623Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 616222623Srmacklem free(port_list[port_pos]); 617222623Srmacklem free(port_list); 618222623Srmacklem } 61974462Salfred 62074462Salfred if (xcreated == 0) { 62174462Salfred syslog(LOG_ERR, "could not create any services"); 6221558Srgrimes exit(1); 6231558Srgrimes } 62475754Siedowse 62575754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 62675754Siedowse for (;;) { 62775754Siedowse if (got_sighup) { 62875754Siedowse get_exportlist(); 62975754Siedowse got_sighup = 0; 63075754Siedowse } 63175754Siedowse readfds = svc_fdset; 63275754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 63375754Siedowse case -1: 63475754Siedowse if (errno == EINTR) 63575754Siedowse continue; 63675754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 63775754Siedowse exit(1); 63875754Siedowse case 0: 63975754Siedowse continue; 64075754Siedowse default: 64175754Siedowse svc_getreqset(&readfds); 64275754Siedowse } 64375754Siedowse } 644172827Smatteo} 645172827Smatteo 646172827Smatteo/* 647172827Smatteo * This routine creates and binds sockets on the appropriate 648222623Srmacklem * addresses. It gets called one time for each transport. 649222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 650222623Srmacklem * bind failed with EADDRINUSE. 651222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and 652222623Srmacklem * the total count of them is maintained in sock_fdcnt. 653172827Smatteo */ 654222623Srmacklemstatic int 655172827Smatteocreate_service(struct netconfig *nconf) 656172827Smatteo{ 657172827Smatteo struct addrinfo hints, *res = NULL; 658172827Smatteo struct sockaddr_in *sin; 659172827Smatteo struct sockaddr_in6 *sin6; 660172827Smatteo struct __rpc_sockinfo si; 661172827Smatteo int aicode; 662172827Smatteo int fd; 663172827Smatteo int nhostsbak; 664172827Smatteo int one = 1; 665172827Smatteo int r; 666172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 667222623Srmacklem int mallocd_res; 668172827Smatteo 669172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 670172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 671172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 672222623Srmacklem return (1); /* not my type */ 673172827Smatteo 674172827Smatteo /* 675172827Smatteo * XXX - using RPC library internal functions. 676172827Smatteo */ 677172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 678172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 679172827Smatteo nconf->nc_netid); 680222623Srmacklem return (1); 681172827Smatteo } 682172827Smatteo 683172827Smatteo /* Get mountd's address on this transport */ 684172827Smatteo memset(&hints, 0, sizeof hints); 685172827Smatteo hints.ai_family = si.si_af; 686172827Smatteo hints.ai_socktype = si.si_socktype; 687172827Smatteo hints.ai_protocol = si.si_proto; 688172827Smatteo 689172827Smatteo /* 690172827Smatteo * Bind to specific IPs if asked to 691172827Smatteo */ 692172827Smatteo nhostsbak = nhosts; 693172827Smatteo while (nhostsbak > 0) { 694172827Smatteo --nhostsbak; 695222623Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 696222623Srmacklem if (sock_fd == NULL) 697222623Srmacklem out_of_mem(); 698222623Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 699222623Srmacklem mallocd_res = 0; 700222623Srmacklem 701277352Srstone hints.ai_flags = AI_PASSIVE; 702277352Srstone 703172827Smatteo /* 704172827Smatteo * XXX - using RPC library internal functions. 705172827Smatteo */ 706172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 707172827Smatteo int non_fatal = 0; 708244538Skevlo if (errno == EAFNOSUPPORT && 709172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 710172827Smatteo non_fatal = 1; 711172827Smatteo 712172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 713172827Smatteo "cannot create socket for %s", nconf->nc_netid); 714222623Srmacklem if (non_fatal != 0) 715222623Srmacklem continue; 716222623Srmacklem exit(1); 717172827Smatteo } 718172827Smatteo 719172827Smatteo switch (hints.ai_family) { 720172827Smatteo case AF_INET: 721172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 722172827Smatteo host_addr) == 1) { 723222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 724172827Smatteo } else { 725172827Smatteo /* 726172827Smatteo * Skip if we have an AF_INET6 address. 727172827Smatteo */ 728172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 729172827Smatteo host_addr) == 1) { 730172827Smatteo close(fd); 731172827Smatteo continue; 732172827Smatteo } 733172827Smatteo } 734172827Smatteo break; 735172827Smatteo case AF_INET6: 736172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 737172827Smatteo host_addr) == 1) { 738222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 739172827Smatteo } else { 740172827Smatteo /* 741172827Smatteo * Skip if we have an AF_INET address. 742172827Smatteo */ 743172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 744172827Smatteo host_addr) == 1) { 745172827Smatteo close(fd); 746172827Smatteo continue; 747172827Smatteo } 748172827Smatteo } 749172827Smatteo 750172827Smatteo /* 751172827Smatteo * We're doing host-based access checks here, so don't 752172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 753172827Smatteo * disable it by default on NFS sockets too. 754172827Smatteo */ 755172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 756172827Smatteo sizeof one) < 0) { 757172827Smatteo syslog(LOG_ERR, 758172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 759172827Smatteo exit(1); 760172827Smatteo } 761172827Smatteo break; 762172827Smatteo default: 763172827Smatteo break; 764172827Smatteo } 765172827Smatteo 766172827Smatteo /* 767172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 768172827Smatteo */ 769172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 770172827Smatteo if (svcport_str == NULL) { 771172827Smatteo res = malloc(sizeof(struct addrinfo)); 772172827Smatteo if (res == NULL) 773172827Smatteo out_of_mem(); 774222623Srmacklem mallocd_res = 1; 775172827Smatteo res->ai_flags = hints.ai_flags; 776172827Smatteo res->ai_family = hints.ai_family; 777172827Smatteo res->ai_protocol = hints.ai_protocol; 778172827Smatteo switch (res->ai_family) { 779172827Smatteo case AF_INET: 780172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 781172827Smatteo if (sin == NULL) 782172827Smatteo out_of_mem(); 783172827Smatteo sin->sin_family = AF_INET; 784172827Smatteo sin->sin_port = htons(0); 785172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 786172827Smatteo res->ai_addr = (struct sockaddr*) sin; 787172827Smatteo res->ai_addrlen = (socklen_t) 788222623Srmacklem sizeof(struct sockaddr_in); 789172827Smatteo break; 790172827Smatteo case AF_INET6: 791172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 792173056Ssimon if (sin6 == NULL) 793172827Smatteo out_of_mem(); 794172827Smatteo sin6->sin6_family = AF_INET6; 795172827Smatteo sin6->sin6_port = htons(0); 796172827Smatteo sin6->sin6_addr = in6addr_any; 797172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 798172827Smatteo res->ai_addrlen = (socklen_t) 799222623Srmacklem sizeof(struct sockaddr_in6); 800222623Srmacklem break; 801172827Smatteo default: 802222623Srmacklem syslog(LOG_ERR, "bad addr fam %d", 803222623Srmacklem res->ai_family); 804222623Srmacklem exit(1); 805172827Smatteo } 806172827Smatteo } else { 807172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 808172827Smatteo &hints, &res)) != 0) { 809172827Smatteo syslog(LOG_ERR, 810172827Smatteo "cannot get local address for %s: %s", 811172827Smatteo nconf->nc_netid, 812172827Smatteo gai_strerror(aicode)); 813222623Srmacklem close(fd); 814172827Smatteo continue; 815172827Smatteo } 816172827Smatteo } 817172827Smatteo } else { 818172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 819172827Smatteo &hints, &res)) != 0) { 820172827Smatteo syslog(LOG_ERR, 821172827Smatteo "cannot get local address for %s: %s", 822172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 823222623Srmacklem close(fd); 824172827Smatteo continue; 825172827Smatteo } 826172827Smatteo } 827172827Smatteo 828222623Srmacklem /* Store the fd. */ 829222623Srmacklem sock_fd[sock_fdcnt - 1] = fd; 830222623Srmacklem 831222623Srmacklem /* Now, attempt the bind. */ 832172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 833172827Smatteo if (r != 0) { 834222623Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 835222623Srmacklem if (mallocd_res != 0) { 836222623Srmacklem free(res->ai_addr); 837222623Srmacklem free(res); 838222623Srmacklem } else 839222623Srmacklem freeaddrinfo(res); 840222623Srmacklem return (-1); 841222623Srmacklem } 842172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 843172827Smatteo exit(1); 844172827Smatteo } 845172827Smatteo 846222623Srmacklem if (svcport_str == NULL) { 847222623Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 848222623Srmacklem if (svcport_str == NULL) 849222623Srmacklem out_of_mem(); 850222623Srmacklem mallocd_svcport = 1; 851222623Srmacklem 852222623Srmacklem if (getnameinfo(res->ai_addr, 853222623Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 854222623Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 855222623Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 856222623Srmacklem errx(1, "Cannot get port number"); 857222623Srmacklem } 858222623Srmacklem if (mallocd_res != 0) { 859222623Srmacklem free(res->ai_addr); 860222623Srmacklem free(res); 861222623Srmacklem } else 862222623Srmacklem freeaddrinfo(res); 863222623Srmacklem res = NULL; 864222623Srmacklem } 865222623Srmacklem return (0); 866222623Srmacklem} 867222623Srmacklem 868222623Srmacklem/* 869222623Srmacklem * Called after all the create_service() calls have succeeded, to complete 870222623Srmacklem * the setup and registration. 871222623Srmacklem */ 872222623Srmacklemstatic void 873222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 874222623Srmacklem{ 875222623Srmacklem struct addrinfo hints, *res = NULL; 876222623Srmacklem struct __rpc_sockinfo si; 877222623Srmacklem struct netbuf servaddr; 878222623Srmacklem SVCXPRT *transp = NULL; 879222623Srmacklem int aicode, fd, nhostsbak; 880222623Srmacklem int registered = 0; 881222623Srmacklem 882222623Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 883222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 884222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 885222623Srmacklem return; /* not my type */ 886222623Srmacklem 887222623Srmacklem /* 888222623Srmacklem * XXX - using RPC library internal functions. 889222623Srmacklem */ 890222623Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 891222623Srmacklem syslog(LOG_ERR, "cannot get information for %s", 892222623Srmacklem nconf->nc_netid); 893222623Srmacklem return; 894222623Srmacklem } 895222623Srmacklem 896222623Srmacklem nhostsbak = nhosts; 897222623Srmacklem while (nhostsbak > 0) { 898222623Srmacklem --nhostsbak; 899222623Srmacklem if (sock_fdpos >= sock_fdcnt) { 900222623Srmacklem /* Should never happen. */ 901222623Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 902222623Srmacklem return; 903222623Srmacklem } 904222623Srmacklem fd = sock_fd[sock_fdpos++]; 905222623Srmacklem if (fd < 0) 906222623Srmacklem continue; 907222623Srmacklem 908172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 909172827Smatteo listen(fd, SOMAXCONN); 910172827Smatteo 911172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 912172827Smatteo transp = svc_dg_create(fd, 0, 0); 913172827Smatteo else 914172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 915172827Smatteo RPC_MAXDATASIZE); 916172827Smatteo 917172827Smatteo if (transp != (SVCXPRT *) NULL) { 918194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 919172827Smatteo NULL)) 920172827Smatteo syslog(LOG_ERR, 921194880Sdfr "can't register %s MOUNTVERS service", 922172827Smatteo nconf->nc_netid); 923172827Smatteo if (!force_v2) { 924194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 925172827Smatteo mntsrv, NULL)) 926172827Smatteo syslog(LOG_ERR, 927194880Sdfr "can't register %s MOUNTVERS3 service", 928172827Smatteo nconf->nc_netid); 929172827Smatteo } 930172827Smatteo } else 931172827Smatteo syslog(LOG_WARNING, "can't create %s services", 932172827Smatteo nconf->nc_netid); 933172827Smatteo 934172827Smatteo if (registered == 0) { 935172827Smatteo registered = 1; 936172827Smatteo memset(&hints, 0, sizeof hints); 937172827Smatteo hints.ai_flags = AI_PASSIVE; 938172827Smatteo hints.ai_family = si.si_af; 939172827Smatteo hints.ai_socktype = si.si_socktype; 940172827Smatteo hints.ai_protocol = si.si_proto; 941172827Smatteo 942222623Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 943172827Smatteo &res)) != 0) { 944172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 945172827Smatteo gai_strerror(aicode)); 946172827Smatteo exit(1); 947172827Smatteo } 948172827Smatteo 949172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 950172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 951172827Smatteo servaddr.len = res->ai_addrlen; 952172827Smatteo 953194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 954194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 955172827Smatteo 956172827Smatteo xcreated++; 957172827Smatteo freeaddrinfo(res); 958172827Smatteo } 959172827Smatteo } /* end while */ 9601558Srgrimes} 9611558Srgrimes 962222623Srmacklem/* 963222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the 964222623Srmacklem * cycle of socket creation/binding can start anew. 965222623Srmacklem */ 96637663Scharnierstatic void 967222623Srmacklemclearout_service(void) 968222623Srmacklem{ 969222623Srmacklem int i; 970222623Srmacklem 971222623Srmacklem for (i = 0; i < sock_fdcnt; i++) { 972222623Srmacklem if (sock_fd[i] >= 0) { 973222623Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 974222623Srmacklem close(sock_fd[i]); 975222623Srmacklem } 976222623Srmacklem } 977222623Srmacklem} 978222623Srmacklem 979222623Srmacklemstatic void 980216587Scharnierusage(void) 98137663Scharnier{ 98237663Scharnier fprintf(stderr, 983192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 984241568Srmacklem "[-S] [-h <bindip>] [export_file ...]\n"); 98537663Scharnier exit(1); 98637663Scharnier} 98737663Scharnier 9881558Srgrimes/* 9891558Srgrimes * The mount rpc service 9901558Srgrimes */ 9911558Srgrimesvoid 992216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp) 9931558Srgrimes{ 9941558Srgrimes struct exportlist *ep; 9951558Srgrimes struct dirlist *dp; 9969336Sdfr struct fhreturn fhr; 9971558Srgrimes struct stat stb; 9981558Srgrimes struct statfs fsb; 99974462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 100074462Salfred int lookup_failed = 1; 100174462Salfred struct sockaddr *saddr; 10029336Sdfr u_short sport; 1003194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 100428911Sguido int bad = 0, defset, hostset; 10059336Sdfr sigset_t sighup_mask; 1006240902Srmacklem int numsecflavors, *secflavorsp; 10071558Srgrimes 10089336Sdfr sigemptyset(&sighup_mask); 10099336Sdfr sigaddset(&sighup_mask, SIGHUP); 101074462Salfred saddr = svc_getrpccaller(transp)->buf; 101174462Salfred switch (saddr->sa_family) { 101274462Salfred case AF_INET6: 101375635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 101474462Salfred break; 101574462Salfred case AF_INET: 101675635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 101774462Salfred break; 101874462Salfred default: 101974462Salfred syslog(LOG_ERR, "request from unknown address family"); 102074462Salfred return; 102174462Salfred } 102274462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 102374462Salfred NULL, 0, 0); 102474462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 102574462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 10261558Srgrimes switch (rqstp->rq_proc) { 10271558Srgrimes case NULLPROC: 1028121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 102937663Scharnier syslog(LOG_ERR, "can't send reply"); 10301558Srgrimes return; 1031194880Sdfr case MOUNTPROC_MNT: 10329336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 103331656Sguido syslog(LOG_NOTICE, 103431656Sguido "mount request from %s from unprivileged port", 103574462Salfred numerichost); 10361558Srgrimes svcerr_weakauth(transp); 10371558Srgrimes return; 10381558Srgrimes } 1039121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 104031656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 104174462Salfred numerichost); 10421558Srgrimes svcerr_decode(transp); 10431558Srgrimes return; 10441558Srgrimes } 10451558Srgrimes 10461558Srgrimes /* 10471558Srgrimes * Get the real pathname and make sure it is a directory 10489336Sdfr * or a regular file if the -r option was specified 10499336Sdfr * and it exists. 10501558Srgrimes */ 105151968Salfred if (realpath(rpcpath, dirpath) == NULL || 10521558Srgrimes stat(dirpath, &stb) < 0 || 10539336Sdfr (!S_ISDIR(stb.st_mode) && 105474462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 10551558Srgrimes statfs(dirpath, &fsb) < 0) { 10561558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 105731656Sguido syslog(LOG_NOTICE, 105837663Scharnier "mount request from %s for non existent path %s", 105974462Salfred numerichost, dirpath); 10601558Srgrimes if (debug) 106137663Scharnier warnx("stat failed on %s", dirpath); 106228911Sguido bad = ENOENT; /* We will send error reply later */ 10631558Srgrimes } 10641558Srgrimes 10651558Srgrimes /* Check in the exports list */ 10669336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10671558Srgrimes ep = ex_search(&fsb.f_fsid); 10689336Sdfr hostset = defset = 0; 1069240902Srmacklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1070240902Srmacklem &numsecflavors, &secflavorsp) || 10711558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1072240902Srmacklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1073240902Srmacklem &secflavorsp)) || 107474462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 107574462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 107628911Sguido if (bad) { 1077121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 107828911Sguido (caddr_t)&bad)) 107937663Scharnier syslog(LOG_ERR, "can't send reply"); 108028911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 108128911Sguido return; 108228911Sguido } 1083240902Srmacklem if (hostset & DP_HOSTSET) { 10849336Sdfr fhr.fhr_flag = hostset; 1085240902Srmacklem fhr.fhr_numsecflavors = numsecflavors; 1086240902Srmacklem fhr.fhr_secflavors = secflavorsp; 1087240902Srmacklem } else { 10889336Sdfr fhr.fhr_flag = defset; 1089240902Srmacklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1090240902Srmacklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1091240902Srmacklem } 10929336Sdfr fhr.fhr_vers = rqstp->rq_vers; 10931558Srgrimes /* Get the file handle */ 109423681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 10959336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 10961558Srgrimes bad = errno; 109737663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1098121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 10991558Srgrimes (caddr_t)&bad)) 110037663Scharnier syslog(LOG_ERR, "can't send reply"); 11019336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11021558Srgrimes return; 11031558Srgrimes } 1104121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1105121556Speter (caddr_t)&fhr)) 110637663Scharnier syslog(LOG_ERR, "can't send reply"); 110774462Salfred if (!lookup_failed) 110874462Salfred add_mlist(host, dirpath); 11091558Srgrimes else 111074462Salfred add_mlist(numerichost, dirpath); 11111558Srgrimes if (debug) 111237663Scharnier warnx("mount successful"); 1113121767Speter if (dolog) 111431656Sguido syslog(LOG_NOTICE, 111531656Sguido "mount request succeeded from %s for %s", 111674462Salfred numerichost, dirpath); 111731656Sguido } else { 11181558Srgrimes bad = EACCES; 111931656Sguido syslog(LOG_NOTICE, 112031656Sguido "mount request denied from %s for %s", 112174462Salfred numerichost, dirpath); 112231656Sguido } 112328911Sguido 1124121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1125121556Speter (caddr_t)&bad)) 112637663Scharnier syslog(LOG_ERR, "can't send reply"); 11279336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11281558Srgrimes return; 1129194880Sdfr case MOUNTPROC_DUMP: 1130121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 113137663Scharnier syslog(LOG_ERR, "can't send reply"); 1132121767Speter else if (dolog) 113331656Sguido syslog(LOG_NOTICE, 113431656Sguido "dump request succeeded from %s", 113574462Salfred numerichost); 11361558Srgrimes return; 1137194880Sdfr case MOUNTPROC_UMNT: 11389336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 113931656Sguido syslog(LOG_NOTICE, 114031656Sguido "umount request from %s from unprivileged port", 114174462Salfred numerichost); 11421558Srgrimes svcerr_weakauth(transp); 11431558Srgrimes return; 11441558Srgrimes } 1145121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 114631656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 114774462Salfred numerichost); 11481558Srgrimes svcerr_decode(transp); 11491558Srgrimes return; 11501558Srgrimes } 115151968Salfred if (realpath(rpcpath, dirpath) == NULL) { 115251968Salfred syslog(LOG_NOTICE, "umount request from %s " 115351968Salfred "for non existent path %s", 115474462Salfred numerichost, dirpath); 115551968Salfred } 1156121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 115737663Scharnier syslog(LOG_ERR, "can't send reply"); 115874462Salfred if (!lookup_failed) 115975635Siedowse del_mlist(host, dirpath); 116075635Siedowse del_mlist(numerichost, dirpath); 1161121767Speter if (dolog) 116231656Sguido syslog(LOG_NOTICE, 116331656Sguido "umount request succeeded from %s for %s", 116474462Salfred numerichost, dirpath); 11651558Srgrimes return; 1166194880Sdfr case MOUNTPROC_UMNTALL: 11679336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 116831656Sguido syslog(LOG_NOTICE, 116931656Sguido "umountall request from %s from unprivileged port", 117074462Salfred numerichost); 11711558Srgrimes svcerr_weakauth(transp); 11721558Srgrimes return; 11731558Srgrimes } 1174121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 117537663Scharnier syslog(LOG_ERR, "can't send reply"); 117674462Salfred if (!lookup_failed) 117775635Siedowse del_mlist(host, NULL); 117875635Siedowse del_mlist(numerichost, NULL); 1179121767Speter if (dolog) 118031656Sguido syslog(LOG_NOTICE, 118131656Sguido "umountall request succeeded from %s", 118274462Salfred numerichost); 11831558Srgrimes return; 1184194880Sdfr case MOUNTPROC_EXPORT: 1185121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1186121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1187121556Speter (caddr_t)NULL)) 1188100117Salfred syslog(LOG_ERR, "can't send reply"); 1189121767Speter if (dolog) 119031656Sguido syslog(LOG_NOTICE, 119131656Sguido "export request succeeded from %s", 119274462Salfred numerichost); 11931558Srgrimes return; 11941558Srgrimes default: 11951558Srgrimes svcerr_noproc(transp); 11961558Srgrimes return; 11971558Srgrimes } 11981558Srgrimes} 11991558Srgrimes 12001558Srgrimes/* 12011558Srgrimes * Xdr conversion for a dirpath string 12021558Srgrimes */ 1203285128Straszstatic int 1204216587Scharnierxdr_dir(XDR *xdrsp, char *dirp) 12051558Srgrimes{ 1206194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 12071558Srgrimes} 12081558Srgrimes 12091558Srgrimes/* 12109336Sdfr * Xdr routine to generate file handle reply 12111558Srgrimes */ 1212285128Straszstatic int 1213216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp) 12141558Srgrimes{ 121592806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 12169336Sdfr u_long ok = 0, len, auth; 1217184588Sdfr int i; 12181558Srgrimes 12191558Srgrimes if (!xdr_long(xdrsp, &ok)) 12201558Srgrimes return (0); 12219336Sdfr switch (fhrp->fhr_vers) { 12229336Sdfr case 1: 12239336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 12249336Sdfr case 3: 12259336Sdfr len = NFSX_V3FH; 12269336Sdfr if (!xdr_long(xdrsp, &len)) 12279336Sdfr return (0); 12289336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 12299336Sdfr return (0); 1230184588Sdfr if (fhrp->fhr_numsecflavors) { 1231184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1232184588Sdfr return (0); 1233184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1234184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1235184588Sdfr return (0); 1236184588Sdfr return (1); 1237184588Sdfr } else { 1238184588Sdfr auth = AUTH_SYS; 1239184588Sdfr len = 1; 1240184588Sdfr if (!xdr_long(xdrsp, &len)) 1241184588Sdfr return (0); 1242184588Sdfr return (xdr_long(xdrsp, &auth)); 1243184588Sdfr } 1244298089Spfg } 12459336Sdfr return (0); 12461558Srgrimes} 12471558Srgrimes 1248285128Straszstatic int 1249216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 12501558Srgrimes{ 12511558Srgrimes struct mountlist *mlp; 12521558Srgrimes int true = 1; 12531558Srgrimes int false = 0; 12541558Srgrimes char *strp; 12551558Srgrimes 12561558Srgrimes mlp = mlhead; 12571558Srgrimes while (mlp) { 12581558Srgrimes if (!xdr_bool(xdrsp, &true)) 12591558Srgrimes return (0); 12601558Srgrimes strp = &mlp->ml_host[0]; 1261194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 12621558Srgrimes return (0); 12631558Srgrimes strp = &mlp->ml_dirp[0]; 1264194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12651558Srgrimes return (0); 12661558Srgrimes mlp = mlp->ml_next; 12671558Srgrimes } 12681558Srgrimes if (!xdr_bool(xdrsp, &false)) 12691558Srgrimes return (0); 12701558Srgrimes return (1); 12711558Srgrimes} 12721558Srgrimes 12731558Srgrimes/* 12741558Srgrimes * Xdr conversion for export list 12751558Srgrimes */ 1276285128Straszstatic int 1277216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 12781558Srgrimes{ 12791558Srgrimes struct exportlist *ep; 12801558Srgrimes int false = 0; 12819336Sdfr int putdef; 12829336Sdfr sigset_t sighup_mask; 12831558Srgrimes 12849336Sdfr sigemptyset(&sighup_mask); 12859336Sdfr sigaddset(&sighup_mask, SIGHUP); 12869336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 12871558Srgrimes ep = exphead; 12881558Srgrimes while (ep) { 12891558Srgrimes putdef = 0; 1290100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1291100117Salfred &putdef, brief)) 12921558Srgrimes goto errout; 12931558Srgrimes if (ep->ex_defdir && putdef == 0 && 12941558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1295100117Salfred &putdef, brief)) 12961558Srgrimes goto errout; 12971558Srgrimes ep = ep->ex_next; 12981558Srgrimes } 12999336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13001558Srgrimes if (!xdr_bool(xdrsp, &false)) 13011558Srgrimes return (0); 13021558Srgrimes return (1); 13031558Srgrimeserrout: 13049336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13051558Srgrimes return (0); 13061558Srgrimes} 13071558Srgrimes 13081558Srgrimes/* 13091558Srgrimes * Called from xdr_explist() to traverse the tree and export the 13101558Srgrimes * directory paths. 13111558Srgrimes */ 1312285128Straszstatic int 1313216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1314216587Scharnier int brief) 13151558Srgrimes{ 13161558Srgrimes struct grouplist *grp; 13171558Srgrimes struct hostlist *hp; 13181558Srgrimes int true = 1; 13191558Srgrimes int false = 0; 13201558Srgrimes int gotalldir = 0; 13211558Srgrimes char *strp; 13221558Srgrimes 13231558Srgrimes if (dp) { 1324100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 13251558Srgrimes return (1); 13261558Srgrimes if (!xdr_bool(xdrsp, &true)) 13271558Srgrimes return (1); 13281558Srgrimes strp = dp->dp_dirp; 1329194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 13301558Srgrimes return (1); 13311558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 13321558Srgrimes gotalldir = 1; 13331558Srgrimes *putdefp = 1; 13341558Srgrimes } 1335100117Salfred if (brief) { 1336100117Salfred if (!xdr_bool(xdrsp, &true)) 1337100117Salfred return (1); 1338100117Salfred strp = "(...)"; 1339194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1340100117Salfred return (1); 1341100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 13421558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 13431558Srgrimes hp = dp->dp_hosts; 13441558Srgrimes while (hp) { 13451558Srgrimes grp = hp->ht_grp; 13461558Srgrimes if (grp->gr_type == GT_HOST) { 13471558Srgrimes if (!xdr_bool(xdrsp, &true)) 13481558Srgrimes return (1); 134974462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 13508871Srgrimes if (!xdr_string(xdrsp, &strp, 1351194880Sdfr MNTNAMLEN)) 13521558Srgrimes return (1); 13531558Srgrimes } else if (grp->gr_type == GT_NET) { 13541558Srgrimes if (!xdr_bool(xdrsp, &true)) 13551558Srgrimes return (1); 13561558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 13578871Srgrimes if (!xdr_string(xdrsp, &strp, 1358194880Sdfr MNTNAMLEN)) 13591558Srgrimes return (1); 13601558Srgrimes } 13611558Srgrimes hp = hp->ht_next; 13621558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 13631558Srgrimes hp = adp->dp_hosts; 13641558Srgrimes gotalldir = 0; 13651558Srgrimes } 13661558Srgrimes } 13671558Srgrimes } 13681558Srgrimes if (!xdr_bool(xdrsp, &false)) 13691558Srgrimes return (1); 1370100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 13711558Srgrimes return (1); 13721558Srgrimes } 13731558Srgrimes return (0); 13741558Srgrimes} 13751558Srgrimes 1376285128Straszstatic int 1377216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp) 1378100117Salfred{ 1379100117Salfred 1380100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1381100117Salfred} 1382100117Salfred 1383285128Straszstatic int 1384216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1385100117Salfred{ 1386100117Salfred 1387100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1388100117Salfred} 1389100117Salfred 1390285128Straszstatic char *line; 1391285128Straszstatic size_t linesize; 1392285128Straszstatic FILE *exp_file; 13931558Srgrimes 13941558Srgrimes/* 1395166440Spjd * Get the export list from one, currently open file 13961558Srgrimes */ 1397166440Spjdstatic void 1398216587Scharnierget_exportlist_one(void) 13991558Srgrimes{ 14001558Srgrimes struct exportlist *ep, *ep2; 14011558Srgrimes struct grouplist *grp, *tgrp; 14021558Srgrimes struct exportlist **epp; 14031558Srgrimes struct dirlist *dirhead; 1404166440Spjd struct statfs fsb; 140572650Sgreen struct xucred anon; 14061558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1407166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 14081558Srgrimes 1409192934Srmacklem v4root_phase = 0; 14101558Srgrimes dirhead = (struct dirlist *)NULL; 14111558Srgrimes while (get_line()) { 14121558Srgrimes if (debug) 141337663Scharnier warnx("got line %s", line); 14141558Srgrimes cp = line; 14151558Srgrimes nextfield(&cp, &endcp); 14161558Srgrimes if (*cp == '#') 14171558Srgrimes goto nextline; 14181558Srgrimes 14191558Srgrimes /* 14201558Srgrimes * Set defaults. 14211558Srgrimes */ 14221558Srgrimes has_host = FALSE; 14231558Srgrimes anon = def_anon; 14241558Srgrimes exflags = MNT_EXPORTED; 14251558Srgrimes got_nondir = 0; 14261558Srgrimes opt_flags = 0; 14271558Srgrimes ep = (struct exportlist *)NULL; 1428192934Srmacklem dirp = NULL; 14291558Srgrimes 14301558Srgrimes /* 1431192934Srmacklem * Handle the V4 root dir. 1432192934Srmacklem */ 1433192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1434192934Srmacklem /* 1435192934Srmacklem * V4: just indicates that it is the v4 root point, 1436192934Srmacklem * so skip over that and set v4root_phase. 1437192934Srmacklem */ 1438192934Srmacklem if (v4root_phase > 0) { 1439192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1440192934Srmacklem goto nextline; 1441192934Srmacklem } 1442192934Srmacklem v4root_phase = 1; 1443192934Srmacklem cp += 3; 1444192934Srmacklem nextfield(&cp, &endcp); 1445192934Srmacklem } 1446192934Srmacklem 1447192934Srmacklem /* 14481558Srgrimes * Create new exports list entry 14491558Srgrimes */ 14501558Srgrimes len = endcp-cp; 14511558Srgrimes tgrp = grp = get_grp(); 14521558Srgrimes while (len > 0) { 1453194880Sdfr if (len > MNTNAMLEN) { 14541558Srgrimes getexp_err(ep, tgrp); 14551558Srgrimes goto nextline; 14561558Srgrimes } 14571558Srgrimes if (*cp == '-') { 14581558Srgrimes if (ep == (struct exportlist *)NULL) { 14591558Srgrimes getexp_err(ep, tgrp); 14601558Srgrimes goto nextline; 14611558Srgrimes } 14621558Srgrimes if (debug) 146337663Scharnier warnx("doing opt %s", cp); 14641558Srgrimes got_nondir = 1; 14651558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 14661558Srgrimes &exflags, &anon)) { 14671558Srgrimes getexp_err(ep, tgrp); 14681558Srgrimes goto nextline; 14691558Srgrimes } 14701558Srgrimes } else if (*cp == '/') { 14711558Srgrimes savedc = *endcp; 14721558Srgrimes *endcp = '\0'; 1473192934Srmacklem if (v4root_phase > 1) { 1474192934Srmacklem if (dirp != NULL) { 1475192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 1476192934Srmacklem getexp_err(ep, tgrp); 1477192934Srmacklem goto nextline; 1478192934Srmacklem } 1479192934Srmacklem } 14801558Srgrimes if (check_dirpath(cp) && 14811558Srgrimes statfs(cp, &fsb) >= 0) { 1482283008Srmacklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 1483283008Srmacklem syslog(LOG_ERR, "Warning: exporting of " 1484283008Srmacklem "automounted fs %s not supported", cp); 14851558Srgrimes if (got_nondir) { 148637663Scharnier syslog(LOG_ERR, "dirs must be first"); 14871558Srgrimes getexp_err(ep, tgrp); 14881558Srgrimes goto nextline; 14891558Srgrimes } 1490192934Srmacklem if (v4root_phase == 1) { 1491192934Srmacklem if (dirp != NULL) { 1492192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 14931558Srgrimes getexp_err(ep, tgrp); 14941558Srgrimes goto nextline; 14951558Srgrimes } 1496192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1497192934Srmacklem strlcpy(v4root_dirpath, cp, 1498192934Srmacklem sizeof (v4root_dirpath)); 1499192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1500192934Srmacklem != 0) { 1501192934Srmacklem syslog(LOG_ERR, 1502192934Srmacklem "different V4 dirpath %s", cp); 1503192934Srmacklem getexp_err(ep, tgrp); 1504192934Srmacklem goto nextline; 1505192934Srmacklem } 1506192934Srmacklem dirp = cp; 1507192934Srmacklem v4root_phase = 2; 1508192934Srmacklem got_nondir = 1; 1509192934Srmacklem ep = get_exp(); 15101558Srgrimes } else { 1511192934Srmacklem if (ep) { 1512192934Srmacklem if (ep->ex_fs.val[0] != 1513192934Srmacklem fsb.f_fsid.val[0] || 1514192934Srmacklem ep->ex_fs.val[1] != 1515192934Srmacklem fsb.f_fsid.val[1]) { 1516192934Srmacklem getexp_err(ep, tgrp); 1517192934Srmacklem goto nextline; 1518192934Srmacklem } 1519192934Srmacklem } else { 1520192934Srmacklem /* 1521192934Srmacklem * See if this directory is already 1522192934Srmacklem * in the list. 1523192934Srmacklem */ 1524192934Srmacklem ep = ex_search(&fsb.f_fsid); 1525192934Srmacklem if (ep == (struct exportlist *)NULL) { 1526192934Srmacklem ep = get_exp(); 1527192934Srmacklem ep->ex_fs = fsb.f_fsid; 1528192934Srmacklem ep->ex_fsdir = (char *)malloc 1529192934Srmacklem (strlen(fsb.f_mntonname) + 1); 1530192934Srmacklem if (ep->ex_fsdir) 1531192934Srmacklem strcpy(ep->ex_fsdir, 1532192934Srmacklem fsb.f_mntonname); 1533192934Srmacklem else 1534192934Srmacklem out_of_mem(); 1535192934Srmacklem if (debug) 1536192934Srmacklem warnx( 1537192934Srmacklem "making new ep fs=0x%x,0x%x", 1538192934Srmacklem fsb.f_fsid.val[0], 1539192934Srmacklem fsb.f_fsid.val[1]); 1540192934Srmacklem } else if (debug) 1541192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1542192934Srmacklem fsb.f_fsid.val[0], 1543192934Srmacklem fsb.f_fsid.val[1]); 1544192934Srmacklem } 1545192934Srmacklem 15461558Srgrimes /* 1547192934Srmacklem * Add dirpath to export mount point. 15481558Srgrimes */ 1549192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1550192934Srmacklem dirplen = len; 15511558Srgrimes } 15521558Srgrimes } else { 15531558Srgrimes getexp_err(ep, tgrp); 15541558Srgrimes goto nextline; 15551558Srgrimes } 15561558Srgrimes *endcp = savedc; 15571558Srgrimes } else { 15581558Srgrimes savedc = *endcp; 15591558Srgrimes *endcp = '\0'; 15601558Srgrimes got_nondir = 1; 15611558Srgrimes if (ep == (struct exportlist *)NULL) { 15621558Srgrimes getexp_err(ep, tgrp); 15631558Srgrimes goto nextline; 15641558Srgrimes } 15651558Srgrimes 15661558Srgrimes /* 15671558Srgrimes * Get the host or netgroup. 15681558Srgrimes */ 15691558Srgrimes setnetgrent(cp); 15701558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 15711558Srgrimes do { 15721558Srgrimes if (has_host) { 15731558Srgrimes grp->gr_next = get_grp(); 15741558Srgrimes grp = grp->gr_next; 15751558Srgrimes } 15761558Srgrimes if (netgrp) { 157737003Sjoerg if (hst == 0) { 157837663Scharnier syslog(LOG_ERR, 157937663Scharnier "null hostname in netgroup %s, skipping", cp); 158037004Sjoerg grp->gr_type = GT_IGNORE; 158137003Sjoerg } else if (get_host(hst, grp, tgrp)) { 158237663Scharnier syslog(LOG_ERR, 158337663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 158429317Sjlemon grp->gr_type = GT_IGNORE; 15851558Srgrimes } 15867401Swpaul } else if (get_host(cp, grp, tgrp)) { 158737663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 158829317Sjlemon grp->gr_type = GT_IGNORE; 15891558Srgrimes } 15901558Srgrimes has_host = TRUE; 15911558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 15921558Srgrimes endnetgrent(); 15931558Srgrimes *endcp = savedc; 15941558Srgrimes } 15951558Srgrimes cp = endcp; 15961558Srgrimes nextfield(&cp, &endcp); 15971558Srgrimes len = endcp - cp; 15981558Srgrimes } 15991558Srgrimes if (check_options(dirhead)) { 16001558Srgrimes getexp_err(ep, tgrp); 16011558Srgrimes goto nextline; 16021558Srgrimes } 16031558Srgrimes if (!has_host) { 160475641Siedowse grp->gr_type = GT_DEFAULT; 16051558Srgrimes if (debug) 160637663Scharnier warnx("adding a default entry"); 16071558Srgrimes 16081558Srgrimes /* 16091558Srgrimes * Don't allow a network export coincide with a list of 16101558Srgrimes * host(s) on the same line. 16111558Srgrimes */ 16121558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 161375801Siedowse syslog(LOG_ERR, "network/host conflict"); 16141558Srgrimes getexp_err(ep, tgrp); 16151558Srgrimes goto nextline; 161629317Sjlemon 161774462Salfred /* 161874462Salfred * If an export list was specified on this line, make sure 161929317Sjlemon * that we have at least one valid entry, otherwise skip it. 162029317Sjlemon */ 162129317Sjlemon } else { 162229317Sjlemon grp = tgrp; 162374462Salfred while (grp && grp->gr_type == GT_IGNORE) 162429317Sjlemon grp = grp->gr_next; 162529317Sjlemon if (! grp) { 162629317Sjlemon getexp_err(ep, tgrp); 162729317Sjlemon goto nextline; 162829317Sjlemon } 16291558Srgrimes } 16301558Srgrimes 1631192934Srmacklem if (v4root_phase == 1) { 1632192934Srmacklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1633192934Srmacklem getexp_err(ep, tgrp); 1634192934Srmacklem goto nextline; 1635192934Srmacklem } 1636192934Srmacklem 16371558Srgrimes /* 16381558Srgrimes * Loop through hosts, pushing the exports into the kernel. 16391558Srgrimes * After loop, tgrp points to the start of the list and 16401558Srgrimes * grp points to the last entry in the list. 16411558Srgrimes */ 16421558Srgrimes grp = tgrp; 16431558Srgrimes do { 164475635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 164575635Siedowse &fsb)) { 164675635Siedowse getexp_err(ep, tgrp); 164775635Siedowse goto nextline; 164875635Siedowse } 16491558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 16501558Srgrimes 16511558Srgrimes /* 1652192934Srmacklem * For V4: don't enter in mount lists. 1653192934Srmacklem */ 1654194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1655194773Srmacklem /* 1656194773Srmacklem * Since these structures aren't used by mountd, 1657194773Srmacklem * free them up now. 1658194773Srmacklem */ 1659194773Srmacklem if (ep != NULL) 1660194773Srmacklem free_exp(ep); 1661194773Srmacklem while (tgrp != NULL) { 1662194773Srmacklem grp = tgrp; 1663194773Srmacklem tgrp = tgrp->gr_next; 1664194773Srmacklem free_grp(grp); 1665194773Srmacklem } 1666192934Srmacklem goto nextline; 1667194773Srmacklem } 1668192934Srmacklem 1669192934Srmacklem /* 16701558Srgrimes * Success. Update the data structures. 16711558Srgrimes */ 16721558Srgrimes if (has_host) { 16739336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 16741558Srgrimes grp->gr_next = grphead; 16751558Srgrimes grphead = tgrp; 16761558Srgrimes } else { 16771558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 16789336Sdfr opt_flags); 16791558Srgrimes free_grp(grp); 16801558Srgrimes } 16811558Srgrimes dirhead = (struct dirlist *)NULL; 16821558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 16831558Srgrimes ep2 = exphead; 16841558Srgrimes epp = &exphead; 16851558Srgrimes 16861558Srgrimes /* 16871558Srgrimes * Insert in the list in alphabetical order. 16881558Srgrimes */ 16891558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 16901558Srgrimes epp = &ep2->ex_next; 16911558Srgrimes ep2 = ep2->ex_next; 16921558Srgrimes } 16931558Srgrimes if (ep2) 16941558Srgrimes ep->ex_next = ep2; 16951558Srgrimes *epp = ep; 16961558Srgrimes ep->ex_flag |= EX_LINKED; 16971558Srgrimes } 16981558Srgrimesnextline: 1699192934Srmacklem v4root_phase = 0; 17001558Srgrimes if (dirhead) { 17011558Srgrimes free_dir(dirhead); 17021558Srgrimes dirhead = (struct dirlist *)NULL; 17031558Srgrimes } 17041558Srgrimes } 17051558Srgrimes} 17061558Srgrimes 17071558Srgrimes/* 1708166440Spjd * Get the export list from all specified files 1709166440Spjd */ 1710285128Straszstatic void 1711216587Scharnierget_exportlist(void) 1712166440Spjd{ 1713166440Spjd struct exportlist *ep, *ep2; 1714166440Spjd struct grouplist *grp, *tgrp; 1715166440Spjd struct export_args export; 1716166440Spjd struct iovec *iov; 1717166440Spjd struct statfs *fsp, *mntbufp; 1718166440Spjd struct xvfsconf vfc; 1719166440Spjd char errmsg[255]; 1720230352Seadler int num, i; 1721166440Spjd int iovlen; 1722168684Spjd int done; 1723192934Srmacklem struct nfsex_args eargs; 1724166440Spjd 1725241568Srmacklem if (suspend_nfsd != 0) 1726241568Srmacklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 1727192934Srmacklem v4root_dirpath[0] = '\0'; 1728166440Spjd bzero(&export, sizeof(export)); 1729166440Spjd export.ex_flags = MNT_DELEXPORT; 1730166440Spjd iov = NULL; 1731166440Spjd iovlen = 0; 1732166440Spjd bzero(errmsg, sizeof(errmsg)); 1733166440Spjd 1734166440Spjd /* 1735166440Spjd * First, get rid of the old list 1736166440Spjd */ 1737166440Spjd ep = exphead; 1738166440Spjd while (ep) { 1739166440Spjd ep2 = ep; 1740166440Spjd ep = ep->ex_next; 1741166440Spjd free_exp(ep2); 1742166440Spjd } 1743166440Spjd exphead = (struct exportlist *)NULL; 1744166440Spjd 1745166440Spjd grp = grphead; 1746166440Spjd while (grp) { 1747166440Spjd tgrp = grp; 1748166440Spjd grp = grp->gr_next; 1749166440Spjd free_grp(tgrp); 1750166440Spjd } 1751166440Spjd grphead = (struct grouplist *)NULL; 1752166440Spjd 1753166440Spjd /* 1754192934Srmacklem * and the old V4 root dir. 1755192934Srmacklem */ 1756192934Srmacklem bzero(&eargs, sizeof (eargs)); 1757192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1758282214Strasz if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1759192934Srmacklem errno != ENOENT) 1760192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1761192934Srmacklem 1762192934Srmacklem /* 1763192934Srmacklem * and clear flag that notes if a public fh has been exported. 1764192934Srmacklem */ 1765192934Srmacklem has_publicfh = 0; 1766192934Srmacklem 1767192934Srmacklem /* 1768166440Spjd * And delete exports that are in the kernel for all local 1769166440Spjd * filesystems. 1770166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1771166440Spjd */ 1772166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1773166440Spjd 1774166440Spjd if (num > 0) { 1775166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1776166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1777166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1778166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1779166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1780166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1781166440Spjd } 1782166440Spjd 1783166440Spjd for (i = 0; i < num; i++) { 1784166440Spjd fsp = &mntbufp[i]; 1785166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1786166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1787166440Spjd fsp->f_fstypename); 1788166440Spjd continue; 1789166440Spjd } 1790166440Spjd 1791166440Spjd /* 1792281699Ssjg * We do not need to delete "export" flag from 1793281699Ssjg * filesystems that do not have it set. 1794281699Ssjg */ 1795281699Ssjg if (!(fsp->f_flags & MNT_EXPORTED)) 1796281699Ssjg continue; 1797281699Ssjg /* 1798166440Spjd * Do not delete export for network filesystem by 1799166440Spjd * passing "export" arg to nmount(). 1800166440Spjd * It only makes sense to do this for local filesystems. 1801166440Spjd */ 1802166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1803166440Spjd continue; 1804166440Spjd 1805166440Spjd iov[1].iov_base = fsp->f_fstypename; 1806166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1807166440Spjd iov[3].iov_base = fsp->f_mntonname; 1808166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1809166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1810166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1811270183Sbdrewery errmsg[0] = '\0'; 1812166440Spjd 1813278523Skib /* 1814278523Skib * EXDEV is returned when path exists but is not a 1815278523Skib * mount point. May happens if raced with unmount. 1816278523Skib */ 1817166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1818278523Skib errno != ENOENT && errno != ENOTSUP && errno != EXDEV) { 1819166440Spjd syslog(LOG_ERR, 1820166440Spjd "can't delete exports for %s: %m %s", 1821166440Spjd fsp->f_mntonname, errmsg); 1822166440Spjd } 1823166440Spjd } 1824166440Spjd 1825166440Spjd if (iov != NULL) { 1826166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1827166440Spjd free(iov[0].iov_base); /* fstype */ 1828166440Spjd free(iov[2].iov_base); /* fspath */ 1829166440Spjd free(iov[4].iov_base); /* from */ 1830166440Spjd free(iov[6].iov_base); /* update */ 1831166440Spjd free(iov[8].iov_base); /* export */ 1832166440Spjd free(iov[10].iov_base); /* errmsg */ 1833166440Spjd 1834166440Spjd /* free iov, allocated by realloc() */ 1835166440Spjd free(iov); 1836166440Spjd iovlen = 0; 1837166440Spjd } 1838166440Spjd 1839166440Spjd /* 1840166440Spjd * Read in the exports file and build the list, calling 1841166440Spjd * nmount() as we go along to push the export rules into the kernel. 1842166440Spjd */ 1843168684Spjd done = 0; 1844166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1845166440Spjd if (debug) 1846166440Spjd warnx("reading exports from %s", exnames[i]); 1847166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1848168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1849168684Spjd continue; 1850166440Spjd } 1851166440Spjd get_exportlist_one(); 1852166440Spjd fclose(exp_file); 1853168684Spjd done++; 1854166440Spjd } 1855168684Spjd if (done == 0) { 1856168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1857168684Spjd exit(2); 1858168684Spjd } 1859192934Srmacklem 1860192934Srmacklem /* 1861192934Srmacklem * If there was no public fh, clear any previous one set. 1862192934Srmacklem */ 1863282214Strasz if (has_publicfh == 0) 1864192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1865241568Srmacklem 1866241568Srmacklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1867241568Srmacklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 1868166440Spjd} 1869166440Spjd 1870166440Spjd/* 18711558Srgrimes * Allocate an export list element 18721558Srgrimes */ 1873285128Straszstatic struct exportlist * 1874216587Scharnierget_exp(void) 18751558Srgrimes{ 18761558Srgrimes struct exportlist *ep; 18771558Srgrimes 1878224003Sdelphij ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 18791558Srgrimes if (ep == (struct exportlist *)NULL) 18801558Srgrimes out_of_mem(); 18811558Srgrimes return (ep); 18821558Srgrimes} 18831558Srgrimes 18841558Srgrimes/* 18851558Srgrimes * Allocate a group list element 18861558Srgrimes */ 1887285128Straszstatic struct grouplist * 1888216587Scharnierget_grp(void) 18891558Srgrimes{ 18901558Srgrimes struct grouplist *gp; 18911558Srgrimes 1892224003Sdelphij gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 18931558Srgrimes if (gp == (struct grouplist *)NULL) 18941558Srgrimes out_of_mem(); 18951558Srgrimes return (gp); 18961558Srgrimes} 18971558Srgrimes 18981558Srgrimes/* 18991558Srgrimes * Clean up upon an error in get_exportlist(). 19001558Srgrimes */ 1901285128Straszstatic void 1902216587Scharniergetexp_err(struct exportlist *ep, struct grouplist *grp) 19031558Srgrimes{ 19041558Srgrimes struct grouplist *tgrp; 19051558Srgrimes 1906100336Sjoerg if (!(opt_flags & OP_QUIET)) 1907100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 19081558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 19091558Srgrimes free_exp(ep); 19101558Srgrimes while (grp) { 19111558Srgrimes tgrp = grp; 19121558Srgrimes grp = grp->gr_next; 19131558Srgrimes free_grp(tgrp); 19141558Srgrimes } 19151558Srgrimes} 19161558Srgrimes 19171558Srgrimes/* 19181558Srgrimes * Search the export list for a matching fs. 19191558Srgrimes */ 1920285128Straszstatic struct exportlist * 1921216587Scharnierex_search(fsid_t *fsid) 19221558Srgrimes{ 19231558Srgrimes struct exportlist *ep; 19241558Srgrimes 19251558Srgrimes ep = exphead; 19261558Srgrimes while (ep) { 19271558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 19281558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 19291558Srgrimes return (ep); 19301558Srgrimes ep = ep->ex_next; 19311558Srgrimes } 19321558Srgrimes return (ep); 19331558Srgrimes} 19341558Srgrimes 19351558Srgrimes/* 19361558Srgrimes * Add a directory path to the list. 19371558Srgrimes */ 1938285128Straszstatic char * 1939216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len) 19401558Srgrimes{ 19411558Srgrimes struct dirlist *dp; 19421558Srgrimes 19431558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 194437663Scharnier if (dp == (struct dirlist *)NULL) 194537663Scharnier out_of_mem(); 19461558Srgrimes dp->dp_left = *dpp; 19471558Srgrimes dp->dp_right = (struct dirlist *)NULL; 19481558Srgrimes dp->dp_flag = 0; 19491558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 19501558Srgrimes strcpy(dp->dp_dirp, cp); 19511558Srgrimes *dpp = dp; 19521558Srgrimes return (dp->dp_dirp); 19531558Srgrimes} 19541558Srgrimes 19551558Srgrimes/* 19561558Srgrimes * Hang the dir list element off the dirpath binary tree as required 19571558Srgrimes * and update the entry for host. 19581558Srgrimes */ 1959285128Straszstatic void 1960216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1961216587Scharnier int flags) 19621558Srgrimes{ 19631558Srgrimes struct hostlist *hp; 19641558Srgrimes struct dirlist *dp2; 19651558Srgrimes 19669336Sdfr if (flags & OP_ALLDIRS) { 19671558Srgrimes if (ep->ex_defdir) 19681558Srgrimes free((caddr_t)dp); 19691558Srgrimes else 19701558Srgrimes ep->ex_defdir = dp; 19719336Sdfr if (grp == (struct grouplist *)NULL) { 19721558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 1973240902Srmacklem /* Save the default security flavors list. */ 1974240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 1975240902Srmacklem if (ep->ex_numsecflavors > 0) 1976240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 1977240902Srmacklem sizeof(ep->ex_secflavors)); 19789336Sdfr } else while (grp) { 19791558Srgrimes hp = get_ht(); 19801558Srgrimes hp->ht_grp = grp; 19811558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 19821558Srgrimes ep->ex_defdir->dp_hosts = hp; 1983240902Srmacklem /* Save the security flavors list for this host set. */ 1984240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 1985240902Srmacklem if (ep->ex_numsecflavors > 0) 1986240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 1987240902Srmacklem sizeof(ep->ex_secflavors)); 19881558Srgrimes grp = grp->gr_next; 19891558Srgrimes } 19901558Srgrimes } else { 19911558Srgrimes 19921558Srgrimes /* 199337663Scharnier * Loop through the directories adding them to the tree. 19941558Srgrimes */ 19951558Srgrimes while (dp) { 19961558Srgrimes dp2 = dp->dp_left; 1997240902Srmacklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep); 19981558Srgrimes dp = dp2; 19991558Srgrimes } 20001558Srgrimes } 20011558Srgrimes} 20021558Srgrimes 20031558Srgrimes/* 20041558Srgrimes * Traverse the binary tree either updating a node that is already there 20051558Srgrimes * for the new directory or adding the new node. 20061558Srgrimes */ 2007285128Straszstatic void 2008216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2009240902Srmacklem int flags, struct exportlist *ep) 20101558Srgrimes{ 20111558Srgrimes struct dirlist *dp; 20121558Srgrimes struct hostlist *hp; 20131558Srgrimes int cmp; 20141558Srgrimes 20151558Srgrimes dp = *dpp; 20161558Srgrimes if (dp) { 20171558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 20181558Srgrimes if (cmp > 0) { 2019240902Srmacklem add_dlist(&dp->dp_left, newdp, grp, flags, ep); 20201558Srgrimes return; 20211558Srgrimes } else if (cmp < 0) { 2022240902Srmacklem add_dlist(&dp->dp_right, newdp, grp, flags, ep); 20231558Srgrimes return; 20241558Srgrimes } else 20251558Srgrimes free((caddr_t)newdp); 20261558Srgrimes } else { 20271558Srgrimes dp = newdp; 20281558Srgrimes dp->dp_left = (struct dirlist *)NULL; 20291558Srgrimes *dpp = dp; 20301558Srgrimes } 20311558Srgrimes if (grp) { 20321558Srgrimes 20331558Srgrimes /* 20341558Srgrimes * Hang all of the host(s) off of the directory point. 20351558Srgrimes */ 20361558Srgrimes do { 20371558Srgrimes hp = get_ht(); 20381558Srgrimes hp->ht_grp = grp; 20391558Srgrimes hp->ht_next = dp->dp_hosts; 20401558Srgrimes dp->dp_hosts = hp; 2041240902Srmacklem /* Save the security flavors list for this host set. */ 2042240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2043240902Srmacklem if (ep->ex_numsecflavors > 0) 2044240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2045240902Srmacklem sizeof(ep->ex_secflavors)); 20461558Srgrimes grp = grp->gr_next; 20471558Srgrimes } while (grp); 20489336Sdfr } else { 20491558Srgrimes dp->dp_flag |= DP_DEFSET; 2050240902Srmacklem /* Save the default security flavors list. */ 2051240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2052240902Srmacklem if (ep->ex_numsecflavors > 0) 2053240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2054240902Srmacklem sizeof(ep->ex_secflavors)); 20559336Sdfr } 20561558Srgrimes} 20571558Srgrimes 20581558Srgrimes/* 20591558Srgrimes * Search for a dirpath on the export point. 20601558Srgrimes */ 2061285128Straszstatic struct dirlist * 2062216587Scharnierdirp_search(struct dirlist *dp, char *dirp) 20631558Srgrimes{ 20641558Srgrimes int cmp; 20651558Srgrimes 20661558Srgrimes if (dp) { 206774462Salfred cmp = strcmp(dp->dp_dirp, dirp); 20681558Srgrimes if (cmp > 0) 206974462Salfred return (dirp_search(dp->dp_left, dirp)); 20701558Srgrimes else if (cmp < 0) 207174462Salfred return (dirp_search(dp->dp_right, dirp)); 20721558Srgrimes else 20731558Srgrimes return (dp); 20741558Srgrimes } 20751558Srgrimes return (dp); 20761558Srgrimes} 20771558Srgrimes 20781558Srgrimes/* 20791558Srgrimes * Scan for a host match in a directory tree. 20801558Srgrimes */ 2081285128Straszstatic int 2082216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2083240902Srmacklem int *hostsetp, int *numsecflavors, int **secflavorsp) 20841558Srgrimes{ 20851558Srgrimes struct hostlist *hp; 20861558Srgrimes struct grouplist *grp; 208774462Salfred struct addrinfo *ai; 20881558Srgrimes 20891558Srgrimes if (dp) { 20901558Srgrimes if (dp->dp_flag & DP_DEFSET) 20919336Sdfr *defsetp = dp->dp_flag; 20921558Srgrimes hp = dp->dp_hosts; 20931558Srgrimes while (hp) { 20941558Srgrimes grp = hp->ht_grp; 20951558Srgrimes switch (grp->gr_type) { 20961558Srgrimes case GT_HOST: 209774462Salfred ai = grp->gr_ptr.gt_addrinfo; 209874462Salfred for (; ai; ai = ai->ai_next) { 209975801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 210074462Salfred *hostsetp = 210174462Salfred (hp->ht_flag | DP_HOSTSET); 2102240902Srmacklem if (numsecflavors != NULL) { 2103240902Srmacklem *numsecflavors = 2104240902Srmacklem grp->gr_numsecflavors; 2105240902Srmacklem *secflavorsp = 2106240902Srmacklem grp->gr_secflavors; 2107240902Srmacklem } 210874462Salfred return (1); 210974462Salfred } 21109336Sdfr } 211175801Siedowse break; 21121558Srgrimes case GT_NET: 211375801Siedowse if (!sacmp(saddr, (struct sockaddr *) 211475801Siedowse &grp->gr_ptr.gt_net.nt_net, 211575801Siedowse (struct sockaddr *) 211675801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 211774462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 2118240902Srmacklem if (numsecflavors != NULL) { 2119240902Srmacklem *numsecflavors = 2120240902Srmacklem grp->gr_numsecflavors; 2121240902Srmacklem *secflavorsp = 2122240902Srmacklem grp->gr_secflavors; 2123240902Srmacklem } 212474462Salfred return (1); 212574462Salfred } 212675801Siedowse break; 212775801Siedowse } 21281558Srgrimes hp = hp->ht_next; 21291558Srgrimes } 21301558Srgrimes } 21311558Srgrimes return (0); 21321558Srgrimes} 21331558Srgrimes 21341558Srgrimes/* 21351558Srgrimes * Scan tree for a host that matches the address. 21361558Srgrimes */ 2137285128Straszstatic int 2138216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr) 21391558Srgrimes{ 21409336Sdfr int defset, hostset; 21411558Srgrimes 21421558Srgrimes if (dp) { 21431558Srgrimes if (scan_tree(dp->dp_left, saddr)) 21441558Srgrimes return (1); 2145240902Srmacklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 21461558Srgrimes return (1); 21471558Srgrimes if (scan_tree(dp->dp_right, saddr)) 21481558Srgrimes return (1); 21491558Srgrimes } 21501558Srgrimes return (0); 21511558Srgrimes} 21521558Srgrimes 21531558Srgrimes/* 21541558Srgrimes * Traverse the dirlist tree and free it up. 21551558Srgrimes */ 2156285128Straszstatic void 2157216587Scharnierfree_dir(struct dirlist *dp) 21581558Srgrimes{ 21591558Srgrimes 21601558Srgrimes if (dp) { 21611558Srgrimes free_dir(dp->dp_left); 21621558Srgrimes free_dir(dp->dp_right); 21631558Srgrimes free_host(dp->dp_hosts); 21641558Srgrimes free((caddr_t)dp); 21651558Srgrimes } 21661558Srgrimes} 21671558Srgrimes 21681558Srgrimes/* 2169184588Sdfr * Parse a colon separated list of security flavors 2170184588Sdfr */ 2171285128Straszstatic int 2172216587Scharnierparsesec(char *seclist, struct exportlist *ep) 2173184588Sdfr{ 2174184588Sdfr char *cp, savedc; 2175184588Sdfr int flavor; 2176184588Sdfr 2177184588Sdfr ep->ex_numsecflavors = 0; 2178184588Sdfr for (;;) { 2179184588Sdfr cp = strchr(seclist, ':'); 2180184588Sdfr if (cp) { 2181184588Sdfr savedc = *cp; 2182184588Sdfr *cp = '\0'; 2183184588Sdfr } 2184184588Sdfr 2185184588Sdfr if (!strcmp(seclist, "sys")) 2186184588Sdfr flavor = AUTH_SYS; 2187184588Sdfr else if (!strcmp(seclist, "krb5")) 2188184588Sdfr flavor = RPCSEC_GSS_KRB5; 2189184588Sdfr else if (!strcmp(seclist, "krb5i")) 2190184588Sdfr flavor = RPCSEC_GSS_KRB5I; 2191184588Sdfr else if (!strcmp(seclist, "krb5p")) 2192184588Sdfr flavor = RPCSEC_GSS_KRB5P; 2193184588Sdfr else { 2194184588Sdfr if (cp) 2195184588Sdfr *cp = savedc; 2196184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2197184588Sdfr return (1); 2198184588Sdfr } 2199184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2200184588Sdfr if (cp) 2201184588Sdfr *cp = savedc; 2202184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2203184588Sdfr return (1); 2204184588Sdfr } 2205184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2206184588Sdfr ep->ex_numsecflavors++; 2207184588Sdfr if (cp) { 2208184588Sdfr *cp = savedc; 2209184588Sdfr seclist = cp + 1; 2210184588Sdfr } else { 2211184588Sdfr break; 2212184588Sdfr } 2213184588Sdfr } 2214184588Sdfr return (0); 2215184588Sdfr} 2216184588Sdfr 2217184588Sdfr/* 22181558Srgrimes * Parse the option string and update fields. 22191558Srgrimes * Option arguments may either be -<option>=<value> or 22201558Srgrimes * -<option> <value> 22211558Srgrimes */ 2222285128Straszstatic int 2223216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2224216587Scharnier int *has_hostp, int *exflagsp, struct xucred *cr) 22251558Srgrimes{ 22261558Srgrimes char *cpoptarg, *cpoptend; 22271558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 22281558Srgrimes int allflag, usedarg; 22291558Srgrimes 223051968Salfred savedc2 = '\0'; 22311558Srgrimes cpopt = *cpp; 22321558Srgrimes cpopt++; 22331558Srgrimes cp = *endcpp; 22341558Srgrimes savedc = *cp; 22351558Srgrimes *cp = '\0'; 22361558Srgrimes while (cpopt && *cpopt) { 22371558Srgrimes allflag = 1; 22381558Srgrimes usedarg = -2; 223937663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 22401558Srgrimes *cpoptend++ = '\0'; 224137663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 22421558Srgrimes *cpoptarg++ = '\0'; 22431558Srgrimes } else { 224437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 22451558Srgrimes *cpoptarg++ = '\0'; 22461558Srgrimes else { 22471558Srgrimes *cp = savedc; 22481558Srgrimes nextfield(&cp, &endcp); 22491558Srgrimes **endcpp = '\0'; 22501558Srgrimes if (endcp > cp && *cp != '-') { 22511558Srgrimes cpoptarg = cp; 22521558Srgrimes savedc2 = *endcp; 22531558Srgrimes *endcp = '\0'; 22541558Srgrimes usedarg = 0; 22551558Srgrimes } 22561558Srgrimes } 22571558Srgrimes } 22581558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 22591558Srgrimes *exflagsp |= MNT_EXRDONLY; 22601558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 22611558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 22621558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 22631558Srgrimes usedarg++; 22641558Srgrimes parsecred(cpoptarg, cr); 22651558Srgrimes if (allflag == 0) { 22661558Srgrimes *exflagsp |= MNT_EXPORTANON; 22671558Srgrimes opt_flags |= OP_MAPALL; 22681558Srgrimes } else 22691558Srgrimes opt_flags |= OP_MAPROOT; 22701558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 227175801Siedowse !strcmp(cpopt, "m"))) { 22721558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 227337663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 22741558Srgrimes return (1); 22751558Srgrimes } 22761558Srgrimes usedarg++; 22771558Srgrimes opt_flags |= OP_MASK; 22781558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 22791558Srgrimes !strcmp(cpopt, "n"))) { 228074462Salfred if (strchr(cpoptarg, '/') != NULL) { 228174462Salfred if (debug) 228274462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 228374462Salfred opt_flags |= OP_MASKLEN; 228474462Salfred } 22851558Srgrimes if (grp->gr_type != GT_NULL) { 228637663Scharnier syslog(LOG_ERR, "network/host conflict"); 22871558Srgrimes return (1); 22881558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 228937663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 22901558Srgrimes return (1); 22911558Srgrimes } 22921558Srgrimes grp->gr_type = GT_NET; 22931558Srgrimes *has_hostp = 1; 22941558Srgrimes usedarg++; 22951558Srgrimes opt_flags |= OP_NET; 22961558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 22971558Srgrimes opt_flags |= OP_ALLDIRS; 229827447Sdfr } else if (!strcmp(cpopt, "public")) { 229927447Sdfr *exflagsp |= MNT_EXPUBLIC; 230027447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 230127447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 230227447Sdfr opt_flags |= OP_MAPALL; 230327447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 230427447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2305100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2306100336Sjoerg opt_flags |= OP_QUIET; 2307247034Spluknet } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2308184588Sdfr if (parsesec(cpoptarg, ep)) 2309184588Sdfr return (1); 2310184588Sdfr opt_flags |= OP_SEC; 2311184588Sdfr usedarg++; 23121558Srgrimes } else { 231337663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 23141558Srgrimes return (1); 23151558Srgrimes } 23161558Srgrimes if (usedarg >= 0) { 23171558Srgrimes *endcp = savedc2; 23181558Srgrimes **endcpp = savedc; 23191558Srgrimes if (usedarg > 0) { 23201558Srgrimes *cpp = cp; 23211558Srgrimes *endcpp = endcp; 23221558Srgrimes } 23231558Srgrimes return (0); 23241558Srgrimes } 23251558Srgrimes cpopt = cpoptend; 23261558Srgrimes } 23271558Srgrimes **endcpp = savedc; 23281558Srgrimes return (0); 23291558Srgrimes} 23301558Srgrimes 23311558Srgrimes/* 23321558Srgrimes * Translate a character string to the corresponding list of network 23331558Srgrimes * addresses for a hostname. 23341558Srgrimes */ 2335285128Straszstatic int 2336216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 23371558Srgrimes{ 23387401Swpaul struct grouplist *checkgrp; 233975635Siedowse struct addrinfo *ai, *tai, hints; 234074462Salfred int ecode; 234174462Salfred char host[NI_MAXHOST]; 23421558Srgrimes 234374462Salfred if (grp->gr_type != GT_NULL) { 234474462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 23451558Srgrimes return (1); 23461558Srgrimes } 234774462Salfred memset(&hints, 0, sizeof hints); 234874462Salfred hints.ai_flags = AI_CANONNAME; 234974462Salfred hints.ai_protocol = IPPROTO_UDP; 235074462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 235174462Salfred if (ecode != 0) { 235275635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 235374462Salfred return 1; 235474462Salfred } 235574462Salfred grp->gr_ptr.gt_addrinfo = ai; 235674462Salfred while (ai != NULL) { 235774462Salfred if (ai->ai_canonname == NULL) { 235874462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2359146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 236074462Salfred strlcpy(host, "?", sizeof(host)); 236174462Salfred ai->ai_canonname = strdup(host); 236274462Salfred ai->ai_flags |= AI_CANONNAME; 236375641Siedowse } 236474462Salfred if (debug) 236575635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 236675635Siedowse /* 236775635Siedowse * Sanity check: make sure we don't already have an entry 236875635Siedowse * for this host in the grouplist. 236975635Siedowse */ 237075635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 237175635Siedowse checkgrp = checkgrp->gr_next) { 237275635Siedowse if (checkgrp->gr_type != GT_HOST) 237375635Siedowse continue; 237475635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 237575635Siedowse tai = tai->ai_next) { 237675801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 237775635Siedowse continue; 237875635Siedowse if (debug) 237975635Siedowse fprintf(stderr, 238075635Siedowse "ignoring duplicate host %s\n", 238175635Siedowse ai->ai_canonname); 238275635Siedowse grp->gr_type = GT_IGNORE; 238375635Siedowse return (0); 238475635Siedowse } 238575635Siedowse } 238674462Salfred ai = ai->ai_next; 23871558Srgrimes } 238875635Siedowse grp->gr_type = GT_HOST; 23891558Srgrimes return (0); 23901558Srgrimes} 23911558Srgrimes 23921558Srgrimes/* 23931558Srgrimes * Free up an exports list component 23941558Srgrimes */ 2395285128Straszstatic void 2396216587Scharnierfree_exp(struct exportlist *ep) 23971558Srgrimes{ 23981558Srgrimes 23991558Srgrimes if (ep->ex_defdir) { 24001558Srgrimes free_host(ep->ex_defdir->dp_hosts); 24011558Srgrimes free((caddr_t)ep->ex_defdir); 24021558Srgrimes } 24031558Srgrimes if (ep->ex_fsdir) 24041558Srgrimes free(ep->ex_fsdir); 240527447Sdfr if (ep->ex_indexfile) 240627447Sdfr free(ep->ex_indexfile); 24071558Srgrimes free_dir(ep->ex_dirl); 24081558Srgrimes free((caddr_t)ep); 24091558Srgrimes} 24101558Srgrimes 24111558Srgrimes/* 24121558Srgrimes * Free hosts. 24131558Srgrimes */ 2414285128Straszstatic void 2415216587Scharnierfree_host(struct hostlist *hp) 24161558Srgrimes{ 24171558Srgrimes struct hostlist *hp2; 24181558Srgrimes 24191558Srgrimes while (hp) { 24201558Srgrimes hp2 = hp; 24211558Srgrimes hp = hp->ht_next; 24221558Srgrimes free((caddr_t)hp2); 24231558Srgrimes } 24241558Srgrimes} 24251558Srgrimes 2426285128Straszstatic struct hostlist * 2427216587Scharnierget_ht(void) 24281558Srgrimes{ 24291558Srgrimes struct hostlist *hp; 24301558Srgrimes 24311558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 24321558Srgrimes if (hp == (struct hostlist *)NULL) 24331558Srgrimes out_of_mem(); 24341558Srgrimes hp->ht_next = (struct hostlist *)NULL; 24359336Sdfr hp->ht_flag = 0; 24361558Srgrimes return (hp); 24371558Srgrimes} 24381558Srgrimes 24391558Srgrimes/* 24401558Srgrimes * Out of memory, fatal 24411558Srgrimes */ 2442285128Straszstatic void 2443216587Scharnierout_of_mem(void) 24441558Srgrimes{ 24451558Srgrimes 244637663Scharnier syslog(LOG_ERR, "out of memory"); 24471558Srgrimes exit(2); 24481558Srgrimes} 24491558Srgrimes 24501558Srgrimes/* 2451158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 24521558Srgrimes * the kernel. 24531558Srgrimes */ 2454285128Straszstatic int 2455158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2456158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 24571558Srgrimes{ 245875841Siedowse struct statfs fsb1; 245974462Salfred struct addrinfo *ai; 2460282214Strasz struct export_args *eap; 2461158857Srodrigc char errmsg[255]; 2462158857Srodrigc char *cp; 24631558Srgrimes int done; 2464158857Srodrigc char savedc; 2465158857Srodrigc struct iovec *iov; 2466184588Sdfr int i, iovlen; 2467158857Srodrigc int ret; 2468192934Srmacklem struct nfsex_args nfsea; 24691558Srgrimes 2470282214Strasz eap = &nfsea.export; 2471192934Srmacklem 2472158857Srodrigc cp = NULL; 2473158857Srodrigc savedc = '\0'; 2474158857Srodrigc iov = NULL; 2475158857Srodrigc iovlen = 0; 2476158857Srodrigc ret = 0; 247775801Siedowse 2478192934Srmacklem bzero(eap, sizeof (struct export_args)); 2479158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2480192934Srmacklem eap->ex_flags = exflags; 2481192934Srmacklem eap->ex_anon = *anoncrp; 2482192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 248375641Siedowse if (grp->gr_type == GT_HOST) 248474462Salfred ai = grp->gr_ptr.gt_addrinfo; 248575641Siedowse else 248675641Siedowse ai = NULL; 2487192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2488192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2489192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2490192934Srmacklem if (eap->ex_numsecflavors == 0) { 2491192934Srmacklem eap->ex_numsecflavors = 1; 2492192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2493184588Sdfr } 24941558Srgrimes done = FALSE; 2495158857Srodrigc 2496192934Srmacklem if (v4root_phase == 0) { 2497192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2498192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2499192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2500192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2501192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2502192934Srmacklem sizeof (struct export_args)); 2503192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2504192934Srmacklem } 2505158857Srodrigc 25061558Srgrimes while (!done) { 25071558Srgrimes switch (grp->gr_type) { 25081558Srgrimes case GT_HOST: 250975641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 251074462Salfred goto skip; 2511192934Srmacklem eap->ex_addr = ai->ai_addr; 2512192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2513192934Srmacklem eap->ex_masklen = 0; 25141558Srgrimes break; 25151558Srgrimes case GT_NET: 251675801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 251774462Salfred have_v6 == 0) 251874462Salfred goto skip; 2519192934Srmacklem eap->ex_addr = 252075801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2521192934Srmacklem eap->ex_addrlen = 2522158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2523192934Srmacklem eap->ex_mask = 252475801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2525192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 25261558Srgrimes break; 252775641Siedowse case GT_DEFAULT: 2528192934Srmacklem eap->ex_addr = NULL; 2529192934Srmacklem eap->ex_addrlen = 0; 2530192934Srmacklem eap->ex_mask = NULL; 2531192934Srmacklem eap->ex_masklen = 0; 253275641Siedowse break; 25337401Swpaul case GT_IGNORE: 2534158857Srodrigc ret = 0; 2535158857Srodrigc goto error_exit; 25367401Swpaul break; 25371558Srgrimes default: 253837663Scharnier syslog(LOG_ERR, "bad grouptype"); 25391558Srgrimes if (cp) 25401558Srgrimes *cp = savedc; 2541158857Srodrigc ret = 1; 2542158857Srodrigc goto error_exit; 2543298089Spfg } 25441558Srgrimes 25451558Srgrimes /* 2546192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 25471558Srgrimes */ 2548192934Srmacklem if (v4root_phase == 2) { 2549192934Srmacklem nfsea.fspec = v4root_dirpath; 2550282214Strasz if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2551192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2552192934Srmacklem return (2); 2553158857Srodrigc } 2554192934Srmacklem } else { 2555192934Srmacklem /* 2556192934Srmacklem * XXX: 2557192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2558192934Srmacklem * instead of looping back up the dirp to the mount 2559192934Srmacklem * point?? 2560192934Srmacklem * Also, needs to know how to export all types of local 2561192934Srmacklem * exportable filesystems and not just "ufs". 2562192934Srmacklem */ 2563192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2564192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2565192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2566192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2567192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2568192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2569270183Sbdrewery errmsg[0] = '\0'; 2570192934Srmacklem 2571192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2572192934Srmacklem if (cp) 2573192934Srmacklem *cp-- = savedc; 2574192934Srmacklem else 2575192934Srmacklem cp = dirp + dirplen - 1; 2576192934Srmacklem if (opt_flags & OP_QUIET) { 2577192934Srmacklem ret = 1; 2578192934Srmacklem goto error_exit; 2579192934Srmacklem } 2580192934Srmacklem if (errno == EPERM) { 2581192934Srmacklem if (debug) 2582239744Sdelphij warnx("can't change attributes for %s: %s", 2583239744Sdelphij dirp, errmsg); 2584192934Srmacklem syslog(LOG_ERR, 2585239744Sdelphij "can't change attributes for %s: %s", 2586239744Sdelphij dirp, errmsg); 2587192934Srmacklem ret = 1; 2588192934Srmacklem goto error_exit; 2589192934Srmacklem } 2590192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2591192934Srmacklem if (errno == EINVAL) 2592192934Srmacklem syslog(LOG_ERR, 2593100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2594192934Srmacklem dirp); 2595192934Srmacklem else 2596192934Srmacklem syslog(LOG_ERR, 2597192934Srmacklem "could not remount %s: %m", 2598192934Srmacklem dirp); 2599192934Srmacklem ret = 1; 2600192934Srmacklem goto error_exit; 2601192934Srmacklem } 2602192934Srmacklem /* back up over the last component */ 2603192934Srmacklem while (*cp == '/' && cp > dirp) 2604192934Srmacklem cp--; 2605192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2606192934Srmacklem cp--; 2607192934Srmacklem if (cp == dirp) { 2608192934Srmacklem if (debug) 2609192934Srmacklem warnx("mnt unsucc"); 2610192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2611192934Srmacklem dirp, errmsg); 2612192934Srmacklem ret = 1; 2613192934Srmacklem goto error_exit; 2614192934Srmacklem } 2615192934Srmacklem savedc = *cp; 2616192934Srmacklem *cp = '\0'; 2617192934Srmacklem /* 2618192934Srmacklem * Check that we're still on the same 2619192934Srmacklem * filesystem. 2620192934Srmacklem */ 2621192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2622192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2623192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2624192934Srmacklem *cp = savedc; 2625100336Sjoerg syslog(LOG_ERR, 2626192934Srmacklem "can't export %s %s", dirp, 2627192934Srmacklem errmsg); 2628192934Srmacklem ret = 1; 2629192934Srmacklem goto error_exit; 2630192934Srmacklem } 26311558Srgrimes } 26321558Srgrimes } 2633192934Srmacklem 2634192934Srmacklem /* 2635192934Srmacklem * For the experimental server: 2636192934Srmacklem * If this is the public directory, get the file handle 2637192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2638192934Srmacklem */ 2639282214Strasz if ((exflags & MNT_EXPUBLIC) != 0) { 2640192934Srmacklem fhandle_t fh; 2641192934Srmacklem char *public_name; 2642192934Srmacklem 2643192934Srmacklem if (eap->ex_indexfile != NULL) 2644192934Srmacklem public_name = eap->ex_indexfile; 2645192934Srmacklem else 2646192934Srmacklem public_name = dirp; 2647192934Srmacklem if (getfh(public_name, &fh) < 0) 2648192934Srmacklem syslog(LOG_ERR, 2649192934Srmacklem "Can't get public fh for %s", public_name); 2650192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2651192934Srmacklem syslog(LOG_ERR, 2652192934Srmacklem "Can't set public fh for %s", public_name); 2653192934Srmacklem else 2654192934Srmacklem has_publicfh = 1; 2655192934Srmacklem } 265674462Salfredskip: 265775641Siedowse if (ai != NULL) 265874462Salfred ai = ai->ai_next; 265975641Siedowse if (ai == NULL) 26601558Srgrimes done = TRUE; 26611558Srgrimes } 26621558Srgrimes if (cp) 26631558Srgrimes *cp = savedc; 2664158857Srodrigcerror_exit: 2665158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2666158857Srodrigc if (iov != NULL) { 2667158857Srodrigc free(iov[0].iov_base); /* fstype */ 2668158857Srodrigc free(iov[2].iov_base); /* fspath */ 2669158857Srodrigc free(iov[4].iov_base); /* from */ 2670158857Srodrigc free(iov[6].iov_base); /* update */ 2671158857Srodrigc free(iov[8].iov_base); /* export */ 2672158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2673158857Srodrigc 2674158857Srodrigc /* free iov, allocated by realloc() */ 2675158857Srodrigc free(iov); 2676158857Srodrigc } 2677158857Srodrigc return (ret); 26781558Srgrimes} 26791558Srgrimes 26801558Srgrimes/* 26811558Srgrimes * Translate a net address. 268275801Siedowse * 268375801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 26841558Srgrimes */ 2685285128Straszstatic int 2686216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg) 26871558Srgrimes{ 268875861Siedowse struct netent *np = NULL; 268974462Salfred char *name, *p, *prefp; 269075801Siedowse struct sockaddr_in sin; 269175861Siedowse struct sockaddr *sa = NULL; 269274462Salfred struct addrinfo hints, *ai = NULL; 269374462Salfred char netname[NI_MAXHOST]; 269474462Salfred long preflen; 26951558Srgrimes 269675635Siedowse p = prefp = NULL; 269774462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 269874462Salfred p = strchr(cp, '/'); 269974462Salfred *p = '\0'; 270074462Salfred prefp = p + 1; 270174462Salfred } 270274462Salfred 270375861Siedowse /* 270475861Siedowse * Check for a numeric address first. We wish to avoid 270575861Siedowse * possible DNS lookups in getnetbyname(). 270675861Siedowse */ 270775861Siedowse if (isxdigit(*cp) || *cp == ':') { 270874462Salfred memset(&hints, 0, sizeof hints); 270975801Siedowse /* Ensure the mask and the network have the same family. */ 271075801Siedowse if (maskflg && (opt_flags & OP_NET)) 271175801Siedowse hints.ai_family = net->nt_net.ss_family; 271275801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 271375801Siedowse hints.ai_family = net->nt_mask.ss_family; 271475801Siedowse else 271575801Siedowse hints.ai_family = AF_UNSPEC; 271674462Salfred hints.ai_flags = AI_NUMERICHOST; 271775861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 271875861Siedowse sa = ai->ai_addr; 271975861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 272074462Salfred /* 272175801Siedowse * The address in `cp' is really a network address, so 272275801Siedowse * use inet_network() to re-interpret this correctly. 272375801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 272474462Salfred */ 272575801Siedowse bzero(&sin, sizeof sin); 272674462Salfred sin.sin_family = AF_INET; 272774462Salfred sin.sin_len = sizeof sin; 272875801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 272974462Salfred if (debug) 273075801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 273175801Siedowse inet_ntoa(sin.sin_addr)); 273274462Salfred sa = (struct sockaddr *)&sin; 273375861Siedowse } 273475861Siedowse } 273575861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 273675861Siedowse bzero(&sin, sizeof sin); 273775861Siedowse sin.sin_family = AF_INET; 273875861Siedowse sin.sin_len = sizeof sin; 273975861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 274075861Siedowse sa = (struct sockaddr *)&sin; 274175861Siedowse } 274275861Siedowse if (sa == NULL) 274374462Salfred goto fail; 274425318Spst 274575801Siedowse if (maskflg) { 274675801Siedowse /* The specified sockaddr is a mask. */ 274775801Siedowse if (checkmask(sa) != 0) 274875801Siedowse goto fail; 274975801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 275075801Siedowse opt_flags |= OP_HAVEMASK; 275175801Siedowse } else { 275275801Siedowse /* The specified sockaddr is a network address. */ 275375801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 275474462Salfred 275575801Siedowse /* Get a network name for the export list. */ 275675801Siedowse if (np) { 275775801Siedowse name = np->n_name; 275875801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2759146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 276075801Siedowse name = netname; 276175801Siedowse } else { 276275801Siedowse goto fail; 276375801Siedowse } 276475801Siedowse if ((net->nt_name = strdup(name)) == NULL) 276575801Siedowse out_of_mem(); 276675801Siedowse 276775801Siedowse /* 276875801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 276975801Siedowse * from the class of an IPv4 address. 277075801Siedowse */ 277174462Salfred if (opt_flags & OP_MASKLEN) { 277274462Salfred preflen = strtol(prefp, NULL, 10); 277375801Siedowse if (preflen < 0L || preflen == LONG_MAX) 277474462Salfred goto fail; 277575801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 277675801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 277775801Siedowse goto fail; 277875801Siedowse opt_flags |= OP_HAVEMASK; 277974462Salfred *p = '/'; 278075801Siedowse } else if (sa->sa_family == AF_INET && 278175801Siedowse (opt_flags & OP_MASK) == 0) { 278275801Siedowse in_addr_t addr; 278374462Salfred 278475801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 278575801Siedowse if (IN_CLASSA(addr)) 278675801Siedowse preflen = 8; 278775801Siedowse else if (IN_CLASSB(addr)) 278875801Siedowse preflen = 16; 278975801Siedowse else if (IN_CLASSC(addr)) 279075801Siedowse preflen = 24; 279175801Siedowse else if (IN_CLASSD(addr)) 279275801Siedowse preflen = 28; 279375801Siedowse else 279475801Siedowse preflen = 32; /* XXX */ 279575801Siedowse 279675801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 279775801Siedowse makemask(&net->nt_mask, (int)preflen); 279875801Siedowse opt_flags |= OP_HAVEMASK; 279974462Salfred } 280074462Salfred } 280174462Salfred 280274462Salfred if (ai) 280374462Salfred freeaddrinfo(ai); 280474462Salfred return 0; 280574462Salfred 280674462Salfredfail: 280774462Salfred if (ai) 280874462Salfred freeaddrinfo(ai); 280974462Salfred return 1; 28101558Srgrimes} 28111558Srgrimes 28121558Srgrimes/* 28131558Srgrimes * Parse out the next white space separated field 28141558Srgrimes */ 2815285128Straszstatic void 2816216587Scharniernextfield(char **cp, char **endcp) 28171558Srgrimes{ 28181558Srgrimes char *p; 28191558Srgrimes 28201558Srgrimes p = *cp; 28211558Srgrimes while (*p == ' ' || *p == '\t') 28221558Srgrimes p++; 28231558Srgrimes if (*p == '\n' || *p == '\0') 28241558Srgrimes *cp = *endcp = p; 28251558Srgrimes else { 28261558Srgrimes *cp = p++; 28271558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 28281558Srgrimes p++; 28291558Srgrimes *endcp = p; 28301558Srgrimes } 28311558Srgrimes} 28321558Srgrimes 28331558Srgrimes/* 28341558Srgrimes * Get an exports file line. Skip over blank lines and handle line 28351558Srgrimes * continuations. 28361558Srgrimes */ 2837285128Straszstatic int 2838216587Scharnierget_line(void) 28391558Srgrimes{ 28401558Srgrimes char *p, *cp; 284196622Siedowse size_t len; 28421558Srgrimes int totlen, cont_line; 28431558Srgrimes 28441558Srgrimes /* 28451558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 28461558Srgrimes */ 28471558Srgrimes p = line; 28481558Srgrimes totlen = 0; 28491558Srgrimes do { 285096622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 28511558Srgrimes return (0); 28521558Srgrimes cp = p + len - 1; 28531558Srgrimes cont_line = 0; 28541558Srgrimes while (cp >= p && 28551558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 28561558Srgrimes if (*cp == '\\') 28571558Srgrimes cont_line = 1; 28581558Srgrimes cp--; 28591558Srgrimes len--; 28601558Srgrimes } 286179117Sdd if (cont_line) { 286279117Sdd *++cp = ' '; 286379117Sdd len++; 286479117Sdd } 286596622Siedowse if (linesize < len + totlen + 1) { 286696622Siedowse linesize = len + totlen + 1; 286796622Siedowse line = realloc(line, linesize); 286896622Siedowse if (line == NULL) 286996622Siedowse out_of_mem(); 28701558Srgrimes } 287196622Siedowse memcpy(line + totlen, p, len); 287296622Siedowse totlen += len; 287396622Siedowse line[totlen] = '\0'; 28741558Srgrimes } while (totlen == 0 || cont_line); 28751558Srgrimes return (1); 28761558Srgrimes} 28771558Srgrimes 28781558Srgrimes/* 28791558Srgrimes * Parse a description of a credential. 28801558Srgrimes */ 2881285128Straszstatic void 2882216587Scharnierparsecred(char *namelist, struct xucred *cr) 28831558Srgrimes{ 28841558Srgrimes char *name; 28851558Srgrimes int cnt; 28861558Srgrimes char *names; 28871558Srgrimes struct passwd *pw; 28881558Srgrimes struct group *gr; 2889194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2890136051Sstefanf int ngroups; 28911558Srgrimes 289291354Sdd cr->cr_version = XUCRED_VERSION; 28931558Srgrimes /* 289437663Scharnier * Set up the unprivileged user. 28951558Srgrimes */ 28961558Srgrimes cr->cr_uid = -2; 28971558Srgrimes cr->cr_groups[0] = -2; 28981558Srgrimes cr->cr_ngroups = 1; 28991558Srgrimes /* 29001558Srgrimes * Get the user's password table entry. 29011558Srgrimes */ 2902293305Sjpaetzel names = strsep_quote(&namelist, " \t\n"); 29031558Srgrimes name = strsep(&names, ":"); 2904293305Sjpaetzel /* Bug? name could be NULL here */ 29051558Srgrimes if (isdigit(*name) || *name == '-') 29061558Srgrimes pw = getpwuid(atoi(name)); 29071558Srgrimes else 29081558Srgrimes pw = getpwnam(name); 29091558Srgrimes /* 29101558Srgrimes * Credentials specified as those of a user. 29111558Srgrimes */ 29121558Srgrimes if (names == NULL) { 29131558Srgrimes if (pw == NULL) { 291437663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 29151558Srgrimes return; 29161558Srgrimes } 29171558Srgrimes cr->cr_uid = pw->pw_uid; 2918194498Sbrooks ngroups = XU_NGROUPS + 1; 29191558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 292037663Scharnier syslog(LOG_ERR, "too many groups"); 29211558Srgrimes /* 2922136051Sstefanf * Compress out duplicate. 29231558Srgrimes */ 29241558Srgrimes cr->cr_ngroups = ngroups - 1; 29251558Srgrimes cr->cr_groups[0] = groups[0]; 29261558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 29271558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 29281558Srgrimes return; 29291558Srgrimes } 29301558Srgrimes /* 29311558Srgrimes * Explicit credential specified as a colon separated list: 29321558Srgrimes * uid:gid:gid:... 29331558Srgrimes */ 29341558Srgrimes if (pw != NULL) 29351558Srgrimes cr->cr_uid = pw->pw_uid; 29361558Srgrimes else if (isdigit(*name) || *name == '-') 29371558Srgrimes cr->cr_uid = atoi(name); 29381558Srgrimes else { 293937663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 29401558Srgrimes return; 29411558Srgrimes } 29421558Srgrimes cr->cr_ngroups = 0; 2943194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 29441558Srgrimes name = strsep(&names, ":"); 29451558Srgrimes if (isdigit(*name) || *name == '-') { 29461558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 29471558Srgrimes } else { 29481558Srgrimes if ((gr = getgrnam(name)) == NULL) { 294937663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 29501558Srgrimes continue; 29511558Srgrimes } 29521558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 29531558Srgrimes } 29541558Srgrimes } 2955194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 295637663Scharnier syslog(LOG_ERR, "too many groups"); 29571558Srgrimes} 29581558Srgrimes 2959194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 29601558Srgrimes/* 29611558Srgrimes * Routines that maintain the remote mounttab 29621558Srgrimes */ 2963285128Straszstatic void 2964216587Scharnierget_mountlist(void) 29651558Srgrimes{ 29661558Srgrimes struct mountlist *mlp, **mlpp; 296723681Speter char *host, *dirp, *cp; 29681558Srgrimes char str[STRSIZ]; 29691558Srgrimes FILE *mlfile; 29701558Srgrimes 29711558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 297253117Sbillf if (errno == ENOENT) 297353117Sbillf return; 297453117Sbillf else { 297553117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 297653117Sbillf return; 297753117Sbillf } 29781558Srgrimes } 29791558Srgrimes mlpp = &mlhead; 29801558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 298123681Speter cp = str; 298223681Speter host = strsep(&cp, " \t\n"); 298323681Speter dirp = strsep(&cp, " \t\n"); 298423681Speter if (host == NULL || dirp == NULL) 29851558Srgrimes continue; 29861558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 298737663Scharnier if (mlp == (struct mountlist *)NULL) 298837663Scharnier out_of_mem(); 2989194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 2990194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2991194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2992194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 29931558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 29941558Srgrimes *mlpp = mlp; 29951558Srgrimes mlpp = &mlp->ml_next; 29961558Srgrimes } 29971558Srgrimes fclose(mlfile); 29981558Srgrimes} 29991558Srgrimes 3000285128Straszstatic void 300175635Siedowsedel_mlist(char *hostp, char *dirp) 30021558Srgrimes{ 30031558Srgrimes struct mountlist *mlp, **mlpp; 30041558Srgrimes struct mountlist *mlp2; 30051558Srgrimes FILE *mlfile; 30061558Srgrimes int fnd = 0; 30071558Srgrimes 30081558Srgrimes mlpp = &mlhead; 30091558Srgrimes mlp = mlhead; 30101558Srgrimes while (mlp) { 30111558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 30121558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 30131558Srgrimes fnd = 1; 30141558Srgrimes mlp2 = mlp; 30151558Srgrimes *mlpp = mlp = mlp->ml_next; 30161558Srgrimes free((caddr_t)mlp2); 30171558Srgrimes } else { 30181558Srgrimes mlpp = &mlp->ml_next; 30191558Srgrimes mlp = mlp->ml_next; 30201558Srgrimes } 30211558Srgrimes } 30221558Srgrimes if (fnd) { 30231558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 302437663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 30251558Srgrimes return; 30261558Srgrimes } 30271558Srgrimes mlp = mlhead; 30281558Srgrimes while (mlp) { 30291558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30301558Srgrimes mlp = mlp->ml_next; 30311558Srgrimes } 30321558Srgrimes fclose(mlfile); 30331558Srgrimes } 30341558Srgrimes} 30351558Srgrimes 3036285128Straszstatic void 3037216587Scharnieradd_mlist(char *hostp, char *dirp) 30381558Srgrimes{ 30391558Srgrimes struct mountlist *mlp, **mlpp; 30401558Srgrimes FILE *mlfile; 30411558Srgrimes 30421558Srgrimes mlpp = &mlhead; 30431558Srgrimes mlp = mlhead; 30441558Srgrimes while (mlp) { 30451558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 30461558Srgrimes return; 30471558Srgrimes mlpp = &mlp->ml_next; 30481558Srgrimes mlp = mlp->ml_next; 30491558Srgrimes } 30501558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 305137663Scharnier if (mlp == (struct mountlist *)NULL) 305237663Scharnier out_of_mem(); 3053194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 3054194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 3055194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 3056194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 30571558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 30581558Srgrimes *mlpp = mlp; 30591558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 306037663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 30611558Srgrimes return; 30621558Srgrimes } 30631558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30641558Srgrimes fclose(mlfile); 30651558Srgrimes} 30661558Srgrimes 30671558Srgrimes/* 30681558Srgrimes * Free up a group list. 30691558Srgrimes */ 3070285128Straszstatic void 3071216587Scharnierfree_grp(struct grouplist *grp) 30721558Srgrimes{ 30731558Srgrimes if (grp->gr_type == GT_HOST) { 307474462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 307574462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 30761558Srgrimes } else if (grp->gr_type == GT_NET) { 30771558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 30781558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 30791558Srgrimes } 30801558Srgrimes free((caddr_t)grp); 30811558Srgrimes} 30821558Srgrimes 30831558Srgrimes#ifdef DEBUG 3084285128Straszstatic void 30851558SrgrimesSYSLOG(int pri, const char *fmt, ...) 30861558Srgrimes{ 30871558Srgrimes va_list ap; 30881558Srgrimes 30891558Srgrimes va_start(ap, fmt); 30901558Srgrimes vfprintf(stderr, fmt, ap); 30911558Srgrimes va_end(ap); 30921558Srgrimes} 30931558Srgrimes#endif /* DEBUG */ 30941558Srgrimes 30951558Srgrimes/* 30961558Srgrimes * Check options for consistency. 30971558Srgrimes */ 3098285128Straszstatic int 3099216587Scharniercheck_options(struct dirlist *dp) 31001558Srgrimes{ 31011558Srgrimes 3102192934Srmacklem if (v4root_phase == 0 && dp == NULL) 31031558Srgrimes return (1); 310483653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 310583653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 31061558Srgrimes return (1); 31071558Srgrimes } 31081558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 310975801Siedowse syslog(LOG_ERR, "-mask requires -network"); 311075801Siedowse return (1); 31111558Srgrimes } 311275801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 311375801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 311475801Siedowse return (1); 311575801Siedowse } 311675801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 311775801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 311875801Siedowse return (1); 311975801Siedowse } 3120192934Srmacklem if (v4root_phase > 0 && 3121192934Srmacklem (opt_flags & 3122192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3123192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3124192934Srmacklem return (1); 3125192934Srmacklem } 3126207689Srmacklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 3127207689Srmacklem syslog(LOG_ERR, "-alldirs has multiple directories"); 3128207689Srmacklem return (1); 3129207689Srmacklem } 31301558Srgrimes return (0); 31311558Srgrimes} 31321558Srgrimes 31331558Srgrimes/* 31341558Srgrimes * Check an absolute directory path for any symbolic links. Return true 31351558Srgrimes */ 3136285128Straszstatic int 3137216587Scharniercheck_dirpath(char *dirp) 31381558Srgrimes{ 31391558Srgrimes char *cp; 31401558Srgrimes int ret = 1; 31411558Srgrimes struct stat sb; 31421558Srgrimes 31431558Srgrimes cp = dirp + 1; 31441558Srgrimes while (*cp && ret) { 31451558Srgrimes if (*cp == '/') { 31461558Srgrimes *cp = '\0'; 31479336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31481558Srgrimes ret = 0; 31491558Srgrimes *cp = '/'; 31501558Srgrimes } 31511558Srgrimes cp++; 31521558Srgrimes } 31539336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31541558Srgrimes ret = 0; 31551558Srgrimes return (ret); 31561558Srgrimes} 31579336Sdfr 315875801Siedowse/* 315975801Siedowse * Make a netmask according to the specified prefix length. The ss_family 316075801Siedowse * and other non-address fields must be initialised before calling this. 316175801Siedowse */ 3162285128Straszstatic int 316375801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 316474462Salfred{ 316575801Siedowse u_char *p; 316675801Siedowse int bits, i, len; 316774462Salfred 316875801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 316975801Siedowse return (-1); 3170103949Smike if (bitlen > len * CHAR_BIT) 317175801Siedowse return (-1); 317274462Salfred 317375801Siedowse for (i = 0; i < len; i++) { 3174298912Saraujo bits = MIN(CHAR_BIT, bitlen); 3175219125Sru *p++ = (u_char)~0 << (CHAR_BIT - bits); 317675801Siedowse bitlen -= bits; 317774462Salfred } 317875801Siedowse return 0; 317974462Salfred} 318074462Salfred 318175801Siedowse/* 318275801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 318375801Siedowse * is acceptable (i.e. of the form 1...10....0). 318475801Siedowse */ 3185285128Straszstatic int 318675801Siedowsecheckmask(struct sockaddr *sa) 318774462Salfred{ 318875801Siedowse u_char *mask; 318975801Siedowse int i, len; 319074462Salfred 319175801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 319275801Siedowse return (-1); 319375801Siedowse 319475801Siedowse for (i = 0; i < len; i++) 319575801Siedowse if (mask[i] != 0xff) 319675801Siedowse break; 319775801Siedowse if (i < len) { 319875801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 319975801Siedowse return (-1); 320075801Siedowse i++; 320174462Salfred } 320275801Siedowse for (; i < len; i++) 320375801Siedowse if (mask[i] != 0) 320475801Siedowse return (-1); 320575801Siedowse return (0); 320674462Salfred} 320774462Salfred 320875801Siedowse/* 320975801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 321075801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 3211228990Suqs * If samask is NULL, perform a full comparison. 321275801Siedowse */ 3213285128Straszstatic int 321475801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 321574462Salfred{ 321675801Siedowse unsigned char *p1, *p2, *mask; 321775801Siedowse int len, i; 321874462Salfred 321975801Siedowse if (sa1->sa_family != sa2->sa_family || 322075801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 322175801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 322275801Siedowse return (1); 322375801Siedowse 322475801Siedowse switch (sa1->sa_family) { 322574462Salfred case AF_INET6: 322675801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 322775801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 322875801Siedowse return (1); 322974462Salfred break; 323074462Salfred } 323174462Salfred 323275801Siedowse /* Simple binary comparison if no mask specified. */ 323375801Siedowse if (samask == NULL) 323475801Siedowse return (memcmp(p1, p2, len)); 323574462Salfred 323675801Siedowse /* Set up the mask, and do a mask-based comparison. */ 323775801Siedowse if (sa1->sa_family != samask->sa_family || 323875801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 323975801Siedowse return (1); 324074462Salfred 324175801Siedowse for (i = 0; i < len; i++) 324275801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 324375801Siedowse return (1); 324475801Siedowse return (0); 324574462Salfred} 324674462Salfred 324775801Siedowse/* 324875801Siedowse * Return a pointer to the part of the sockaddr that contains the 324975801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 325075801Siedowse * NULL if the address family is unknown. 325175801Siedowse */ 3252285128Straszstatic void * 325375801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 325475801Siedowse void *p; 325574462Salfred int len; 325674462Salfred 325775801Siedowse switch (sa->sa_family) { 325874462Salfred case AF_INET: 325975801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 326075801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 326174462Salfred break; 326274462Salfred case AF_INET6: 326375801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 326475801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 326574462Salfred break; 326674462Salfred default: 326775801Siedowse p = NULL; 326875801Siedowse len = 0; 326974462Salfred } 327074462Salfred 327175801Siedowse if (nbytes != NULL) 327275801Siedowse *nbytes = len; 327375801Siedowse return (p); 327474462Salfred} 327574462Salfred 3276285128Straszstatic void 3277216587Scharnierhuphandler(int sig __unused) 327875754Siedowse{ 3279285128Strasz 328075754Siedowse got_sighup = 1; 328175754Siedowse} 328275754Siedowse 3283285128Straszstatic void 3284285128Straszterminate(int sig __unused) 328574462Salfred{ 3286149433Spjd pidfile_remove(pfh); 3287194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3288194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 328974462Salfred exit (0); 329074462Salfred} 3291