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: stable/10/usr.sbin/mountd/mountd.c 333198 2018-05-03 07:28:49Z avg $"); 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 */ 16892882Simpchar *add_expdir(struct dirlist **, char *, int); 16992882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 170240902Srmacklem struct grouplist *, int, struct exportlist *); 17192882Simpvoid add_mlist(char *, char *); 17292882Simpint check_dirpath(char *); 17392882Simpint check_options(struct dirlist *); 17475801Siedowseint checkmask(struct sockaddr *sa); 175240902Srmacklemint chk_host(struct dirlist *, struct sockaddr *, int *, int *, int *, 176240902Srmacklem int **); 177294124Sjpaetzelstatic 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); 18175635Siedowsevoid del_mlist(char *hostp, char *dirp); 18292882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 18392882Simpint do_mount(struct exportlist *, struct grouplist *, int, 18492882Simp struct xucred *, char *, int, struct statfs *); 18592882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 18692882Simp int *, int *, struct xucred *); 18792882Simpstruct exportlist *ex_search(fsid_t *); 18892882Simpstruct exportlist *get_exp(void); 18992882Simpvoid free_dir(struct dirlist *); 19092882Simpvoid free_exp(struct exportlist *); 19192882Simpvoid free_grp(struct grouplist *); 19292882Simpvoid free_host(struct hostlist *); 19392882Simpvoid get_exportlist(void); 19492882Simpint get_host(char *, struct grouplist *, struct grouplist *); 19592882Simpstruct hostlist *get_ht(void); 19692882Simpint get_line(void); 19792882Simpvoid get_mountlist(void); 19892882Simpint get_net(char *, struct netmsk *, int); 19992882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 20092882Simpstruct grouplist *get_grp(void); 20192882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 20292882Simp struct exportlist *, int); 20375754Siedowsevoid huphandler(int sig); 20475801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 20592882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 20692882Simpvoid nextfield(char **, char **); 20792882Simpvoid out_of_mem(void); 20892882Simpvoid parsecred(char *, struct xucred *); 209216587Scharnierint parsesec(char *, struct exportlist *); 210100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 21175801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 21275801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 21375801Siedowse struct sockaddr *samask); 21492882Simpint scan_tree(struct dirlist *, struct sockaddr *); 21592882Simpstatic void usage(void); 21692882Simpint xdr_dir(XDR *, char *); 21792882Simpint xdr_explist(XDR *, caddr_t); 218100117Salfredint xdr_explist_brief(XDR *, caddr_t); 219216587Scharnierint xdr_explist_common(XDR *, caddr_t, int); 22092882Simpint xdr_fhs(XDR *, caddr_t); 22192882Simpint xdr_mlist(XDR *, caddr_t); 22292882Simpvoid terminate(int); 2231558Srgrimes 2241558Srgrimesstruct exportlist *exphead; 2251558Srgrimesstruct mountlist *mlhead; 2261558Srgrimesstruct grouplist *grphead; 227166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 228166440Spjdchar **exnames; 229172827Smatteochar **hosts = NULL; 23072650Sgreenstruct xucred def_anon = { 23191354Sdd XUCRED_VERSION, 23272650Sgreen (uid_t)-2, 2331558Srgrimes 1, 23472650Sgreen { (gid_t)-2 }, 23572650Sgreen NULL 2361558Srgrimes}; 23725087Sdfrint force_v2 = 0; 2389336Sdfrint resvport_only = 1; 239172827Smatteoint nhosts = 0; 2409336Sdfrint dir_only = 1; 241121767Speterint dolog = 0; 24275754Siedowseint got_sighup = 0; 243172827Smatteoint xcreated = 0; 24474462Salfred 245172827Smatteochar *svcport_str = NULL; 246222623Srmacklemstatic int mallocd_svcport = 0; 247222623Srmacklemstatic int *sock_fd; 248222623Srmacklemstatic int sock_fdcnt; 249222623Srmacklemstatic int sock_fdpos; 250241568Srmacklemstatic int suspend_nfsd = 0; 251172827Smatteo 2521558Srgrimesint opt_flags; 25374462Salfredstatic int have_v6 = 1; 25474462Salfred 255192934Srmacklemint v4root_phase = 0; 256192934Srmacklemchar v4root_dirpath[PATH_MAX + 1]; 257220980Srmacklemint run_v4server = 1; 258192934Srmacklemint has_publicfh = 0; 259192934Srmacklem 260149433Spjdstruct 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 2741558Srgrimesint debug = 1; 27592882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2761558Srgrimes#define syslog SYSLOG 2771558Srgrimes#else 2781558Srgrimesint debug = 0; 2791558Srgrimes#endif 2801558Srgrimes 2811558Srgrimes/* 282294124Sjpaetzel * Similar to strsep(), but it allows for quoted strings 283294124Sjpaetzel * and escaped characters. 284294124Sjpaetzel * 285294124Sjpaetzel * It returns the string (or NULL, if *stringp is NULL), 286294124Sjpaetzel * which is a de-quoted version of the string if necessary. 287294124Sjpaetzel * 288294124Sjpaetzel * It modifies *stringp in place. 289294124Sjpaetzel */ 290294124Sjpaetzelstatic char * 291294124Sjpaetzelstrsep_quote(char **stringp, const char *delim) 292294124Sjpaetzel{ 293294124Sjpaetzel char *srcptr, *dstptr, *retval; 294294124Sjpaetzel char quot = 0; 295294124Sjpaetzel 296294124Sjpaetzel if (stringp == NULL || *stringp == NULL) 297294124Sjpaetzel return (NULL); 298294124Sjpaetzel 299294124Sjpaetzel srcptr = dstptr = retval = *stringp; 300294124Sjpaetzel 301294124Sjpaetzel while (*srcptr) { 302294124Sjpaetzel /* 303294124Sjpaetzel * We're looking for several edge cases here. 304294124Sjpaetzel * First: if we're in quote state (quot != 0), 305294124Sjpaetzel * then we ignore the delim characters, but otherwise 306294124Sjpaetzel * process as normal, unless it is the quote character. 307294124Sjpaetzel * Second: if the current character is a backslash, 308294124Sjpaetzel * we take the next character as-is, without checking 309294124Sjpaetzel * for delim, quote, or backslash. Exception: if the 310294124Sjpaetzel * next character is a NUL, that's the end of the string. 311294124Sjpaetzel * Third: if the character is a quote character, we toggle 312294124Sjpaetzel * quote state. 313294124Sjpaetzel * Otherwise: check the current character for NUL, or 314294124Sjpaetzel * being in delim, and end the string if either is true. 315294124Sjpaetzel */ 316294124Sjpaetzel if (*srcptr == '\\') { 317294124Sjpaetzel srcptr++; 318294124Sjpaetzel /* 319294124Sjpaetzel * The edge case here is if the next character 320294124Sjpaetzel * is NUL, we want to stop processing. But if 321294124Sjpaetzel * it's not NUL, then we simply want to copy it. 322294124Sjpaetzel */ 323294124Sjpaetzel if (*srcptr) { 324294124Sjpaetzel *dstptr++ = *srcptr++; 325294124Sjpaetzel } 326294124Sjpaetzel continue; 327294124Sjpaetzel } 328294124Sjpaetzel if (quot == 0 && (*srcptr == '\'' || *srcptr == '"')) { 329294124Sjpaetzel quot = *srcptr++; 330294124Sjpaetzel continue; 331294124Sjpaetzel } 332294124Sjpaetzel if (quot && *srcptr == quot) { 333294124Sjpaetzel /* End of the quoted part */ 334294124Sjpaetzel quot = 0; 335294124Sjpaetzel srcptr++; 336294124Sjpaetzel continue; 337294124Sjpaetzel } 338294124Sjpaetzel if (!quot && strchr(delim, *srcptr)) 339294124Sjpaetzel break; 340294124Sjpaetzel *dstptr++ = *srcptr++; 341294124Sjpaetzel } 342294124Sjpaetzel 343294124Sjpaetzel *dstptr = 0; /* Terminate the string */ 344294124Sjpaetzel *stringp = (*srcptr == '\0') ? NULL : srcptr + 1; 345294124Sjpaetzel return (retval); 346294124Sjpaetzel} 347294124Sjpaetzel 348294124Sjpaetzel/* 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 383241568Srmacklem while ((c = getopt(argc, argv, "2deh:lnop: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; 403220980Srmacklem case 'o': 404220980Srmacklem run_v4server = 0; 405220980Srmacklem break; 406126572Sbms case 'p': 407126572Sbms endptr = NULL; 408126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 409126572Sbms if (endptr == NULL || *endptr != '\0' || 410126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 411126572Sbms usage(); 412172827Smatteo svcport_str = strdup(optarg); 413126572Sbms break; 414172827Smatteo case 'h': 415172827Smatteo ++nhosts; 416172827Smatteo hosts_bak = hosts; 417172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 418172827Smatteo if (hosts_bak == NULL) { 419172827Smatteo if (hosts != NULL) { 420172827Smatteo for (k = 0; k < nhosts; k++) 421172827Smatteo free(hosts[k]); 422172827Smatteo free(hosts); 423172827Smatteo out_of_mem(); 424172827Smatteo } 425172827Smatteo } 426172827Smatteo hosts = hosts_bak; 427172827Smatteo hosts[nhosts - 1] = strdup(optarg); 428172827Smatteo if (hosts[nhosts - 1] == NULL) { 429172827Smatteo for (k = 0; k < (nhosts - 1); k++) 430172827Smatteo free(hosts[k]); 431172827Smatteo free(hosts); 432172827Smatteo out_of_mem(); 433172827Smatteo } 434172827Smatteo break; 435241568Srmacklem case 'S': 436241568Srmacklem suspend_nfsd = 1; 437241568Srmacklem break; 4381558Srgrimes default: 43937663Scharnier usage(); 4401558Srgrimes }; 441192934Srmacklem 442192934Srmacklem /* 443220980Srmacklem * Unless the "-o" option was specified, try and run "nfsd". 444220980Srmacklem * If "-o" was specified, try and run "nfsserver". 445192934Srmacklem */ 446192934Srmacklem if (run_v4server > 0) { 447192934Srmacklem if (modfind("nfsd") < 0) { 448192934Srmacklem /* Not present in kernel, try loading it */ 449192934Srmacklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 450192934Srmacklem errx(1, "NFS server is not available"); 451192934Srmacklem } 452192934Srmacklem } else if (modfind("nfsserver") < 0) { 453192934Srmacklem /* Not present in kernel, try loading it */ 454192934Srmacklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 455192934Srmacklem errx(1, "NFS server is not available"); 456192934Srmacklem } 457192934Srmacklem 4581558Srgrimes argc -= optind; 4591558Srgrimes argv += optind; 4601558Srgrimes grphead = (struct grouplist *)NULL; 4611558Srgrimes exphead = (struct exportlist *)NULL; 4621558Srgrimes mlhead = (struct mountlist *)NULL; 463166440Spjd if (argc > 0) 464166440Spjd exnames = argv; 465166440Spjd else 466166440Spjd exnames = exnames_default; 4671558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 4681558Srgrimes if (debug) 46937663Scharnier warnx("getting export list"); 4701558Srgrimes get_exportlist(); 4711558Srgrimes if (debug) 47237663Scharnier warnx("getting mount list"); 4731558Srgrimes get_mountlist(); 4741558Srgrimes if (debug) 47537663Scharnier warnx("here we go"); 4761558Srgrimes if (debug == 0) { 4771558Srgrimes daemon(0, 0); 4781558Srgrimes signal(SIGINT, SIG_IGN); 4791558Srgrimes signal(SIGQUIT, SIG_IGN); 4801558Srgrimes } 48175754Siedowse signal(SIGHUP, huphandler); 48274462Salfred signal(SIGTERM, terminate); 483164394Srodrigc signal(SIGPIPE, SIG_IGN); 484149433Spjd 485149433Spjd pidfile_write(pfh); 486149433Spjd 487194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 488194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 489109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 490109363Smbr 49124759Sguido if (!resvport_only) { 492308452Srmacklem if (run_v4server != 0) { 493308452Srmacklem if (sysctlbyname("vfs.nfsd.nfs_privport", NULL, NULL, 494308452Srmacklem &resvport_only, sizeof(resvport_only)) != 0 && 495308452Srmacklem errno != ENOENT) { 496308452Srmacklem syslog(LOG_ERR, "sysctl: %m"); 497308452Srmacklem exit(1); 498308452Srmacklem } 499308452Srmacklem } else { 500308452Srmacklem if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 501308452Srmacklem &resvport_only, sizeof(resvport_only)) != 0 && 502308452Srmacklem errno != ENOENT) { 503308452Srmacklem syslog(LOG_ERR, "sysctl: %m"); 504308452Srmacklem exit(1); 505308452Srmacklem } 50624759Sguido } 50724330Sguido } 508126572Sbms 509172827Smatteo /* 510172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 511172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 512172827Smatteo * list. 513172827Smatteo */ 514172827Smatteo if (nhosts == 0) { 515172827Smatteo hosts = malloc(sizeof(char**)); 516172827Smatteo if (hosts == NULL) 517172827Smatteo out_of_mem(); 518172827Smatteo hosts[0] = "*"; 519172827Smatteo nhosts = 1; 520172827Smatteo } else { 521172827Smatteo hosts_bak = hosts; 522172827Smatteo if (have_v6) { 523172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 524172827Smatteo sizeof(char *)); 525172827Smatteo if (hosts_bak == NULL) { 526172827Smatteo for (k = 0; k < nhosts; k++) 527172827Smatteo free(hosts[k]); 528172827Smatteo free(hosts); 529172827Smatteo out_of_mem(); 530172827Smatteo } else 531172827Smatteo hosts = hosts_bak; 532172827Smatteo nhosts += 2; 533172827Smatteo hosts[nhosts - 2] = "::1"; 534172827Smatteo } else { 535172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 536172827Smatteo if (hosts_bak == NULL) { 537172827Smatteo for (k = 0; k < nhosts; k++) 538172827Smatteo free(hosts[k]); 539172827Smatteo free(hosts); 540172827Smatteo out_of_mem(); 541172827Smatteo } else { 542172827Smatteo nhosts += 1; 543172827Smatteo hosts = hosts_bak; 544126572Sbms } 545172827Smatteo } 54674462Salfred 547172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 54874462Salfred } 54974462Salfred 550222623Srmacklem attempt_cnt = 1; 551222623Srmacklem sock_fdcnt = 0; 552222623Srmacklem sock_fd = NULL; 553222623Srmacklem port_list = NULL; 554222623Srmacklem port_len = 0; 555172827Smatteo nc_handle = setnetconfig(); 556172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 557172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 558172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 559172827Smatteo "inet6") == 0) { 560172827Smatteo /* DO NOTHING */ 561222623Srmacklem } else { 562222623Srmacklem ret = create_service(nconf); 563222623Srmacklem if (ret == 1) 564222623Srmacklem /* Ignore this call */ 565222623Srmacklem continue; 566222623Srmacklem if (ret < 0) { 567222623Srmacklem /* 568222623Srmacklem * Failed to bind port, so close off 569222623Srmacklem * all sockets created and try again 570222623Srmacklem * if the port# was dynamically 571222623Srmacklem * assigned via bind(2). 572222623Srmacklem */ 573222623Srmacklem clearout_service(); 574222623Srmacklem if (mallocd_svcport != 0 && 575222623Srmacklem attempt_cnt < GETPORT_MAXTRY) { 576222623Srmacklem free(svcport_str); 577222623Srmacklem svcport_str = NULL; 578222623Srmacklem mallocd_svcport = 0; 579222623Srmacklem } else { 580222623Srmacklem errno = EADDRINUSE; 581222623Srmacklem syslog(LOG_ERR, 582222623Srmacklem "bindresvport_sa: %m"); 583222623Srmacklem exit(1); 584222623Srmacklem } 585222623Srmacklem 586222623Srmacklem /* Start over at the first service. */ 587222623Srmacklem free(sock_fd); 588222623Srmacklem sock_fdcnt = 0; 589222623Srmacklem sock_fd = NULL; 590222623Srmacklem nc_handle = setnetconfig(); 591222623Srmacklem attempt_cnt++; 592222623Srmacklem } else if (mallocd_svcport != 0 && 593222623Srmacklem attempt_cnt == GETPORT_MAXTRY) { 594222623Srmacklem /* 595222623Srmacklem * For the last attempt, allow 596222623Srmacklem * different port #s for each nconf 597222623Srmacklem * by saving the svcport_str and 598222623Srmacklem * setting it back to NULL. 599222623Srmacklem */ 600222623Srmacklem port_list = realloc(port_list, 601222623Srmacklem (port_len + 1) * sizeof(char *)); 602222623Srmacklem if (port_list == NULL) 603222623Srmacklem out_of_mem(); 604222623Srmacklem port_list[port_len++] = svcport_str; 605222623Srmacklem svcport_str = NULL; 606222623Srmacklem mallocd_svcport = 0; 607222623Srmacklem } 608222623Srmacklem } 609222623Srmacklem } 610222623Srmacklem } 611222623Srmacklem 612222623Srmacklem /* 613222623Srmacklem * Successfully bound the ports, so call complete_service() to 614222623Srmacklem * do the rest of the setup on the service(s). 615222623Srmacklem */ 616222623Srmacklem sock_fdpos = 0; 617222623Srmacklem port_pos = 0; 618222623Srmacklem nc_handle = setnetconfig(); 619222623Srmacklem while ((nconf = getnetconfig(nc_handle))) { 620222623Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 621222623Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 622222623Srmacklem "inet6") == 0) { 623222623Srmacklem /* DO NOTHING */ 624222623Srmacklem } else if (port_list != NULL) { 625222623Srmacklem if (port_pos >= port_len) { 626222623Srmacklem syslog(LOG_ERR, "too many port#s"); 627222623Srmacklem exit(1); 628222623Srmacklem } 629222623Srmacklem complete_service(nconf, port_list[port_pos++]); 630172827Smatteo } else 631222623Srmacklem complete_service(nconf, svcport_str); 632172827Smatteo } 63374462Salfred } 634172827Smatteo endnetconfig(nc_handle); 635222623Srmacklem free(sock_fd); 636222623Srmacklem if (port_list != NULL) { 637222623Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 638222623Srmacklem free(port_list[port_pos]); 639222623Srmacklem free(port_list); 640222623Srmacklem } 64174462Salfred 64274462Salfred if (xcreated == 0) { 64374462Salfred syslog(LOG_ERR, "could not create any services"); 6441558Srgrimes exit(1); 6451558Srgrimes } 64675754Siedowse 64775754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 64875754Siedowse for (;;) { 64975754Siedowse if (got_sighup) { 65075754Siedowse get_exportlist(); 65175754Siedowse got_sighup = 0; 65275754Siedowse } 65375754Siedowse readfds = svc_fdset; 65475754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 65575754Siedowse case -1: 65675754Siedowse if (errno == EINTR) 65775754Siedowse continue; 65875754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 65975754Siedowse exit(1); 66075754Siedowse case 0: 66175754Siedowse continue; 66275754Siedowse default: 66375754Siedowse svc_getreqset(&readfds); 66475754Siedowse } 66575754Siedowse } 666172827Smatteo} 667172827Smatteo 668172827Smatteo/* 669172827Smatteo * This routine creates and binds sockets on the appropriate 670222623Srmacklem * addresses. It gets called one time for each transport. 671222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 672222623Srmacklem * bind failed with EADDRINUSE. 673222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and 674222623Srmacklem * the total count of them is maintained in sock_fdcnt. 675172827Smatteo */ 676222623Srmacklemstatic int 677172827Smatteocreate_service(struct netconfig *nconf) 678172827Smatteo{ 679172827Smatteo struct addrinfo hints, *res = NULL; 680172827Smatteo struct sockaddr_in *sin; 681172827Smatteo struct sockaddr_in6 *sin6; 682172827Smatteo struct __rpc_sockinfo si; 683172827Smatteo int aicode; 684172827Smatteo int fd; 685172827Smatteo int nhostsbak; 686172827Smatteo int one = 1; 687172827Smatteo int r; 688172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 689222623Srmacklem int mallocd_res; 690172827Smatteo 691172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 692172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 693172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 694222623Srmacklem return (1); /* not my type */ 695172827Smatteo 696172827Smatteo /* 697172827Smatteo * XXX - using RPC library internal functions. 698172827Smatteo */ 699172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 700172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 701172827Smatteo nconf->nc_netid); 702222623Srmacklem return (1); 703172827Smatteo } 704172827Smatteo 705172827Smatteo /* Get mountd's address on this transport */ 706172827Smatteo memset(&hints, 0, sizeof hints); 707172827Smatteo hints.ai_family = si.si_af; 708172827Smatteo hints.ai_socktype = si.si_socktype; 709172827Smatteo hints.ai_protocol = si.si_proto; 710172827Smatteo 711172827Smatteo /* 712172827Smatteo * Bind to specific IPs if asked to 713172827Smatteo */ 714172827Smatteo nhostsbak = nhosts; 715172827Smatteo while (nhostsbak > 0) { 716172827Smatteo --nhostsbak; 717222623Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 718222623Srmacklem if (sock_fd == NULL) 719222623Srmacklem out_of_mem(); 720222623Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 721222623Srmacklem mallocd_res = 0; 722222623Srmacklem 723277859Srstone hints.ai_flags = AI_PASSIVE; 724277859Srstone 725172827Smatteo /* 726172827Smatteo * XXX - using RPC library internal functions. 727172827Smatteo */ 728172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 729172827Smatteo int non_fatal = 0; 730244538Skevlo if (errno == EAFNOSUPPORT && 731172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 732172827Smatteo non_fatal = 1; 733172827Smatteo 734172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 735172827Smatteo "cannot create socket for %s", nconf->nc_netid); 736222623Srmacklem if (non_fatal != 0) 737222623Srmacklem continue; 738222623Srmacklem exit(1); 739172827Smatteo } 740172827Smatteo 741172827Smatteo switch (hints.ai_family) { 742172827Smatteo case AF_INET: 743172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 744172827Smatteo host_addr) == 1) { 745222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 746172827Smatteo } else { 747172827Smatteo /* 748172827Smatteo * Skip if we have an AF_INET6 address. 749172827Smatteo */ 750172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 751172827Smatteo host_addr) == 1) { 752172827Smatteo close(fd); 753172827Smatteo continue; 754172827Smatteo } 755172827Smatteo } 756172827Smatteo break; 757172827Smatteo case AF_INET6: 758172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 759172827Smatteo host_addr) == 1) { 760222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 761172827Smatteo } else { 762172827Smatteo /* 763172827Smatteo * Skip if we have an AF_INET address. 764172827Smatteo */ 765172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 766172827Smatteo host_addr) == 1) { 767172827Smatteo close(fd); 768172827Smatteo continue; 769172827Smatteo } 770172827Smatteo } 771172827Smatteo 772172827Smatteo /* 773172827Smatteo * We're doing host-based access checks here, so don't 774172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 775172827Smatteo * disable it by default on NFS sockets too. 776172827Smatteo */ 777172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 778172827Smatteo sizeof one) < 0) { 779172827Smatteo syslog(LOG_ERR, 780172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 781172827Smatteo exit(1); 782172827Smatteo } 783172827Smatteo break; 784172827Smatteo default: 785172827Smatteo break; 786172827Smatteo } 787172827Smatteo 788172827Smatteo /* 789172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 790172827Smatteo */ 791172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 792172827Smatteo if (svcport_str == NULL) { 793172827Smatteo res = malloc(sizeof(struct addrinfo)); 794172827Smatteo if (res == NULL) 795172827Smatteo out_of_mem(); 796222623Srmacklem mallocd_res = 1; 797172827Smatteo res->ai_flags = hints.ai_flags; 798172827Smatteo res->ai_family = hints.ai_family; 799172827Smatteo res->ai_protocol = hints.ai_protocol; 800172827Smatteo switch (res->ai_family) { 801172827Smatteo case AF_INET: 802172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 803172827Smatteo if (sin == NULL) 804172827Smatteo out_of_mem(); 805172827Smatteo sin->sin_family = AF_INET; 806172827Smatteo sin->sin_port = htons(0); 807172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 808172827Smatteo res->ai_addr = (struct sockaddr*) sin; 809172827Smatteo res->ai_addrlen = (socklen_t) 810222623Srmacklem sizeof(struct sockaddr_in); 811172827Smatteo break; 812172827Smatteo case AF_INET6: 813172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 814173056Ssimon if (sin6 == NULL) 815172827Smatteo out_of_mem(); 816172827Smatteo sin6->sin6_family = AF_INET6; 817172827Smatteo sin6->sin6_port = htons(0); 818172827Smatteo sin6->sin6_addr = in6addr_any; 819172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 820172827Smatteo res->ai_addrlen = (socklen_t) 821222623Srmacklem sizeof(struct sockaddr_in6); 822222623Srmacklem break; 823172827Smatteo default: 824222623Srmacklem syslog(LOG_ERR, "bad addr fam %d", 825222623Srmacklem res->ai_family); 826222623Srmacklem exit(1); 827172827Smatteo } 828172827Smatteo } else { 829172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 830172827Smatteo &hints, &res)) != 0) { 831172827Smatteo syslog(LOG_ERR, 832172827Smatteo "cannot get local address for %s: %s", 833172827Smatteo nconf->nc_netid, 834172827Smatteo gai_strerror(aicode)); 835222623Srmacklem close(fd); 836172827Smatteo continue; 837172827Smatteo } 838172827Smatteo } 839172827Smatteo } else { 840172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 841172827Smatteo &hints, &res)) != 0) { 842172827Smatteo syslog(LOG_ERR, 843172827Smatteo "cannot get local address for %s: %s", 844172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 845222623Srmacklem close(fd); 846172827Smatteo continue; 847172827Smatteo } 848172827Smatteo } 849172827Smatteo 850222623Srmacklem /* Store the fd. */ 851222623Srmacklem sock_fd[sock_fdcnt - 1] = fd; 852222623Srmacklem 853222623Srmacklem /* Now, attempt the bind. */ 854172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 855172827Smatteo if (r != 0) { 856222623Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 857222623Srmacklem if (mallocd_res != 0) { 858222623Srmacklem free(res->ai_addr); 859222623Srmacklem free(res); 860222623Srmacklem } else 861222623Srmacklem freeaddrinfo(res); 862222623Srmacklem return (-1); 863222623Srmacklem } 864172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 865172827Smatteo exit(1); 866172827Smatteo } 867172827Smatteo 868222623Srmacklem if (svcport_str == NULL) { 869222623Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 870222623Srmacklem if (svcport_str == NULL) 871222623Srmacklem out_of_mem(); 872222623Srmacklem mallocd_svcport = 1; 873222623Srmacklem 874222623Srmacklem if (getnameinfo(res->ai_addr, 875222623Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 876222623Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 877222623Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 878222623Srmacklem errx(1, "Cannot get port number"); 879222623Srmacklem } 880222623Srmacklem if (mallocd_res != 0) { 881222623Srmacklem free(res->ai_addr); 882222623Srmacklem free(res); 883222623Srmacklem } else 884222623Srmacklem freeaddrinfo(res); 885222623Srmacklem res = NULL; 886222623Srmacklem } 887222623Srmacklem return (0); 888222623Srmacklem} 889222623Srmacklem 890222623Srmacklem/* 891222623Srmacklem * Called after all the create_service() calls have succeeded, to complete 892222623Srmacklem * the setup and registration. 893222623Srmacklem */ 894222623Srmacklemstatic void 895222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 896222623Srmacklem{ 897222623Srmacklem struct addrinfo hints, *res = NULL; 898222623Srmacklem struct __rpc_sockinfo si; 899222623Srmacklem struct netbuf servaddr; 900222623Srmacklem SVCXPRT *transp = NULL; 901222623Srmacklem int aicode, fd, nhostsbak; 902222623Srmacklem int registered = 0; 903222623Srmacklem 904222623Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 905222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 906222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 907222623Srmacklem return; /* not my type */ 908222623Srmacklem 909222623Srmacklem /* 910222623Srmacklem * XXX - using RPC library internal functions. 911222623Srmacklem */ 912222623Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 913222623Srmacklem syslog(LOG_ERR, "cannot get information for %s", 914222623Srmacklem nconf->nc_netid); 915222623Srmacklem return; 916222623Srmacklem } 917222623Srmacklem 918222623Srmacklem nhostsbak = nhosts; 919222623Srmacklem while (nhostsbak > 0) { 920222623Srmacklem --nhostsbak; 921222623Srmacklem if (sock_fdpos >= sock_fdcnt) { 922222623Srmacklem /* Should never happen. */ 923222623Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 924222623Srmacklem return; 925222623Srmacklem } 926222623Srmacklem fd = sock_fd[sock_fdpos++]; 927222623Srmacklem if (fd < 0) 928222623Srmacklem continue; 929222623Srmacklem 930172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 931172827Smatteo listen(fd, SOMAXCONN); 932172827Smatteo 933172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 934172827Smatteo transp = svc_dg_create(fd, 0, 0); 935172827Smatteo else 936172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 937172827Smatteo RPC_MAXDATASIZE); 938172827Smatteo 939172827Smatteo if (transp != (SVCXPRT *) NULL) { 940194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 941172827Smatteo NULL)) 942172827Smatteo syslog(LOG_ERR, 943194880Sdfr "can't register %s MOUNTVERS service", 944172827Smatteo nconf->nc_netid); 945172827Smatteo if (!force_v2) { 946194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 947172827Smatteo mntsrv, NULL)) 948172827Smatteo syslog(LOG_ERR, 949194880Sdfr "can't register %s MOUNTVERS3 service", 950172827Smatteo nconf->nc_netid); 951172827Smatteo } 952172827Smatteo } else 953172827Smatteo syslog(LOG_WARNING, "can't create %s services", 954172827Smatteo nconf->nc_netid); 955172827Smatteo 956172827Smatteo if (registered == 0) { 957172827Smatteo registered = 1; 958172827Smatteo memset(&hints, 0, sizeof hints); 959172827Smatteo hints.ai_flags = AI_PASSIVE; 960172827Smatteo hints.ai_family = si.si_af; 961172827Smatteo hints.ai_socktype = si.si_socktype; 962172827Smatteo hints.ai_protocol = si.si_proto; 963172827Smatteo 964222623Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 965172827Smatteo &res)) != 0) { 966172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 967172827Smatteo gai_strerror(aicode)); 968172827Smatteo exit(1); 969172827Smatteo } 970172827Smatteo 971172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 972172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 973172827Smatteo servaddr.len = res->ai_addrlen; 974172827Smatteo 975194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 976194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 977172827Smatteo 978172827Smatteo xcreated++; 979172827Smatteo freeaddrinfo(res); 980172827Smatteo } 981172827Smatteo } /* end while */ 9821558Srgrimes} 9831558Srgrimes 984222623Srmacklem/* 985222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the 986222623Srmacklem * cycle of socket creation/binding can start anew. 987222623Srmacklem */ 98837663Scharnierstatic void 989222623Srmacklemclearout_service(void) 990222623Srmacklem{ 991222623Srmacklem int i; 992222623Srmacklem 993222623Srmacklem for (i = 0; i < sock_fdcnt; i++) { 994222623Srmacklem if (sock_fd[i] >= 0) { 995222623Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 996222623Srmacklem close(sock_fd[i]); 997222623Srmacklem } 998222623Srmacklem } 999222623Srmacklem} 1000222623Srmacklem 1001222623Srmacklemstatic void 1002216587Scharnierusage(void) 100337663Scharnier{ 100437663Scharnier fprintf(stderr, 1005192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 1006241568Srmacklem "[-S] [-h <bindip>] [export_file ...]\n"); 100737663Scharnier exit(1); 100837663Scharnier} 100937663Scharnier 10101558Srgrimes/* 10111558Srgrimes * The mount rpc service 10121558Srgrimes */ 10131558Srgrimesvoid 1014216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp) 10151558Srgrimes{ 10161558Srgrimes struct exportlist *ep; 10171558Srgrimes struct dirlist *dp; 10189336Sdfr struct fhreturn fhr; 10191558Srgrimes struct stat stb; 10201558Srgrimes struct statfs fsb; 102174462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 102274462Salfred int lookup_failed = 1; 102374462Salfred struct sockaddr *saddr; 10249336Sdfr u_short sport; 1025194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 102628911Sguido int bad = 0, defset, hostset; 10279336Sdfr sigset_t sighup_mask; 1028240902Srmacklem int numsecflavors, *secflavorsp; 10291558Srgrimes 10309336Sdfr sigemptyset(&sighup_mask); 10319336Sdfr sigaddset(&sighup_mask, SIGHUP); 103274462Salfred saddr = svc_getrpccaller(transp)->buf; 103374462Salfred switch (saddr->sa_family) { 103474462Salfred case AF_INET6: 103575635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 103674462Salfred break; 103774462Salfred case AF_INET: 103875635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 103974462Salfred break; 104074462Salfred default: 104174462Salfred syslog(LOG_ERR, "request from unknown address family"); 104274462Salfred return; 104374462Salfred } 104474462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 104574462Salfred NULL, 0, 0); 104674462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 104774462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 10481558Srgrimes switch (rqstp->rq_proc) { 10491558Srgrimes case NULLPROC: 1050121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 105137663Scharnier syslog(LOG_ERR, "can't send reply"); 10521558Srgrimes return; 1053194880Sdfr case MOUNTPROC_MNT: 10549336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 105531656Sguido syslog(LOG_NOTICE, 105631656Sguido "mount request from %s from unprivileged port", 105774462Salfred numerichost); 10581558Srgrimes svcerr_weakauth(transp); 10591558Srgrimes return; 10601558Srgrimes } 1061121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 106231656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 106374462Salfred numerichost); 10641558Srgrimes svcerr_decode(transp); 10651558Srgrimes return; 10661558Srgrimes } 10671558Srgrimes 10681558Srgrimes /* 10691558Srgrimes * Get the real pathname and make sure it is a directory 10709336Sdfr * or a regular file if the -r option was specified 10719336Sdfr * and it exists. 10721558Srgrimes */ 107351968Salfred if (realpath(rpcpath, dirpath) == NULL || 10741558Srgrimes stat(dirpath, &stb) < 0 || 10751558Srgrimes statfs(dirpath, &fsb) < 0) { 10761558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 107731656Sguido syslog(LOG_NOTICE, 107837663Scharnier "mount request from %s for non existent path %s", 107974462Salfred numerichost, dirpath); 10801558Srgrimes if (debug) 108137663Scharnier warnx("stat failed on %s", dirpath); 108228911Sguido bad = ENOENT; /* We will send error reply later */ 10831558Srgrimes } 1084330093Srpokala if (!bad && 1085330093Srpokala !S_ISDIR(stb.st_mode) && 1086330093Srpokala (dir_only || !S_ISREG(stb.st_mode))) { 1087330093Srpokala syslog(LOG_NOTICE, 1088330093Srpokala "mount request from %s for non-directory path %s", 1089330093Srpokala numerichost, dirpath); 1090330093Srpokala if (debug) 1091330093Srpokala warnx("mounting non-directory %s", dirpath); 1092330093Srpokala bad = ENOTDIR; /* We will send error reply later */ 1093330093Srpokala } 10941558Srgrimes 10951558Srgrimes /* Check in the exports list */ 10969336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1097330093Srpokala if (bad) 1098330093Srpokala ep = NULL; 1099330093Srpokala else 1100330093Srpokala ep = ex_search(&fsb.f_fsid); 11019336Sdfr hostset = defset = 0; 1102240902Srmacklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1103240902Srmacklem &numsecflavors, &secflavorsp) || 11041558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1105240902Srmacklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1106240902Srmacklem &secflavorsp)) || 110774462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 110874462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 110928911Sguido if (bad) { 1110121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 111128911Sguido (caddr_t)&bad)) 111237663Scharnier syslog(LOG_ERR, "can't send reply"); 111328911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 111428911Sguido return; 111528911Sguido } 1116240902Srmacklem if (hostset & DP_HOSTSET) { 11179336Sdfr fhr.fhr_flag = hostset; 1118240902Srmacklem fhr.fhr_numsecflavors = numsecflavors; 1119240902Srmacklem fhr.fhr_secflavors = secflavorsp; 1120240902Srmacklem } else { 11219336Sdfr fhr.fhr_flag = defset; 1122240902Srmacklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1123240902Srmacklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1124240902Srmacklem } 11259336Sdfr fhr.fhr_vers = rqstp->rq_vers; 11261558Srgrimes /* Get the file handle */ 112723681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 11289336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 11291558Srgrimes bad = errno; 113037663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1131121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 11321558Srgrimes (caddr_t)&bad)) 113337663Scharnier syslog(LOG_ERR, "can't send reply"); 11349336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11351558Srgrimes return; 11361558Srgrimes } 1137121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1138121556Speter (caddr_t)&fhr)) 113937663Scharnier syslog(LOG_ERR, "can't send reply"); 114074462Salfred if (!lookup_failed) 114174462Salfred add_mlist(host, dirpath); 11421558Srgrimes else 114374462Salfred add_mlist(numerichost, dirpath); 11441558Srgrimes if (debug) 114537663Scharnier warnx("mount successful"); 1146121767Speter if (dolog) 114731656Sguido syslog(LOG_NOTICE, 114831656Sguido "mount request succeeded from %s for %s", 114974462Salfred numerichost, dirpath); 115031656Sguido } else { 1151330093Srpokala if (!bad) 1152330093Srpokala bad = EACCES; 115331656Sguido syslog(LOG_NOTICE, 115431656Sguido "mount request denied from %s for %s", 115574462Salfred numerichost, dirpath); 115631656Sguido } 115728911Sguido 1158121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1159121556Speter (caddr_t)&bad)) 116037663Scharnier syslog(LOG_ERR, "can't send reply"); 11619336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 11621558Srgrimes return; 1163194880Sdfr case MOUNTPROC_DUMP: 1164121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 116537663Scharnier syslog(LOG_ERR, "can't send reply"); 1166121767Speter else if (dolog) 116731656Sguido syslog(LOG_NOTICE, 116831656Sguido "dump request succeeded from %s", 116974462Salfred numerichost); 11701558Srgrimes return; 1171194880Sdfr case MOUNTPROC_UMNT: 11729336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 117331656Sguido syslog(LOG_NOTICE, 117431656Sguido "umount request from %s from unprivileged port", 117574462Salfred numerichost); 11761558Srgrimes svcerr_weakauth(transp); 11771558Srgrimes return; 11781558Srgrimes } 1179121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 118031656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 118174462Salfred numerichost); 11821558Srgrimes svcerr_decode(transp); 11831558Srgrimes return; 11841558Srgrimes } 118551968Salfred if (realpath(rpcpath, dirpath) == NULL) { 118651968Salfred syslog(LOG_NOTICE, "umount request from %s " 118751968Salfred "for non existent path %s", 118874462Salfred numerichost, dirpath); 118951968Salfred } 1190121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 119137663Scharnier syslog(LOG_ERR, "can't send reply"); 119274462Salfred if (!lookup_failed) 119375635Siedowse del_mlist(host, dirpath); 119475635Siedowse del_mlist(numerichost, dirpath); 1195121767Speter if (dolog) 119631656Sguido syslog(LOG_NOTICE, 119731656Sguido "umount request succeeded from %s for %s", 119874462Salfred numerichost, dirpath); 11991558Srgrimes return; 1200194880Sdfr case MOUNTPROC_UMNTALL: 12019336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 120231656Sguido syslog(LOG_NOTICE, 120331656Sguido "umountall request from %s from unprivileged port", 120474462Salfred numerichost); 12051558Srgrimes svcerr_weakauth(transp); 12061558Srgrimes return; 12071558Srgrimes } 1208121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 120937663Scharnier syslog(LOG_ERR, "can't send reply"); 121074462Salfred if (!lookup_failed) 121175635Siedowse del_mlist(host, NULL); 121275635Siedowse del_mlist(numerichost, NULL); 1213121767Speter if (dolog) 121431656Sguido syslog(LOG_NOTICE, 121531656Sguido "umountall request succeeded from %s", 121674462Salfred numerichost); 12171558Srgrimes return; 1218194880Sdfr case MOUNTPROC_EXPORT: 1219121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1220121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1221121556Speter (caddr_t)NULL)) 1222100117Salfred syslog(LOG_ERR, "can't send reply"); 1223121767Speter if (dolog) 122431656Sguido syslog(LOG_NOTICE, 122531656Sguido "export request succeeded from %s", 122674462Salfred numerichost); 12271558Srgrimes return; 12281558Srgrimes default: 12291558Srgrimes svcerr_noproc(transp); 12301558Srgrimes return; 12311558Srgrimes } 12321558Srgrimes} 12331558Srgrimes 12341558Srgrimes/* 12351558Srgrimes * Xdr conversion for a dirpath string 12361558Srgrimes */ 12371558Srgrimesint 1238216587Scharnierxdr_dir(XDR *xdrsp, char *dirp) 12391558Srgrimes{ 1240194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 12411558Srgrimes} 12421558Srgrimes 12431558Srgrimes/* 12449336Sdfr * Xdr routine to generate file handle reply 12451558Srgrimes */ 12461558Srgrimesint 1247216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp) 12481558Srgrimes{ 124992806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 12509336Sdfr u_long ok = 0, len, auth; 1251184588Sdfr int i; 12521558Srgrimes 12531558Srgrimes if (!xdr_long(xdrsp, &ok)) 12541558Srgrimes return (0); 12559336Sdfr switch (fhrp->fhr_vers) { 12569336Sdfr case 1: 12579336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 12589336Sdfr case 3: 12599336Sdfr len = NFSX_V3FH; 12609336Sdfr if (!xdr_long(xdrsp, &len)) 12619336Sdfr return (0); 12629336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 12639336Sdfr return (0); 1264184588Sdfr if (fhrp->fhr_numsecflavors) { 1265184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1266184588Sdfr return (0); 1267184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1268184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1269184588Sdfr return (0); 1270184588Sdfr return (1); 1271184588Sdfr } else { 1272184588Sdfr auth = AUTH_SYS; 1273184588Sdfr len = 1; 1274184588Sdfr if (!xdr_long(xdrsp, &len)) 1275184588Sdfr return (0); 1276184588Sdfr return (xdr_long(xdrsp, &auth)); 1277184588Sdfr } 12789336Sdfr }; 12799336Sdfr return (0); 12801558Srgrimes} 12811558Srgrimes 12821558Srgrimesint 1283216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 12841558Srgrimes{ 12851558Srgrimes struct mountlist *mlp; 12861558Srgrimes int true = 1; 12871558Srgrimes int false = 0; 12881558Srgrimes char *strp; 12891558Srgrimes 12901558Srgrimes mlp = mlhead; 12911558Srgrimes while (mlp) { 12921558Srgrimes if (!xdr_bool(xdrsp, &true)) 12931558Srgrimes return (0); 12941558Srgrimes strp = &mlp->ml_host[0]; 1295194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 12961558Srgrimes return (0); 12971558Srgrimes strp = &mlp->ml_dirp[0]; 1298194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12991558Srgrimes return (0); 13001558Srgrimes mlp = mlp->ml_next; 13011558Srgrimes } 13021558Srgrimes if (!xdr_bool(xdrsp, &false)) 13031558Srgrimes return (0); 13041558Srgrimes return (1); 13051558Srgrimes} 13061558Srgrimes 13071558Srgrimes/* 13081558Srgrimes * Xdr conversion for export list 13091558Srgrimes */ 13101558Srgrimesint 1311216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 13121558Srgrimes{ 13131558Srgrimes struct exportlist *ep; 13141558Srgrimes int false = 0; 13159336Sdfr int putdef; 13169336Sdfr sigset_t sighup_mask; 13171558Srgrimes 13189336Sdfr sigemptyset(&sighup_mask); 13199336Sdfr sigaddset(&sighup_mask, SIGHUP); 13209336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 13211558Srgrimes ep = exphead; 13221558Srgrimes while (ep) { 13231558Srgrimes putdef = 0; 1324100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1325100117Salfred &putdef, brief)) 13261558Srgrimes goto errout; 13271558Srgrimes if (ep->ex_defdir && putdef == 0 && 13281558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1329100117Salfred &putdef, brief)) 13301558Srgrimes goto errout; 13311558Srgrimes ep = ep->ex_next; 13321558Srgrimes } 13339336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13341558Srgrimes if (!xdr_bool(xdrsp, &false)) 13351558Srgrimes return (0); 13361558Srgrimes return (1); 13371558Srgrimeserrout: 13389336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 13391558Srgrimes return (0); 13401558Srgrimes} 13411558Srgrimes 13421558Srgrimes/* 13431558Srgrimes * Called from xdr_explist() to traverse the tree and export the 13441558Srgrimes * directory paths. 13451558Srgrimes */ 13461558Srgrimesint 1347216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1348216587Scharnier int brief) 13491558Srgrimes{ 13501558Srgrimes struct grouplist *grp; 13511558Srgrimes struct hostlist *hp; 13521558Srgrimes int true = 1; 13531558Srgrimes int false = 0; 13541558Srgrimes int gotalldir = 0; 13551558Srgrimes char *strp; 13561558Srgrimes 13571558Srgrimes if (dp) { 1358100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 13591558Srgrimes return (1); 13601558Srgrimes if (!xdr_bool(xdrsp, &true)) 13611558Srgrimes return (1); 13621558Srgrimes strp = dp->dp_dirp; 1363194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 13641558Srgrimes return (1); 13651558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 13661558Srgrimes gotalldir = 1; 13671558Srgrimes *putdefp = 1; 13681558Srgrimes } 1369100117Salfred if (brief) { 1370100117Salfred if (!xdr_bool(xdrsp, &true)) 1371100117Salfred return (1); 1372100117Salfred strp = "(...)"; 1373194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1374100117Salfred return (1); 1375100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 13761558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 13771558Srgrimes hp = dp->dp_hosts; 13781558Srgrimes while (hp) { 13791558Srgrimes grp = hp->ht_grp; 13801558Srgrimes if (grp->gr_type == GT_HOST) { 13811558Srgrimes if (!xdr_bool(xdrsp, &true)) 13821558Srgrimes return (1); 138374462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 13848871Srgrimes if (!xdr_string(xdrsp, &strp, 1385194880Sdfr MNTNAMLEN)) 13861558Srgrimes return (1); 13871558Srgrimes } else if (grp->gr_type == GT_NET) { 13881558Srgrimes if (!xdr_bool(xdrsp, &true)) 13891558Srgrimes return (1); 13901558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 13918871Srgrimes if (!xdr_string(xdrsp, &strp, 1392194880Sdfr MNTNAMLEN)) 13931558Srgrimes return (1); 13941558Srgrimes } 13951558Srgrimes hp = hp->ht_next; 13961558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 13971558Srgrimes hp = adp->dp_hosts; 13981558Srgrimes gotalldir = 0; 13991558Srgrimes } 14001558Srgrimes } 14011558Srgrimes } 14021558Srgrimes if (!xdr_bool(xdrsp, &false)) 14031558Srgrimes return (1); 1404100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 14051558Srgrimes return (1); 14061558Srgrimes } 14071558Srgrimes return (0); 14081558Srgrimes} 14091558Srgrimes 1410100117Salfredint 1411216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp) 1412100117Salfred{ 1413100117Salfred 1414100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1415100117Salfred} 1416100117Salfred 1417100117Salfredint 1418216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1419100117Salfred{ 1420100117Salfred 1421100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1422100117Salfred} 1423100117Salfred 142496622Siedowsechar *line; 142596622Siedowseint linesize; 14261558SrgrimesFILE *exp_file; 14271558Srgrimes 14281558Srgrimes/* 1429166440Spjd * Get the export list from one, currently open file 14301558Srgrimes */ 1431166440Spjdstatic void 1432216587Scharnierget_exportlist_one(void) 14331558Srgrimes{ 14341558Srgrimes struct exportlist *ep, *ep2; 14351558Srgrimes struct grouplist *grp, *tgrp; 14361558Srgrimes struct exportlist **epp; 14371558Srgrimes struct dirlist *dirhead; 1438166440Spjd struct statfs fsb; 143972650Sgreen struct xucred anon; 14401558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1441166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 14421558Srgrimes 1443192934Srmacklem v4root_phase = 0; 14441558Srgrimes dirhead = (struct dirlist *)NULL; 14451558Srgrimes while (get_line()) { 14461558Srgrimes if (debug) 144737663Scharnier warnx("got line %s", line); 14481558Srgrimes cp = line; 14491558Srgrimes nextfield(&cp, &endcp); 14501558Srgrimes if (*cp == '#') 14511558Srgrimes goto nextline; 14521558Srgrimes 14531558Srgrimes /* 14541558Srgrimes * Set defaults. 14551558Srgrimes */ 14561558Srgrimes has_host = FALSE; 14571558Srgrimes anon = def_anon; 14581558Srgrimes exflags = MNT_EXPORTED; 14591558Srgrimes got_nondir = 0; 14601558Srgrimes opt_flags = 0; 14611558Srgrimes ep = (struct exportlist *)NULL; 1462192934Srmacklem dirp = NULL; 14631558Srgrimes 14641558Srgrimes /* 1465192934Srmacklem * Handle the V4 root dir. 1466192934Srmacklem */ 1467192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1468192934Srmacklem /* 1469192934Srmacklem * V4: just indicates that it is the v4 root point, 1470192934Srmacklem * so skip over that and set v4root_phase. 1471192934Srmacklem */ 1472192934Srmacklem if (v4root_phase > 0) { 1473192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1474192934Srmacklem goto nextline; 1475192934Srmacklem } 1476192934Srmacklem v4root_phase = 1; 1477192934Srmacklem cp += 3; 1478192934Srmacklem nextfield(&cp, &endcp); 1479192934Srmacklem } 1480192934Srmacklem 1481192934Srmacklem /* 14821558Srgrimes * Create new exports list entry 14831558Srgrimes */ 14841558Srgrimes len = endcp-cp; 14851558Srgrimes tgrp = grp = get_grp(); 14861558Srgrimes while (len > 0) { 1487194880Sdfr if (len > MNTNAMLEN) { 14881558Srgrimes getexp_err(ep, tgrp); 14891558Srgrimes goto nextline; 14901558Srgrimes } 14911558Srgrimes if (*cp == '-') { 14921558Srgrimes if (ep == (struct exportlist *)NULL) { 14931558Srgrimes getexp_err(ep, tgrp); 14941558Srgrimes goto nextline; 14951558Srgrimes } 14961558Srgrimes if (debug) 149737663Scharnier warnx("doing opt %s", cp); 14981558Srgrimes got_nondir = 1; 14991558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 15001558Srgrimes &exflags, &anon)) { 15011558Srgrimes getexp_err(ep, tgrp); 15021558Srgrimes goto nextline; 15031558Srgrimes } 15041558Srgrimes } else if (*cp == '/') { 15051558Srgrimes savedc = *endcp; 15061558Srgrimes *endcp = '\0'; 1507192934Srmacklem if (v4root_phase > 1) { 1508192934Srmacklem if (dirp != NULL) { 1509192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 1510192934Srmacklem getexp_err(ep, tgrp); 1511192934Srmacklem goto nextline; 1512192934Srmacklem } 1513192934Srmacklem } 15141558Srgrimes if (check_dirpath(cp) && 15151558Srgrimes statfs(cp, &fsb) >= 0) { 1516283762Srmacklem if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) 1517283762Srmacklem syslog(LOG_ERR, "Warning: exporting of " 1518283762Srmacklem "automounted fs %s not supported", cp); 15191558Srgrimes if (got_nondir) { 152037663Scharnier syslog(LOG_ERR, "dirs must be first"); 15211558Srgrimes getexp_err(ep, tgrp); 15221558Srgrimes goto nextline; 15231558Srgrimes } 1524192934Srmacklem if (v4root_phase == 1) { 1525192934Srmacklem if (dirp != NULL) { 1526192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 15271558Srgrimes getexp_err(ep, tgrp); 15281558Srgrimes goto nextline; 15291558Srgrimes } 1530192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1531192934Srmacklem strlcpy(v4root_dirpath, cp, 1532192934Srmacklem sizeof (v4root_dirpath)); 1533192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1534192934Srmacklem != 0) { 1535192934Srmacklem syslog(LOG_ERR, 1536192934Srmacklem "different V4 dirpath %s", cp); 1537192934Srmacklem getexp_err(ep, tgrp); 1538192934Srmacklem goto nextline; 1539192934Srmacklem } 1540192934Srmacklem dirp = cp; 1541192934Srmacklem v4root_phase = 2; 1542192934Srmacklem got_nondir = 1; 1543192934Srmacklem ep = get_exp(); 15441558Srgrimes } else { 1545192934Srmacklem if (ep) { 1546192934Srmacklem if (ep->ex_fs.val[0] != 1547192934Srmacklem fsb.f_fsid.val[0] || 1548192934Srmacklem ep->ex_fs.val[1] != 1549192934Srmacklem fsb.f_fsid.val[1]) { 1550192934Srmacklem getexp_err(ep, tgrp); 1551192934Srmacklem goto nextline; 1552192934Srmacklem } 1553192934Srmacklem } else { 1554192934Srmacklem /* 1555192934Srmacklem * See if this directory is already 1556192934Srmacklem * in the list. 1557192934Srmacklem */ 1558192934Srmacklem ep = ex_search(&fsb.f_fsid); 1559192934Srmacklem if (ep == (struct exportlist *)NULL) { 1560192934Srmacklem ep = get_exp(); 1561192934Srmacklem ep->ex_fs = fsb.f_fsid; 1562192934Srmacklem ep->ex_fsdir = (char *)malloc 1563192934Srmacklem (strlen(fsb.f_mntonname) + 1); 1564192934Srmacklem if (ep->ex_fsdir) 1565192934Srmacklem strcpy(ep->ex_fsdir, 1566192934Srmacklem fsb.f_mntonname); 1567192934Srmacklem else 1568192934Srmacklem out_of_mem(); 1569192934Srmacklem if (debug) 1570192934Srmacklem warnx( 1571192934Srmacklem "making new ep fs=0x%x,0x%x", 1572192934Srmacklem fsb.f_fsid.val[0], 1573192934Srmacklem fsb.f_fsid.val[1]); 1574192934Srmacklem } else if (debug) 1575192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1576192934Srmacklem fsb.f_fsid.val[0], 1577192934Srmacklem fsb.f_fsid.val[1]); 1578192934Srmacklem } 1579192934Srmacklem 15801558Srgrimes /* 1581192934Srmacklem * Add dirpath to export mount point. 15821558Srgrimes */ 1583192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1584192934Srmacklem dirplen = len; 15851558Srgrimes } 15861558Srgrimes } else { 15871558Srgrimes getexp_err(ep, tgrp); 15881558Srgrimes goto nextline; 15891558Srgrimes } 15901558Srgrimes *endcp = savedc; 15911558Srgrimes } else { 15921558Srgrimes savedc = *endcp; 15931558Srgrimes *endcp = '\0'; 15941558Srgrimes got_nondir = 1; 15951558Srgrimes if (ep == (struct exportlist *)NULL) { 15961558Srgrimes getexp_err(ep, tgrp); 15971558Srgrimes goto nextline; 15981558Srgrimes } 15991558Srgrimes 16001558Srgrimes /* 16011558Srgrimes * Get the host or netgroup. 16021558Srgrimes */ 16031558Srgrimes setnetgrent(cp); 16041558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 16051558Srgrimes do { 16061558Srgrimes if (has_host) { 16071558Srgrimes grp->gr_next = get_grp(); 16081558Srgrimes grp = grp->gr_next; 16091558Srgrimes } 16101558Srgrimes if (netgrp) { 161137003Sjoerg if (hst == 0) { 161237663Scharnier syslog(LOG_ERR, 161337663Scharnier "null hostname in netgroup %s, skipping", cp); 161437004Sjoerg grp->gr_type = GT_IGNORE; 161537003Sjoerg } else if (get_host(hst, grp, tgrp)) { 161637663Scharnier syslog(LOG_ERR, 161737663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 161829317Sjlemon grp->gr_type = GT_IGNORE; 16191558Srgrimes } 16207401Swpaul } else if (get_host(cp, grp, tgrp)) { 162137663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 162229317Sjlemon grp->gr_type = GT_IGNORE; 16231558Srgrimes } 16241558Srgrimes has_host = TRUE; 16251558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 16261558Srgrimes endnetgrent(); 16271558Srgrimes *endcp = savedc; 16281558Srgrimes } 16291558Srgrimes cp = endcp; 16301558Srgrimes nextfield(&cp, &endcp); 16311558Srgrimes len = endcp - cp; 16321558Srgrimes } 16331558Srgrimes if (check_options(dirhead)) { 16341558Srgrimes getexp_err(ep, tgrp); 16351558Srgrimes goto nextline; 16361558Srgrimes } 16371558Srgrimes if (!has_host) { 163875641Siedowse grp->gr_type = GT_DEFAULT; 16391558Srgrimes if (debug) 164037663Scharnier warnx("adding a default entry"); 16411558Srgrimes 16421558Srgrimes /* 16431558Srgrimes * Don't allow a network export coincide with a list of 16441558Srgrimes * host(s) on the same line. 16451558Srgrimes */ 16461558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 164775801Siedowse syslog(LOG_ERR, "network/host conflict"); 16481558Srgrimes getexp_err(ep, tgrp); 16491558Srgrimes goto nextline; 165029317Sjlemon 165174462Salfred /* 165274462Salfred * If an export list was specified on this line, make sure 165329317Sjlemon * that we have at least one valid entry, otherwise skip it. 165429317Sjlemon */ 165529317Sjlemon } else { 165629317Sjlemon grp = tgrp; 165774462Salfred while (grp && grp->gr_type == GT_IGNORE) 165829317Sjlemon grp = grp->gr_next; 165929317Sjlemon if (! grp) { 166029317Sjlemon getexp_err(ep, tgrp); 166129317Sjlemon goto nextline; 166229317Sjlemon } 16631558Srgrimes } 16641558Srgrimes 1665192934Srmacklem if (v4root_phase == 1) { 1666192934Srmacklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1667192934Srmacklem getexp_err(ep, tgrp); 1668192934Srmacklem goto nextline; 1669192934Srmacklem } 1670192934Srmacklem 16711558Srgrimes /* 16721558Srgrimes * Loop through hosts, pushing the exports into the kernel. 16731558Srgrimes * After loop, tgrp points to the start of the list and 16741558Srgrimes * grp points to the last entry in the list. 16751558Srgrimes */ 16761558Srgrimes grp = tgrp; 16771558Srgrimes do { 167875635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 167975635Siedowse &fsb)) { 168075635Siedowse getexp_err(ep, tgrp); 168175635Siedowse goto nextline; 168275635Siedowse } 16831558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 16841558Srgrimes 16851558Srgrimes /* 1686192934Srmacklem * For V4: don't enter in mount lists. 1687192934Srmacklem */ 1688194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1689194773Srmacklem /* 1690194773Srmacklem * Since these structures aren't used by mountd, 1691194773Srmacklem * free them up now. 1692194773Srmacklem */ 1693194773Srmacklem if (ep != NULL) 1694194773Srmacklem free_exp(ep); 1695194773Srmacklem while (tgrp != NULL) { 1696194773Srmacklem grp = tgrp; 1697194773Srmacklem tgrp = tgrp->gr_next; 1698194773Srmacklem free_grp(grp); 1699194773Srmacklem } 1700192934Srmacklem goto nextline; 1701194773Srmacklem } 1702192934Srmacklem 1703192934Srmacklem /* 17041558Srgrimes * Success. Update the data structures. 17051558Srgrimes */ 17061558Srgrimes if (has_host) { 17079336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 17081558Srgrimes grp->gr_next = grphead; 17091558Srgrimes grphead = tgrp; 17101558Srgrimes } else { 17111558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 17129336Sdfr opt_flags); 17131558Srgrimes free_grp(grp); 17141558Srgrimes } 17151558Srgrimes dirhead = (struct dirlist *)NULL; 17161558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 17171558Srgrimes ep2 = exphead; 17181558Srgrimes epp = &exphead; 17191558Srgrimes 17201558Srgrimes /* 17211558Srgrimes * Insert in the list in alphabetical order. 17221558Srgrimes */ 17231558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 17241558Srgrimes epp = &ep2->ex_next; 17251558Srgrimes ep2 = ep2->ex_next; 17261558Srgrimes } 17271558Srgrimes if (ep2) 17281558Srgrimes ep->ex_next = ep2; 17291558Srgrimes *epp = ep; 17301558Srgrimes ep->ex_flag |= EX_LINKED; 17311558Srgrimes } 17321558Srgrimesnextline: 1733192934Srmacklem v4root_phase = 0; 17341558Srgrimes if (dirhead) { 17351558Srgrimes free_dir(dirhead); 17361558Srgrimes dirhead = (struct dirlist *)NULL; 17371558Srgrimes } 17381558Srgrimes } 17391558Srgrimes} 17401558Srgrimes 17411558Srgrimes/* 1742166440Spjd * Get the export list from all specified files 1743166440Spjd */ 1744166440Spjdvoid 1745216587Scharnierget_exportlist(void) 1746166440Spjd{ 1747166440Spjd struct exportlist *ep, *ep2; 1748166440Spjd struct grouplist *grp, *tgrp; 1749166440Spjd struct export_args export; 1750166440Spjd struct iovec *iov; 1751166440Spjd struct statfs *fsp, *mntbufp; 1752166440Spjd struct xvfsconf vfc; 1753166440Spjd char errmsg[255]; 1754230352Seadler int num, i; 1755166440Spjd int iovlen; 1756168684Spjd int done; 1757192934Srmacklem struct nfsex_args eargs; 1758166440Spjd 1759241568Srmacklem if (suspend_nfsd != 0) 1760241568Srmacklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 1761192934Srmacklem v4root_dirpath[0] = '\0'; 1762166440Spjd bzero(&export, sizeof(export)); 1763166440Spjd export.ex_flags = MNT_DELEXPORT; 1764166440Spjd iov = NULL; 1765166440Spjd iovlen = 0; 1766166440Spjd bzero(errmsg, sizeof(errmsg)); 1767166440Spjd 1768166440Spjd /* 1769166440Spjd * First, get rid of the old list 1770166440Spjd */ 1771166440Spjd ep = exphead; 1772166440Spjd while (ep) { 1773166440Spjd ep2 = ep; 1774166440Spjd ep = ep->ex_next; 1775166440Spjd free_exp(ep2); 1776166440Spjd } 1777166440Spjd exphead = (struct exportlist *)NULL; 1778166440Spjd 1779166440Spjd grp = grphead; 1780166440Spjd while (grp) { 1781166440Spjd tgrp = grp; 1782166440Spjd grp = grp->gr_next; 1783166440Spjd free_grp(tgrp); 1784166440Spjd } 1785166440Spjd grphead = (struct grouplist *)NULL; 1786166440Spjd 1787166440Spjd /* 1788192934Srmacklem * and the old V4 root dir. 1789192934Srmacklem */ 1790192934Srmacklem bzero(&eargs, sizeof (eargs)); 1791192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1792192934Srmacklem if (run_v4server > 0 && 1793192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1794192934Srmacklem errno != ENOENT) 1795192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1796192934Srmacklem 1797192934Srmacklem /* 1798192934Srmacklem * and clear flag that notes if a public fh has been exported. 1799192934Srmacklem */ 1800192934Srmacklem has_publicfh = 0; 1801192934Srmacklem 1802192934Srmacklem /* 1803166440Spjd * And delete exports that are in the kernel for all local 1804166440Spjd * filesystems. 1805166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1806166440Spjd */ 1807166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1808166440Spjd 1809166440Spjd if (num > 0) { 1810166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1811166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1812166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1813166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1814166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1815166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1816166440Spjd } 1817166440Spjd 1818166440Spjd for (i = 0; i < num; i++) { 1819166440Spjd fsp = &mntbufp[i]; 1820166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1821166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1822166440Spjd fsp->f_fstypename); 1823166440Spjd continue; 1824166440Spjd } 1825166440Spjd 1826166440Spjd /* 1827282915Ssjg * We do not need to delete "export" flag from 1828282915Ssjg * filesystems that do not have it set. 1829282915Ssjg */ 1830282915Ssjg if (!(fsp->f_flags & MNT_EXPORTED)) 1831282915Ssjg continue; 1832282915Ssjg /* 1833166440Spjd * Do not delete export for network filesystem by 1834166440Spjd * passing "export" arg to nmount(). 1835166440Spjd * It only makes sense to do this for local filesystems. 1836166440Spjd */ 1837166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1838166440Spjd continue; 1839166440Spjd 1840166440Spjd iov[1].iov_base = fsp->f_fstypename; 1841166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1842166440Spjd iov[3].iov_base = fsp->f_mntonname; 1843166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1844166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1845166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1846272428Sbdrewery errmsg[0] = '\0'; 1847166440Spjd 1848279224Skib /* 1849279224Skib * EXDEV is returned when path exists but is not a 1850279224Skib * mount point. May happens if raced with unmount. 1851279224Skib */ 1852166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1853279224Skib errno != ENOENT && errno != ENOTSUP && errno != EXDEV) { 1854166440Spjd syslog(LOG_ERR, 1855166440Spjd "can't delete exports for %s: %m %s", 1856166440Spjd fsp->f_mntonname, errmsg); 1857166440Spjd } 1858166440Spjd } 1859166440Spjd 1860166440Spjd if (iov != NULL) { 1861166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1862166440Spjd free(iov[0].iov_base); /* fstype */ 1863166440Spjd free(iov[2].iov_base); /* fspath */ 1864166440Spjd free(iov[4].iov_base); /* from */ 1865166440Spjd free(iov[6].iov_base); /* update */ 1866166440Spjd free(iov[8].iov_base); /* export */ 1867166440Spjd free(iov[10].iov_base); /* errmsg */ 1868166440Spjd 1869166440Spjd /* free iov, allocated by realloc() */ 1870166440Spjd free(iov); 1871166440Spjd iovlen = 0; 1872166440Spjd } 1873166440Spjd 1874166440Spjd /* 1875166440Spjd * Read in the exports file and build the list, calling 1876166440Spjd * nmount() as we go along to push the export rules into the kernel. 1877166440Spjd */ 1878168684Spjd done = 0; 1879166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1880166440Spjd if (debug) 1881166440Spjd warnx("reading exports from %s", exnames[i]); 1882166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1883168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1884168684Spjd continue; 1885166440Spjd } 1886166440Spjd get_exportlist_one(); 1887166440Spjd fclose(exp_file); 1888168684Spjd done++; 1889166440Spjd } 1890168684Spjd if (done == 0) { 1891168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1892168684Spjd exit(2); 1893168684Spjd } 1894192934Srmacklem 1895192934Srmacklem /* 1896192934Srmacklem * If there was no public fh, clear any previous one set. 1897192934Srmacklem */ 1898192934Srmacklem if (run_v4server > 0 && has_publicfh == 0) 1899192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1900241568Srmacklem 1901241568Srmacklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1902241568Srmacklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 1903166440Spjd} 1904166440Spjd 1905166440Spjd/* 19061558Srgrimes * Allocate an export list element 19071558Srgrimes */ 19081558Srgrimesstruct exportlist * 1909216587Scharnierget_exp(void) 19101558Srgrimes{ 19111558Srgrimes struct exportlist *ep; 19121558Srgrimes 1913224003Sdelphij ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 19141558Srgrimes if (ep == (struct exportlist *)NULL) 19151558Srgrimes out_of_mem(); 19161558Srgrimes return (ep); 19171558Srgrimes} 19181558Srgrimes 19191558Srgrimes/* 19201558Srgrimes * Allocate a group list element 19211558Srgrimes */ 19221558Srgrimesstruct grouplist * 1923216587Scharnierget_grp(void) 19241558Srgrimes{ 19251558Srgrimes struct grouplist *gp; 19261558Srgrimes 1927224003Sdelphij gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 19281558Srgrimes if (gp == (struct grouplist *)NULL) 19291558Srgrimes out_of_mem(); 19301558Srgrimes return (gp); 19311558Srgrimes} 19321558Srgrimes 19331558Srgrimes/* 19341558Srgrimes * Clean up upon an error in get_exportlist(). 19351558Srgrimes */ 19361558Srgrimesvoid 1937216587Scharniergetexp_err(struct exportlist *ep, struct grouplist *grp) 19381558Srgrimes{ 19391558Srgrimes struct grouplist *tgrp; 19401558Srgrimes 1941100336Sjoerg if (!(opt_flags & OP_QUIET)) 1942100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 19431558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 19441558Srgrimes free_exp(ep); 19451558Srgrimes while (grp) { 19461558Srgrimes tgrp = grp; 19471558Srgrimes grp = grp->gr_next; 19481558Srgrimes free_grp(tgrp); 19491558Srgrimes } 19501558Srgrimes} 19511558Srgrimes 19521558Srgrimes/* 19531558Srgrimes * Search the export list for a matching fs. 19541558Srgrimes */ 19551558Srgrimesstruct exportlist * 1956216587Scharnierex_search(fsid_t *fsid) 19571558Srgrimes{ 19581558Srgrimes struct exportlist *ep; 19591558Srgrimes 19601558Srgrimes ep = exphead; 19611558Srgrimes while (ep) { 19621558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 19631558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 19641558Srgrimes return (ep); 19651558Srgrimes ep = ep->ex_next; 19661558Srgrimes } 19671558Srgrimes return (ep); 19681558Srgrimes} 19691558Srgrimes 19701558Srgrimes/* 19711558Srgrimes * Add a directory path to the list. 19721558Srgrimes */ 19731558Srgrimeschar * 1974216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len) 19751558Srgrimes{ 19761558Srgrimes struct dirlist *dp; 19771558Srgrimes 19781558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 197937663Scharnier if (dp == (struct dirlist *)NULL) 198037663Scharnier out_of_mem(); 19811558Srgrimes dp->dp_left = *dpp; 19821558Srgrimes dp->dp_right = (struct dirlist *)NULL; 19831558Srgrimes dp->dp_flag = 0; 19841558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 19851558Srgrimes strcpy(dp->dp_dirp, cp); 19861558Srgrimes *dpp = dp; 19871558Srgrimes return (dp->dp_dirp); 19881558Srgrimes} 19891558Srgrimes 19901558Srgrimes/* 19911558Srgrimes * Hang the dir list element off the dirpath binary tree as required 19921558Srgrimes * and update the entry for host. 19931558Srgrimes */ 19941558Srgrimesvoid 1995216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1996216587Scharnier int flags) 19971558Srgrimes{ 19981558Srgrimes struct hostlist *hp; 19991558Srgrimes struct dirlist *dp2; 20001558Srgrimes 20019336Sdfr if (flags & OP_ALLDIRS) { 20021558Srgrimes if (ep->ex_defdir) 20031558Srgrimes free((caddr_t)dp); 20041558Srgrimes else 20051558Srgrimes ep->ex_defdir = dp; 20069336Sdfr if (grp == (struct grouplist *)NULL) { 20071558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 2008240902Srmacklem /* Save the default security flavors list. */ 2009240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2010240902Srmacklem if (ep->ex_numsecflavors > 0) 2011240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2012240902Srmacklem sizeof(ep->ex_secflavors)); 20139336Sdfr } else while (grp) { 20141558Srgrimes hp = get_ht(); 20151558Srgrimes hp->ht_grp = grp; 20161558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 20171558Srgrimes ep->ex_defdir->dp_hosts = hp; 2018240902Srmacklem /* Save the security flavors list for this host set. */ 2019240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2020240902Srmacklem if (ep->ex_numsecflavors > 0) 2021240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2022240902Srmacklem sizeof(ep->ex_secflavors)); 20231558Srgrimes grp = grp->gr_next; 20241558Srgrimes } 20251558Srgrimes } else { 20261558Srgrimes 20271558Srgrimes /* 202837663Scharnier * Loop through the directories adding them to the tree. 20291558Srgrimes */ 20301558Srgrimes while (dp) { 20311558Srgrimes dp2 = dp->dp_left; 2032240902Srmacklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep); 20331558Srgrimes dp = dp2; 20341558Srgrimes } 20351558Srgrimes } 20361558Srgrimes} 20371558Srgrimes 20381558Srgrimes/* 20391558Srgrimes * Traverse the binary tree either updating a node that is already there 20401558Srgrimes * for the new directory or adding the new node. 20411558Srgrimes */ 20421558Srgrimesvoid 2043216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 2044240902Srmacklem int flags, struct exportlist *ep) 20451558Srgrimes{ 20461558Srgrimes struct dirlist *dp; 20471558Srgrimes struct hostlist *hp; 20481558Srgrimes int cmp; 20491558Srgrimes 20501558Srgrimes dp = *dpp; 20511558Srgrimes if (dp) { 20521558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 20531558Srgrimes if (cmp > 0) { 2054240902Srmacklem add_dlist(&dp->dp_left, newdp, grp, flags, ep); 20551558Srgrimes return; 20561558Srgrimes } else if (cmp < 0) { 2057240902Srmacklem add_dlist(&dp->dp_right, newdp, grp, flags, ep); 20581558Srgrimes return; 20591558Srgrimes } else 20601558Srgrimes free((caddr_t)newdp); 20611558Srgrimes } else { 20621558Srgrimes dp = newdp; 20631558Srgrimes dp->dp_left = (struct dirlist *)NULL; 20641558Srgrimes *dpp = dp; 20651558Srgrimes } 20661558Srgrimes if (grp) { 20671558Srgrimes 20681558Srgrimes /* 20691558Srgrimes * Hang all of the host(s) off of the directory point. 20701558Srgrimes */ 20711558Srgrimes do { 20721558Srgrimes hp = get_ht(); 20731558Srgrimes hp->ht_grp = grp; 20741558Srgrimes hp->ht_next = dp->dp_hosts; 20751558Srgrimes dp->dp_hosts = hp; 2076240902Srmacklem /* Save the security flavors list for this host set. */ 2077240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 2078240902Srmacklem if (ep->ex_numsecflavors > 0) 2079240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 2080240902Srmacklem sizeof(ep->ex_secflavors)); 20811558Srgrimes grp = grp->gr_next; 20821558Srgrimes } while (grp); 20839336Sdfr } else { 20841558Srgrimes dp->dp_flag |= DP_DEFSET; 2085240902Srmacklem /* Save the default security flavors list. */ 2086240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 2087240902Srmacklem if (ep->ex_numsecflavors > 0) 2088240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 2089240902Srmacklem sizeof(ep->ex_secflavors)); 20909336Sdfr } 20911558Srgrimes} 20921558Srgrimes 20931558Srgrimes/* 20941558Srgrimes * Search for a dirpath on the export point. 20951558Srgrimes */ 20961558Srgrimesstruct dirlist * 2097216587Scharnierdirp_search(struct dirlist *dp, char *dirp) 20981558Srgrimes{ 20991558Srgrimes int cmp; 21001558Srgrimes 21011558Srgrimes if (dp) { 210274462Salfred cmp = strcmp(dp->dp_dirp, dirp); 21031558Srgrimes if (cmp > 0) 210474462Salfred return (dirp_search(dp->dp_left, dirp)); 21051558Srgrimes else if (cmp < 0) 210674462Salfred return (dirp_search(dp->dp_right, dirp)); 21071558Srgrimes else 21081558Srgrimes return (dp); 21091558Srgrimes } 21101558Srgrimes return (dp); 21111558Srgrimes} 21121558Srgrimes 21131558Srgrimes/* 21141558Srgrimes * Scan for a host match in a directory tree. 21151558Srgrimes */ 21161558Srgrimesint 2117216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2118240902Srmacklem int *hostsetp, int *numsecflavors, int **secflavorsp) 21191558Srgrimes{ 21201558Srgrimes struct hostlist *hp; 21211558Srgrimes struct grouplist *grp; 212274462Salfred struct addrinfo *ai; 21231558Srgrimes 21241558Srgrimes if (dp) { 21251558Srgrimes if (dp->dp_flag & DP_DEFSET) 21269336Sdfr *defsetp = dp->dp_flag; 21271558Srgrimes hp = dp->dp_hosts; 21281558Srgrimes while (hp) { 21291558Srgrimes grp = hp->ht_grp; 21301558Srgrimes switch (grp->gr_type) { 21311558Srgrimes case GT_HOST: 213274462Salfred ai = grp->gr_ptr.gt_addrinfo; 213374462Salfred for (; ai; ai = ai->ai_next) { 213475801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 213574462Salfred *hostsetp = 213674462Salfred (hp->ht_flag | DP_HOSTSET); 2137240902Srmacklem if (numsecflavors != NULL) { 2138240902Srmacklem *numsecflavors = 2139240902Srmacklem grp->gr_numsecflavors; 2140240902Srmacklem *secflavorsp = 2141240902Srmacklem grp->gr_secflavors; 2142240902Srmacklem } 214374462Salfred return (1); 214474462Salfred } 21459336Sdfr } 214675801Siedowse break; 21471558Srgrimes case GT_NET: 214875801Siedowse if (!sacmp(saddr, (struct sockaddr *) 214975801Siedowse &grp->gr_ptr.gt_net.nt_net, 215075801Siedowse (struct sockaddr *) 215175801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 215274462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 2153240902Srmacklem if (numsecflavors != NULL) { 2154240902Srmacklem *numsecflavors = 2155240902Srmacklem grp->gr_numsecflavors; 2156240902Srmacklem *secflavorsp = 2157240902Srmacklem grp->gr_secflavors; 2158240902Srmacklem } 215974462Salfred return (1); 216074462Salfred } 216175801Siedowse break; 216275801Siedowse } 21631558Srgrimes hp = hp->ht_next; 21641558Srgrimes } 21651558Srgrimes } 21661558Srgrimes return (0); 21671558Srgrimes} 21681558Srgrimes 21691558Srgrimes/* 21701558Srgrimes * Scan tree for a host that matches the address. 21711558Srgrimes */ 21721558Srgrimesint 2173216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr) 21741558Srgrimes{ 21759336Sdfr int defset, hostset; 21761558Srgrimes 21771558Srgrimes if (dp) { 21781558Srgrimes if (scan_tree(dp->dp_left, saddr)) 21791558Srgrimes return (1); 2180240902Srmacklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 21811558Srgrimes return (1); 21821558Srgrimes if (scan_tree(dp->dp_right, saddr)) 21831558Srgrimes return (1); 21841558Srgrimes } 21851558Srgrimes return (0); 21861558Srgrimes} 21871558Srgrimes 21881558Srgrimes/* 21891558Srgrimes * Traverse the dirlist tree and free it up. 21901558Srgrimes */ 21911558Srgrimesvoid 2192216587Scharnierfree_dir(struct dirlist *dp) 21931558Srgrimes{ 21941558Srgrimes 21951558Srgrimes if (dp) { 21961558Srgrimes free_dir(dp->dp_left); 21971558Srgrimes free_dir(dp->dp_right); 21981558Srgrimes free_host(dp->dp_hosts); 21991558Srgrimes free((caddr_t)dp); 22001558Srgrimes } 22011558Srgrimes} 22021558Srgrimes 22031558Srgrimes/* 2204184588Sdfr * Parse a colon separated list of security flavors 2205184588Sdfr */ 2206184588Sdfrint 2207216587Scharnierparsesec(char *seclist, struct exportlist *ep) 2208184588Sdfr{ 2209184588Sdfr char *cp, savedc; 2210184588Sdfr int flavor; 2211184588Sdfr 2212184588Sdfr ep->ex_numsecflavors = 0; 2213184588Sdfr for (;;) { 2214184588Sdfr cp = strchr(seclist, ':'); 2215184588Sdfr if (cp) { 2216184588Sdfr savedc = *cp; 2217184588Sdfr *cp = '\0'; 2218184588Sdfr } 2219184588Sdfr 2220184588Sdfr if (!strcmp(seclist, "sys")) 2221184588Sdfr flavor = AUTH_SYS; 2222184588Sdfr else if (!strcmp(seclist, "krb5")) 2223184588Sdfr flavor = RPCSEC_GSS_KRB5; 2224184588Sdfr else if (!strcmp(seclist, "krb5i")) 2225184588Sdfr flavor = RPCSEC_GSS_KRB5I; 2226184588Sdfr else if (!strcmp(seclist, "krb5p")) 2227184588Sdfr flavor = RPCSEC_GSS_KRB5P; 2228184588Sdfr else { 2229184588Sdfr if (cp) 2230184588Sdfr *cp = savedc; 2231184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2232184588Sdfr return (1); 2233184588Sdfr } 2234184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2235184588Sdfr if (cp) 2236184588Sdfr *cp = savedc; 2237184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2238184588Sdfr return (1); 2239184588Sdfr } 2240184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2241184588Sdfr ep->ex_numsecflavors++; 2242184588Sdfr if (cp) { 2243184588Sdfr *cp = savedc; 2244184588Sdfr seclist = cp + 1; 2245184588Sdfr } else { 2246184588Sdfr break; 2247184588Sdfr } 2248184588Sdfr } 2249184588Sdfr return (0); 2250184588Sdfr} 2251184588Sdfr 2252184588Sdfr/* 22531558Srgrimes * Parse the option string and update fields. 22541558Srgrimes * Option arguments may either be -<option>=<value> or 22551558Srgrimes * -<option> <value> 22561558Srgrimes */ 22571558Srgrimesint 2258216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2259216587Scharnier int *has_hostp, int *exflagsp, struct xucred *cr) 22601558Srgrimes{ 22611558Srgrimes char *cpoptarg, *cpoptend; 22621558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 22631558Srgrimes int allflag, usedarg; 22641558Srgrimes 226551968Salfred savedc2 = '\0'; 22661558Srgrimes cpopt = *cpp; 22671558Srgrimes cpopt++; 22681558Srgrimes cp = *endcpp; 22691558Srgrimes savedc = *cp; 22701558Srgrimes *cp = '\0'; 22711558Srgrimes while (cpopt && *cpopt) { 22721558Srgrimes allflag = 1; 22731558Srgrimes usedarg = -2; 227437663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 22751558Srgrimes *cpoptend++ = '\0'; 227637663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 22771558Srgrimes *cpoptarg++ = '\0'; 22781558Srgrimes } else { 227937663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 22801558Srgrimes *cpoptarg++ = '\0'; 22811558Srgrimes else { 22821558Srgrimes *cp = savedc; 22831558Srgrimes nextfield(&cp, &endcp); 22841558Srgrimes **endcpp = '\0'; 22851558Srgrimes if (endcp > cp && *cp != '-') { 22861558Srgrimes cpoptarg = cp; 22871558Srgrimes savedc2 = *endcp; 22881558Srgrimes *endcp = '\0'; 22891558Srgrimes usedarg = 0; 22901558Srgrimes } 22911558Srgrimes } 22921558Srgrimes } 22931558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 22941558Srgrimes *exflagsp |= MNT_EXRDONLY; 22951558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 22961558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 22971558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 22981558Srgrimes usedarg++; 22991558Srgrimes parsecred(cpoptarg, cr); 23001558Srgrimes if (allflag == 0) { 23011558Srgrimes *exflagsp |= MNT_EXPORTANON; 23021558Srgrimes opt_flags |= OP_MAPALL; 23031558Srgrimes } else 23041558Srgrimes opt_flags |= OP_MAPROOT; 23051558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 230675801Siedowse !strcmp(cpopt, "m"))) { 23071558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 230837663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 23091558Srgrimes return (1); 23101558Srgrimes } 23111558Srgrimes usedarg++; 23121558Srgrimes opt_flags |= OP_MASK; 23131558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 23141558Srgrimes !strcmp(cpopt, "n"))) { 231574462Salfred if (strchr(cpoptarg, '/') != NULL) { 231674462Salfred if (debug) 231774462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 231874462Salfred opt_flags |= OP_MASKLEN; 231974462Salfred } 23201558Srgrimes if (grp->gr_type != GT_NULL) { 232137663Scharnier syslog(LOG_ERR, "network/host conflict"); 23221558Srgrimes return (1); 23231558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 232437663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 23251558Srgrimes return (1); 23261558Srgrimes } 23271558Srgrimes grp->gr_type = GT_NET; 23281558Srgrimes *has_hostp = 1; 23291558Srgrimes usedarg++; 23301558Srgrimes opt_flags |= OP_NET; 23311558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 23321558Srgrimes opt_flags |= OP_ALLDIRS; 233327447Sdfr } else if (!strcmp(cpopt, "public")) { 233427447Sdfr *exflagsp |= MNT_EXPUBLIC; 233527447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 233627447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 233727447Sdfr opt_flags |= OP_MAPALL; 233827447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 233927447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2340100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2341100336Sjoerg opt_flags |= OP_QUIET; 2342247034Spluknet } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2343184588Sdfr if (parsesec(cpoptarg, ep)) 2344184588Sdfr return (1); 2345184588Sdfr opt_flags |= OP_SEC; 2346184588Sdfr usedarg++; 23471558Srgrimes } else { 234837663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 23491558Srgrimes return (1); 23501558Srgrimes } 23511558Srgrimes if (usedarg >= 0) { 23521558Srgrimes *endcp = savedc2; 23531558Srgrimes **endcpp = savedc; 23541558Srgrimes if (usedarg > 0) { 23551558Srgrimes *cpp = cp; 23561558Srgrimes *endcpp = endcp; 23571558Srgrimes } 23581558Srgrimes return (0); 23591558Srgrimes } 23601558Srgrimes cpopt = cpoptend; 23611558Srgrimes } 23621558Srgrimes **endcpp = savedc; 23631558Srgrimes return (0); 23641558Srgrimes} 23651558Srgrimes 23661558Srgrimes/* 23671558Srgrimes * Translate a character string to the corresponding list of network 23681558Srgrimes * addresses for a hostname. 23691558Srgrimes */ 23701558Srgrimesint 2371216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 23721558Srgrimes{ 23737401Swpaul struct grouplist *checkgrp; 237475635Siedowse struct addrinfo *ai, *tai, hints; 237574462Salfred int ecode; 237674462Salfred char host[NI_MAXHOST]; 23771558Srgrimes 237874462Salfred if (grp->gr_type != GT_NULL) { 237974462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 23801558Srgrimes return (1); 23811558Srgrimes } 238274462Salfred memset(&hints, 0, sizeof hints); 238374462Salfred hints.ai_flags = AI_CANONNAME; 238474462Salfred hints.ai_protocol = IPPROTO_UDP; 238574462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 238674462Salfred if (ecode != 0) { 238775635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 238874462Salfred return 1; 238974462Salfred } 239074462Salfred grp->gr_ptr.gt_addrinfo = ai; 239174462Salfred while (ai != NULL) { 239274462Salfred if (ai->ai_canonname == NULL) { 239374462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2394146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 239574462Salfred strlcpy(host, "?", sizeof(host)); 239674462Salfred ai->ai_canonname = strdup(host); 239774462Salfred ai->ai_flags |= AI_CANONNAME; 239875641Siedowse } 239974462Salfred if (debug) 240075635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 240175635Siedowse /* 240275635Siedowse * Sanity check: make sure we don't already have an entry 240375635Siedowse * for this host in the grouplist. 240475635Siedowse */ 240575635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 240675635Siedowse checkgrp = checkgrp->gr_next) { 240775635Siedowse if (checkgrp->gr_type != GT_HOST) 240875635Siedowse continue; 240975635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 241075635Siedowse tai = tai->ai_next) { 241175801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 241275635Siedowse continue; 241375635Siedowse if (debug) 241475635Siedowse fprintf(stderr, 241575635Siedowse "ignoring duplicate host %s\n", 241675635Siedowse ai->ai_canonname); 241775635Siedowse grp->gr_type = GT_IGNORE; 241875635Siedowse return (0); 241975635Siedowse } 242075635Siedowse } 242174462Salfred ai = ai->ai_next; 24221558Srgrimes } 242375635Siedowse grp->gr_type = GT_HOST; 24241558Srgrimes return (0); 24251558Srgrimes} 24261558Srgrimes 24271558Srgrimes/* 24281558Srgrimes * Free up an exports list component 24291558Srgrimes */ 24301558Srgrimesvoid 2431216587Scharnierfree_exp(struct exportlist *ep) 24321558Srgrimes{ 24331558Srgrimes 24341558Srgrimes if (ep->ex_defdir) { 24351558Srgrimes free_host(ep->ex_defdir->dp_hosts); 24361558Srgrimes free((caddr_t)ep->ex_defdir); 24371558Srgrimes } 24381558Srgrimes if (ep->ex_fsdir) 24391558Srgrimes free(ep->ex_fsdir); 244027447Sdfr if (ep->ex_indexfile) 244127447Sdfr free(ep->ex_indexfile); 24421558Srgrimes free_dir(ep->ex_dirl); 24431558Srgrimes free((caddr_t)ep); 24441558Srgrimes} 24451558Srgrimes 24461558Srgrimes/* 24471558Srgrimes * Free hosts. 24481558Srgrimes */ 24491558Srgrimesvoid 2450216587Scharnierfree_host(struct hostlist *hp) 24511558Srgrimes{ 24521558Srgrimes struct hostlist *hp2; 24531558Srgrimes 24541558Srgrimes while (hp) { 24551558Srgrimes hp2 = hp; 24561558Srgrimes hp = hp->ht_next; 24571558Srgrimes free((caddr_t)hp2); 24581558Srgrimes } 24591558Srgrimes} 24601558Srgrimes 24611558Srgrimesstruct hostlist * 2462216587Scharnierget_ht(void) 24631558Srgrimes{ 24641558Srgrimes struct hostlist *hp; 24651558Srgrimes 24661558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 24671558Srgrimes if (hp == (struct hostlist *)NULL) 24681558Srgrimes out_of_mem(); 24691558Srgrimes hp->ht_next = (struct hostlist *)NULL; 24709336Sdfr hp->ht_flag = 0; 24711558Srgrimes return (hp); 24721558Srgrimes} 24731558Srgrimes 24741558Srgrimes/* 24751558Srgrimes * Out of memory, fatal 24761558Srgrimes */ 24771558Srgrimesvoid 2478216587Scharnierout_of_mem(void) 24791558Srgrimes{ 24801558Srgrimes 248137663Scharnier syslog(LOG_ERR, "out of memory"); 24821558Srgrimes exit(2); 24831558Srgrimes} 24841558Srgrimes 24851558Srgrimes/* 2486158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 24871558Srgrimes * the kernel. 24881558Srgrimes */ 24891558Srgrimesint 2490158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2491158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 24921558Srgrimes{ 249375841Siedowse struct statfs fsb1; 249474462Salfred struct addrinfo *ai; 2495192934Srmacklem struct export_args ea, *eap; 2496158857Srodrigc char errmsg[255]; 2497158857Srodrigc char *cp; 24981558Srgrimes int done; 2499158857Srodrigc char savedc; 2500158857Srodrigc struct iovec *iov; 2501184588Sdfr int i, iovlen; 2502158857Srodrigc int ret; 2503192934Srmacklem struct nfsex_args nfsea; 25041558Srgrimes 2505192934Srmacklem if (run_v4server > 0) 2506192934Srmacklem eap = &nfsea.export; 2507192934Srmacklem else 2508192934Srmacklem eap = &ea; 2509192934Srmacklem 2510158857Srodrigc cp = NULL; 2511158857Srodrigc savedc = '\0'; 2512158857Srodrigc iov = NULL; 2513158857Srodrigc iovlen = 0; 2514158857Srodrigc ret = 0; 251575801Siedowse 2516192934Srmacklem bzero(eap, sizeof (struct export_args)); 2517158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2518192934Srmacklem eap->ex_flags = exflags; 2519192934Srmacklem eap->ex_anon = *anoncrp; 2520192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 252175641Siedowse if (grp->gr_type == GT_HOST) 252274462Salfred ai = grp->gr_ptr.gt_addrinfo; 252375641Siedowse else 252475641Siedowse ai = NULL; 2525192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2526192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2527192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2528192934Srmacklem if (eap->ex_numsecflavors == 0) { 2529192934Srmacklem eap->ex_numsecflavors = 1; 2530192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2531184588Sdfr } 25321558Srgrimes done = FALSE; 2533158857Srodrigc 2534192934Srmacklem if (v4root_phase == 0) { 2535192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2536192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2537192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2538192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2539192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2540192934Srmacklem sizeof (struct export_args)); 2541192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2542192934Srmacklem } 2543158857Srodrigc 25441558Srgrimes while (!done) { 25451558Srgrimes switch (grp->gr_type) { 25461558Srgrimes case GT_HOST: 254775641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 254874462Salfred goto skip; 2549192934Srmacklem eap->ex_addr = ai->ai_addr; 2550192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2551192934Srmacklem eap->ex_masklen = 0; 25521558Srgrimes break; 25531558Srgrimes case GT_NET: 255475801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 255574462Salfred have_v6 == 0) 255674462Salfred goto skip; 2557192934Srmacklem eap->ex_addr = 255875801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2559192934Srmacklem eap->ex_addrlen = 2560158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2561192934Srmacklem eap->ex_mask = 256275801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2563192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 25641558Srgrimes break; 256575641Siedowse case GT_DEFAULT: 2566192934Srmacklem eap->ex_addr = NULL; 2567192934Srmacklem eap->ex_addrlen = 0; 2568192934Srmacklem eap->ex_mask = NULL; 2569192934Srmacklem eap->ex_masklen = 0; 257075641Siedowse break; 25717401Swpaul case GT_IGNORE: 2572158857Srodrigc ret = 0; 2573158857Srodrigc goto error_exit; 25747401Swpaul break; 25751558Srgrimes default: 257637663Scharnier syslog(LOG_ERR, "bad grouptype"); 25771558Srgrimes if (cp) 25781558Srgrimes *cp = savedc; 2579158857Srodrigc ret = 1; 2580158857Srodrigc goto error_exit; 25811558Srgrimes }; 25821558Srgrimes 25831558Srgrimes /* 2584192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 25851558Srgrimes */ 2586192934Srmacklem if (v4root_phase == 2) { 2587192934Srmacklem nfsea.fspec = v4root_dirpath; 2588192934Srmacklem if (run_v4server > 0 && 2589192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2590192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2591192934Srmacklem return (2); 2592158857Srodrigc } 2593192934Srmacklem } else { 2594192934Srmacklem /* 2595192934Srmacklem * XXX: 2596192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2597192934Srmacklem * instead of looping back up the dirp to the mount 2598192934Srmacklem * point?? 2599192934Srmacklem * Also, needs to know how to export all types of local 2600192934Srmacklem * exportable filesystems and not just "ufs". 2601192934Srmacklem */ 2602192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2603192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2604192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2605192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2606192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2607192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2608272428Sbdrewery errmsg[0] = '\0'; 2609192934Srmacklem 2610192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2611192934Srmacklem if (cp) 2612192934Srmacklem *cp-- = savedc; 2613192934Srmacklem else 2614192934Srmacklem cp = dirp + dirplen - 1; 2615192934Srmacklem if (opt_flags & OP_QUIET) { 2616192934Srmacklem ret = 1; 2617192934Srmacklem goto error_exit; 2618192934Srmacklem } 2619192934Srmacklem if (errno == EPERM) { 2620192934Srmacklem if (debug) 2621239744Sdelphij warnx("can't change attributes for %s: %s", 2622239744Sdelphij dirp, errmsg); 2623192934Srmacklem syslog(LOG_ERR, 2624239744Sdelphij "can't change attributes for %s: %s", 2625239744Sdelphij dirp, errmsg); 2626192934Srmacklem ret = 1; 2627192934Srmacklem goto error_exit; 2628192934Srmacklem } 2629192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2630192934Srmacklem if (errno == EINVAL) 2631192934Srmacklem syslog(LOG_ERR, 2632100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2633192934Srmacklem dirp); 2634192934Srmacklem else 2635192934Srmacklem syslog(LOG_ERR, 2636192934Srmacklem "could not remount %s: %m", 2637192934Srmacklem dirp); 2638192934Srmacklem ret = 1; 2639192934Srmacklem goto error_exit; 2640192934Srmacklem } 2641192934Srmacklem /* back up over the last component */ 2642192934Srmacklem while (*cp == '/' && cp > dirp) 2643192934Srmacklem cp--; 2644192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2645192934Srmacklem cp--; 2646192934Srmacklem if (cp == dirp) { 2647192934Srmacklem if (debug) 2648192934Srmacklem warnx("mnt unsucc"); 2649192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2650192934Srmacklem dirp, errmsg); 2651192934Srmacklem ret = 1; 2652192934Srmacklem goto error_exit; 2653192934Srmacklem } 2654192934Srmacklem savedc = *cp; 2655192934Srmacklem *cp = '\0'; 2656192934Srmacklem /* 2657192934Srmacklem * Check that we're still on the same 2658192934Srmacklem * filesystem. 2659192934Srmacklem */ 2660192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2661192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2662192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2663192934Srmacklem *cp = savedc; 2664100336Sjoerg syslog(LOG_ERR, 2665192934Srmacklem "can't export %s %s", dirp, 2666192934Srmacklem errmsg); 2667192934Srmacklem ret = 1; 2668192934Srmacklem goto error_exit; 2669192934Srmacklem } 26701558Srgrimes } 26711558Srgrimes } 2672192934Srmacklem 2673192934Srmacklem /* 2674192934Srmacklem * For the experimental server: 2675192934Srmacklem * If this is the public directory, get the file handle 2676192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2677192934Srmacklem */ 2678192934Srmacklem if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2679192934Srmacklem fhandle_t fh; 2680192934Srmacklem char *public_name; 2681192934Srmacklem 2682192934Srmacklem if (eap->ex_indexfile != NULL) 2683192934Srmacklem public_name = eap->ex_indexfile; 2684192934Srmacklem else 2685192934Srmacklem public_name = dirp; 2686192934Srmacklem if (getfh(public_name, &fh) < 0) 2687192934Srmacklem syslog(LOG_ERR, 2688192934Srmacklem "Can't get public fh for %s", public_name); 2689192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2690192934Srmacklem syslog(LOG_ERR, 2691192934Srmacklem "Can't set public fh for %s", public_name); 2692192934Srmacklem else 2693192934Srmacklem has_publicfh = 1; 2694192934Srmacklem } 269574462Salfredskip: 269675641Siedowse if (ai != NULL) 269774462Salfred ai = ai->ai_next; 269875641Siedowse if (ai == NULL) 26991558Srgrimes done = TRUE; 27001558Srgrimes } 27011558Srgrimes if (cp) 27021558Srgrimes *cp = savedc; 2703158857Srodrigcerror_exit: 2704158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2705158857Srodrigc if (iov != NULL) { 2706158857Srodrigc free(iov[0].iov_base); /* fstype */ 2707158857Srodrigc free(iov[2].iov_base); /* fspath */ 2708158857Srodrigc free(iov[4].iov_base); /* from */ 2709158857Srodrigc free(iov[6].iov_base); /* update */ 2710158857Srodrigc free(iov[8].iov_base); /* export */ 2711158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2712158857Srodrigc 2713158857Srodrigc /* free iov, allocated by realloc() */ 2714158857Srodrigc free(iov); 2715158857Srodrigc } 2716158857Srodrigc return (ret); 27171558Srgrimes} 27181558Srgrimes 27191558Srgrimes/* 27201558Srgrimes * Translate a net address. 272175801Siedowse * 272275801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 27231558Srgrimes */ 27241558Srgrimesint 2725216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg) 27261558Srgrimes{ 272775861Siedowse struct netent *np = NULL; 272874462Salfred char *name, *p, *prefp; 272975801Siedowse struct sockaddr_in sin; 273075861Siedowse struct sockaddr *sa = NULL; 273174462Salfred struct addrinfo hints, *ai = NULL; 273274462Salfred char netname[NI_MAXHOST]; 273374462Salfred long preflen; 27341558Srgrimes 273575635Siedowse p = prefp = NULL; 273674462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 273774462Salfred p = strchr(cp, '/'); 273874462Salfred *p = '\0'; 273974462Salfred prefp = p + 1; 274074462Salfred } 274174462Salfred 274275861Siedowse /* 274375861Siedowse * Check for a numeric address first. We wish to avoid 274475861Siedowse * possible DNS lookups in getnetbyname(). 274575861Siedowse */ 274675861Siedowse if (isxdigit(*cp) || *cp == ':') { 274774462Salfred memset(&hints, 0, sizeof hints); 274875801Siedowse /* Ensure the mask and the network have the same family. */ 274975801Siedowse if (maskflg && (opt_flags & OP_NET)) 275075801Siedowse hints.ai_family = net->nt_net.ss_family; 275175801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 275275801Siedowse hints.ai_family = net->nt_mask.ss_family; 275375801Siedowse else 275475801Siedowse hints.ai_family = AF_UNSPEC; 275574462Salfred hints.ai_flags = AI_NUMERICHOST; 275675861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 275775861Siedowse sa = ai->ai_addr; 275875861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 275974462Salfred /* 276075801Siedowse * The address in `cp' is really a network address, so 276175801Siedowse * use inet_network() to re-interpret this correctly. 276275801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 276374462Salfred */ 276475801Siedowse bzero(&sin, sizeof sin); 276574462Salfred sin.sin_family = AF_INET; 276674462Salfred sin.sin_len = sizeof sin; 276775801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 276874462Salfred if (debug) 276975801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 277075801Siedowse inet_ntoa(sin.sin_addr)); 277174462Salfred sa = (struct sockaddr *)&sin; 277275861Siedowse } 277375861Siedowse } 277475861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 277575861Siedowse bzero(&sin, sizeof sin); 277675861Siedowse sin.sin_family = AF_INET; 277775861Siedowse sin.sin_len = sizeof sin; 277875861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 277975861Siedowse sa = (struct sockaddr *)&sin; 278075861Siedowse } 278175861Siedowse if (sa == NULL) 278274462Salfred goto fail; 278325318Spst 278475801Siedowse if (maskflg) { 278575801Siedowse /* The specified sockaddr is a mask. */ 278675801Siedowse if (checkmask(sa) != 0) 278775801Siedowse goto fail; 278875801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 278975801Siedowse opt_flags |= OP_HAVEMASK; 279075801Siedowse } else { 279175801Siedowse /* The specified sockaddr is a network address. */ 279275801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 279374462Salfred 279475801Siedowse /* Get a network name for the export list. */ 279575801Siedowse if (np) { 279675801Siedowse name = np->n_name; 279775801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2798146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 279975801Siedowse name = netname; 280075801Siedowse } else { 280175801Siedowse goto fail; 280275801Siedowse } 280375801Siedowse if ((net->nt_name = strdup(name)) == NULL) 280475801Siedowse out_of_mem(); 280575801Siedowse 280675801Siedowse /* 280775801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 280875801Siedowse * from the class of an IPv4 address. 280975801Siedowse */ 281074462Salfred if (opt_flags & OP_MASKLEN) { 281174462Salfred preflen = strtol(prefp, NULL, 10); 281275801Siedowse if (preflen < 0L || preflen == LONG_MAX) 281374462Salfred goto fail; 281475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 281575801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 281675801Siedowse goto fail; 281775801Siedowse opt_flags |= OP_HAVEMASK; 281874462Salfred *p = '/'; 281975801Siedowse } else if (sa->sa_family == AF_INET && 282075801Siedowse (opt_flags & OP_MASK) == 0) { 282175801Siedowse in_addr_t addr; 282274462Salfred 282375801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 282475801Siedowse if (IN_CLASSA(addr)) 282575801Siedowse preflen = 8; 282675801Siedowse else if (IN_CLASSB(addr)) 282775801Siedowse preflen = 16; 282875801Siedowse else if (IN_CLASSC(addr)) 282975801Siedowse preflen = 24; 283075801Siedowse else if (IN_CLASSD(addr)) 283175801Siedowse preflen = 28; 283275801Siedowse else 283375801Siedowse preflen = 32; /* XXX */ 283475801Siedowse 283575801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 283675801Siedowse makemask(&net->nt_mask, (int)preflen); 283775801Siedowse opt_flags |= OP_HAVEMASK; 283874462Salfred } 283974462Salfred } 284074462Salfred 284174462Salfred if (ai) 284274462Salfred freeaddrinfo(ai); 284374462Salfred return 0; 284474462Salfred 284574462Salfredfail: 284674462Salfred if (ai) 284774462Salfred freeaddrinfo(ai); 284874462Salfred return 1; 28491558Srgrimes} 28501558Srgrimes 28511558Srgrimes/* 28521558Srgrimes * Parse out the next white space separated field 28531558Srgrimes */ 28541558Srgrimesvoid 2855216587Scharniernextfield(char **cp, char **endcp) 28561558Srgrimes{ 28571558Srgrimes char *p; 28581558Srgrimes 28591558Srgrimes p = *cp; 28601558Srgrimes while (*p == ' ' || *p == '\t') 28611558Srgrimes p++; 28621558Srgrimes if (*p == '\n' || *p == '\0') 28631558Srgrimes *cp = *endcp = p; 28641558Srgrimes else { 28651558Srgrimes *cp = p++; 28661558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 28671558Srgrimes p++; 28681558Srgrimes *endcp = p; 28691558Srgrimes } 28701558Srgrimes} 28711558Srgrimes 28721558Srgrimes/* 28731558Srgrimes * Get an exports file line. Skip over blank lines and handle line 28741558Srgrimes * continuations. 28751558Srgrimes */ 28761558Srgrimesint 2877216587Scharnierget_line(void) 28781558Srgrimes{ 28791558Srgrimes char *p, *cp; 288096622Siedowse size_t len; 28811558Srgrimes int totlen, cont_line; 28821558Srgrimes 28831558Srgrimes /* 28841558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 28851558Srgrimes */ 28861558Srgrimes p = line; 28871558Srgrimes totlen = 0; 28881558Srgrimes do { 288996622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 28901558Srgrimes return (0); 28911558Srgrimes cp = p + len - 1; 28921558Srgrimes cont_line = 0; 28931558Srgrimes while (cp >= p && 28941558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 28951558Srgrimes if (*cp == '\\') 28961558Srgrimes cont_line = 1; 28971558Srgrimes cp--; 28981558Srgrimes len--; 28991558Srgrimes } 290079117Sdd if (cont_line) { 290179117Sdd *++cp = ' '; 290279117Sdd len++; 290379117Sdd } 290496622Siedowse if (linesize < len + totlen + 1) { 290596622Siedowse linesize = len + totlen + 1; 290696622Siedowse line = realloc(line, linesize); 290796622Siedowse if (line == NULL) 290896622Siedowse out_of_mem(); 29091558Srgrimes } 291096622Siedowse memcpy(line + totlen, p, len); 291196622Siedowse totlen += len; 291296622Siedowse line[totlen] = '\0'; 29131558Srgrimes } while (totlen == 0 || cont_line); 29141558Srgrimes return (1); 29151558Srgrimes} 29161558Srgrimes 29171558Srgrimes/* 29181558Srgrimes * Parse a description of a credential. 29191558Srgrimes */ 29201558Srgrimesvoid 2921216587Scharnierparsecred(char *namelist, struct xucred *cr) 29221558Srgrimes{ 29231558Srgrimes char *name; 29241558Srgrimes int cnt; 29251558Srgrimes char *names; 29261558Srgrimes struct passwd *pw; 29271558Srgrimes struct group *gr; 2928194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2929136051Sstefanf int ngroups; 29301558Srgrimes 293191354Sdd cr->cr_version = XUCRED_VERSION; 29321558Srgrimes /* 293337663Scharnier * Set up the unprivileged user. 29341558Srgrimes */ 29351558Srgrimes cr->cr_uid = -2; 29361558Srgrimes cr->cr_groups[0] = -2; 29371558Srgrimes cr->cr_ngroups = 1; 29381558Srgrimes /* 29391558Srgrimes * Get the user's password table entry. 29401558Srgrimes */ 2941294124Sjpaetzel names = strsep_quote(&namelist, " \t\n"); 29421558Srgrimes name = strsep(&names, ":"); 2943294124Sjpaetzel /* Bug? name could be NULL here */ 29441558Srgrimes if (isdigit(*name) || *name == '-') 29451558Srgrimes pw = getpwuid(atoi(name)); 29461558Srgrimes else 29471558Srgrimes pw = getpwnam(name); 29481558Srgrimes /* 29491558Srgrimes * Credentials specified as those of a user. 29501558Srgrimes */ 29511558Srgrimes if (names == NULL) { 29521558Srgrimes if (pw == NULL) { 295337663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 29541558Srgrimes return; 29551558Srgrimes } 29561558Srgrimes cr->cr_uid = pw->pw_uid; 2957194498Sbrooks ngroups = XU_NGROUPS + 1; 2958333198Savg if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) { 295937663Scharnier syslog(LOG_ERR, "too many groups"); 2960333198Savg ngroups = XU_NGROUPS + 1; 2961333198Savg } 2962333198Savg 29631558Srgrimes /* 2964136051Sstefanf * Compress out duplicate. 29651558Srgrimes */ 29661558Srgrimes cr->cr_ngroups = ngroups - 1; 29671558Srgrimes cr->cr_groups[0] = groups[0]; 29681558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 29691558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 29701558Srgrimes return; 29711558Srgrimes } 29721558Srgrimes /* 29731558Srgrimes * Explicit credential specified as a colon separated list: 29741558Srgrimes * uid:gid:gid:... 29751558Srgrimes */ 29761558Srgrimes if (pw != NULL) 29771558Srgrimes cr->cr_uid = pw->pw_uid; 29781558Srgrimes else if (isdigit(*name) || *name == '-') 29791558Srgrimes cr->cr_uid = atoi(name); 29801558Srgrimes else { 298137663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 29821558Srgrimes return; 29831558Srgrimes } 29841558Srgrimes cr->cr_ngroups = 0; 2985194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 29861558Srgrimes name = strsep(&names, ":"); 29871558Srgrimes if (isdigit(*name) || *name == '-') { 29881558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 29891558Srgrimes } else { 29901558Srgrimes if ((gr = getgrnam(name)) == NULL) { 299137663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 29921558Srgrimes continue; 29931558Srgrimes } 29941558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 29951558Srgrimes } 29961558Srgrimes } 2997194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 299837663Scharnier syslog(LOG_ERR, "too many groups"); 29991558Srgrimes} 30001558Srgrimes 3001194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 30021558Srgrimes/* 30031558Srgrimes * Routines that maintain the remote mounttab 30041558Srgrimes */ 30051558Srgrimesvoid 3006216587Scharnierget_mountlist(void) 30071558Srgrimes{ 30081558Srgrimes struct mountlist *mlp, **mlpp; 300923681Speter char *host, *dirp, *cp; 30101558Srgrimes char str[STRSIZ]; 30111558Srgrimes FILE *mlfile; 30121558Srgrimes 30131558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 301453117Sbillf if (errno == ENOENT) 301553117Sbillf return; 301653117Sbillf else { 301753117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 301853117Sbillf return; 301953117Sbillf } 30201558Srgrimes } 30211558Srgrimes mlpp = &mlhead; 30221558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 302323681Speter cp = str; 302423681Speter host = strsep(&cp, " \t\n"); 302523681Speter dirp = strsep(&cp, " \t\n"); 302623681Speter if (host == NULL || dirp == NULL) 30271558Srgrimes continue; 30281558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 302937663Scharnier if (mlp == (struct mountlist *)NULL) 303037663Scharnier out_of_mem(); 3031194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 3032194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 3033194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 3034194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 30351558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 30361558Srgrimes *mlpp = mlp; 30371558Srgrimes mlpp = &mlp->ml_next; 30381558Srgrimes } 30391558Srgrimes fclose(mlfile); 30401558Srgrimes} 30411558Srgrimes 304275635Siedowsevoid 304375635Siedowsedel_mlist(char *hostp, char *dirp) 30441558Srgrimes{ 30451558Srgrimes struct mountlist *mlp, **mlpp; 30461558Srgrimes struct mountlist *mlp2; 30471558Srgrimes FILE *mlfile; 30481558Srgrimes int fnd = 0; 30491558Srgrimes 30501558Srgrimes mlpp = &mlhead; 30511558Srgrimes mlp = mlhead; 30521558Srgrimes while (mlp) { 30531558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 30541558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 30551558Srgrimes fnd = 1; 30561558Srgrimes mlp2 = mlp; 30571558Srgrimes *mlpp = mlp = mlp->ml_next; 30581558Srgrimes free((caddr_t)mlp2); 30591558Srgrimes } else { 30601558Srgrimes mlpp = &mlp->ml_next; 30611558Srgrimes mlp = mlp->ml_next; 30621558Srgrimes } 30631558Srgrimes } 30641558Srgrimes if (fnd) { 30651558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 306637663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 30671558Srgrimes return; 30681558Srgrimes } 30691558Srgrimes mlp = mlhead; 30701558Srgrimes while (mlp) { 30711558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30721558Srgrimes mlp = mlp->ml_next; 30731558Srgrimes } 30741558Srgrimes fclose(mlfile); 30751558Srgrimes } 30761558Srgrimes} 30771558Srgrimes 30781558Srgrimesvoid 3079216587Scharnieradd_mlist(char *hostp, char *dirp) 30801558Srgrimes{ 30811558Srgrimes struct mountlist *mlp, **mlpp; 30821558Srgrimes FILE *mlfile; 30831558Srgrimes 30841558Srgrimes mlpp = &mlhead; 30851558Srgrimes mlp = mlhead; 30861558Srgrimes while (mlp) { 30871558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 30881558Srgrimes return; 30891558Srgrimes mlpp = &mlp->ml_next; 30901558Srgrimes mlp = mlp->ml_next; 30911558Srgrimes } 30921558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 309337663Scharnier if (mlp == (struct mountlist *)NULL) 309437663Scharnier out_of_mem(); 3095194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 3096194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 3097194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 3098194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 30991558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 31001558Srgrimes *mlpp = mlp; 31011558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 310237663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 31031558Srgrimes return; 31041558Srgrimes } 31051558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 31061558Srgrimes fclose(mlfile); 31071558Srgrimes} 31081558Srgrimes 31091558Srgrimes/* 31101558Srgrimes * Free up a group list. 31111558Srgrimes */ 31121558Srgrimesvoid 3113216587Scharnierfree_grp(struct grouplist *grp) 31141558Srgrimes{ 31151558Srgrimes if (grp->gr_type == GT_HOST) { 311674462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 311774462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 31181558Srgrimes } else if (grp->gr_type == GT_NET) { 31191558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 31201558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 31211558Srgrimes } 31221558Srgrimes free((caddr_t)grp); 31231558Srgrimes} 31241558Srgrimes 31251558Srgrimes#ifdef DEBUG 31261558Srgrimesvoid 31271558SrgrimesSYSLOG(int pri, const char *fmt, ...) 31281558Srgrimes{ 31291558Srgrimes va_list ap; 31301558Srgrimes 31311558Srgrimes va_start(ap, fmt); 31321558Srgrimes vfprintf(stderr, fmt, ap); 31331558Srgrimes va_end(ap); 31341558Srgrimes} 31351558Srgrimes#endif /* DEBUG */ 31361558Srgrimes 31371558Srgrimes/* 31381558Srgrimes * Check options for consistency. 31391558Srgrimes */ 31401558Srgrimesint 3141216587Scharniercheck_options(struct dirlist *dp) 31421558Srgrimes{ 31431558Srgrimes 3144192934Srmacklem if (v4root_phase == 0 && dp == NULL) 31451558Srgrimes return (1); 314683653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 314783653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 31481558Srgrimes return (1); 31491558Srgrimes } 31501558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 315175801Siedowse syslog(LOG_ERR, "-mask requires -network"); 315275801Siedowse return (1); 31531558Srgrimes } 315475801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 315575801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 315675801Siedowse return (1); 315775801Siedowse } 315875801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 315975801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 316075801Siedowse return (1); 316175801Siedowse } 3162192934Srmacklem if (v4root_phase > 0 && 3163192934Srmacklem (opt_flags & 3164192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3165192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3166192934Srmacklem return (1); 3167192934Srmacklem } 3168207689Srmacklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 3169207689Srmacklem syslog(LOG_ERR, "-alldirs has multiple directories"); 3170207689Srmacklem return (1); 3171207689Srmacklem } 31721558Srgrimes return (0); 31731558Srgrimes} 31741558Srgrimes 31751558Srgrimes/* 31761558Srgrimes * Check an absolute directory path for any symbolic links. Return true 31771558Srgrimes */ 31781558Srgrimesint 3179216587Scharniercheck_dirpath(char *dirp) 31801558Srgrimes{ 31811558Srgrimes char *cp; 31821558Srgrimes int ret = 1; 31831558Srgrimes struct stat sb; 31841558Srgrimes 31851558Srgrimes cp = dirp + 1; 31861558Srgrimes while (*cp && ret) { 31871558Srgrimes if (*cp == '/') { 31881558Srgrimes *cp = '\0'; 31899336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31901558Srgrimes ret = 0; 31911558Srgrimes *cp = '/'; 31921558Srgrimes } 31931558Srgrimes cp++; 31941558Srgrimes } 31959336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 31961558Srgrimes ret = 0; 31971558Srgrimes return (ret); 31981558Srgrimes} 31999336Sdfr 320075801Siedowse/* 320175801Siedowse * Make a netmask according to the specified prefix length. The ss_family 320275801Siedowse * and other non-address fields must be initialised before calling this. 320375801Siedowse */ 320475801Siedowseint 320575801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 320674462Salfred{ 320775801Siedowse u_char *p; 320875801Siedowse int bits, i, len; 320974462Salfred 321075801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 321175801Siedowse return (-1); 3212103949Smike if (bitlen > len * CHAR_BIT) 321375801Siedowse return (-1); 321474462Salfred 321575801Siedowse for (i = 0; i < len; i++) { 3216103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 3217219125Sru *p++ = (u_char)~0 << (CHAR_BIT - bits); 321875801Siedowse bitlen -= bits; 321974462Salfred } 322075801Siedowse return 0; 322174462Salfred} 322274462Salfred 322375801Siedowse/* 322475801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 322575801Siedowse * is acceptable (i.e. of the form 1...10....0). 322675801Siedowse */ 322775801Siedowseint 322875801Siedowsecheckmask(struct sockaddr *sa) 322974462Salfred{ 323075801Siedowse u_char *mask; 323175801Siedowse int i, len; 323274462Salfred 323375801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 323475801Siedowse return (-1); 323575801Siedowse 323675801Siedowse for (i = 0; i < len; i++) 323775801Siedowse if (mask[i] != 0xff) 323875801Siedowse break; 323975801Siedowse if (i < len) { 324075801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 324175801Siedowse return (-1); 324275801Siedowse i++; 324374462Salfred } 324475801Siedowse for (; i < len; i++) 324575801Siedowse if (mask[i] != 0) 324675801Siedowse return (-1); 324775801Siedowse return (0); 324874462Salfred} 324974462Salfred 325075801Siedowse/* 325175801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 325275801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 3253228990Suqs * If samask is NULL, perform a full comparison. 325475801Siedowse */ 325575801Siedowseint 325675801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 325774462Salfred{ 325875801Siedowse unsigned char *p1, *p2, *mask; 325975801Siedowse int len, i; 326074462Salfred 326175801Siedowse if (sa1->sa_family != sa2->sa_family || 326275801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 326375801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 326475801Siedowse return (1); 326575801Siedowse 326675801Siedowse switch (sa1->sa_family) { 326774462Salfred case AF_INET6: 326875801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 326975801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 327075801Siedowse return (1); 327174462Salfred break; 327274462Salfred } 327374462Salfred 327475801Siedowse /* Simple binary comparison if no mask specified. */ 327575801Siedowse if (samask == NULL) 327675801Siedowse return (memcmp(p1, p2, len)); 327774462Salfred 327875801Siedowse /* Set up the mask, and do a mask-based comparison. */ 327975801Siedowse if (sa1->sa_family != samask->sa_family || 328075801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 328175801Siedowse return (1); 328274462Salfred 328375801Siedowse for (i = 0; i < len; i++) 328475801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 328575801Siedowse return (1); 328675801Siedowse return (0); 328774462Salfred} 328874462Salfred 328975801Siedowse/* 329075801Siedowse * Return a pointer to the part of the sockaddr that contains the 329175801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 329275801Siedowse * NULL if the address family is unknown. 329375801Siedowse */ 329475801Siedowsevoid * 329575801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 329675801Siedowse void *p; 329774462Salfred int len; 329874462Salfred 329975801Siedowse switch (sa->sa_family) { 330074462Salfred case AF_INET: 330175801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 330275801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 330374462Salfred break; 330474462Salfred case AF_INET6: 330575801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 330675801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 330774462Salfred break; 330874462Salfred default: 330975801Siedowse p = NULL; 331075801Siedowse len = 0; 331174462Salfred } 331274462Salfred 331375801Siedowse if (nbytes != NULL) 331475801Siedowse *nbytes = len; 331575801Siedowse return (p); 331674462Salfred} 331774462Salfred 331875754Siedowsevoid 3319216587Scharnierhuphandler(int sig __unused) 332075754Siedowse{ 332175754Siedowse got_sighup = 1; 332275754Siedowse} 332375754Siedowse 3324216587Scharniervoid terminate(int sig __unused) 332574462Salfred{ 3326149433Spjd pidfile_remove(pfh); 3327194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3328194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 332974462Salfred exit (0); 333074462Salfred} 3331192934Srmacklem 3332