mountd.c revision 277352
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Herb Hasler and Rick Macklem at The University of Guelph. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 4. Neither the name of the University nor the names of its contributors 171558Srgrimes * may be used to endorse or promote products derived from this software 181558Srgrimes * without specific prior written permission. 191558Srgrimes * 201558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301558Srgrimes * SUCH DAMAGE. 311558Srgrimes */ 321558Srgrimes 331558Srgrimes#ifndef lint 3437663Scharnierstatic const char copyright[] = 351558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 361558Srgrimes The Regents of the University of California. All rights reserved.\n"; 372999Swollman#endif /*not lint*/ 381558Srgrimes 39105267Scharnier#if 0 401558Srgrimes#ifndef lint 4137663Scharnierstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42105267Scharnier#endif /*not lint*/ 4337663Scharnier#endif 441558Srgrimes 45105267Scharnier#include <sys/cdefs.h> 46105267Scharnier__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 277352 2015-01-19 00:33:32Z rstone $"); 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 **); 177222623Srmacklemstatic int create_service(struct netconfig *nconf); 178222623Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 179222623Srmacklemstatic void clearout_service(void); 18075635Siedowsevoid del_mlist(char *hostp, char *dirp); 18192882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 18292882Simpint do_mount(struct exportlist *, struct grouplist *, int, 18392882Simp struct xucred *, char *, int, struct statfs *); 18492882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 18592882Simp int *, int *, struct xucred *); 18692882Simpstruct exportlist *ex_search(fsid_t *); 18792882Simpstruct exportlist *get_exp(void); 18892882Simpvoid free_dir(struct dirlist *); 18992882Simpvoid free_exp(struct exportlist *); 19092882Simpvoid free_grp(struct grouplist *); 19192882Simpvoid free_host(struct hostlist *); 19292882Simpvoid get_exportlist(void); 19392882Simpint get_host(char *, struct grouplist *, struct grouplist *); 19492882Simpstruct hostlist *get_ht(void); 19592882Simpint get_line(void); 19692882Simpvoid get_mountlist(void); 19792882Simpint get_net(char *, struct netmsk *, int); 19892882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 19992882Simpstruct grouplist *get_grp(void); 20092882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 20192882Simp struct exportlist *, int); 20275754Siedowsevoid huphandler(int sig); 20375801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 20492882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 20592882Simpvoid nextfield(char **, char **); 20692882Simpvoid out_of_mem(void); 20792882Simpvoid parsecred(char *, struct xucred *); 208216587Scharnierint parsesec(char *, struct exportlist *); 209100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 21075801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 21175801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 21275801Siedowse struct sockaddr *samask); 21392882Simpint scan_tree(struct dirlist *, struct sockaddr *); 21492882Simpstatic void usage(void); 21592882Simpint xdr_dir(XDR *, char *); 21692882Simpint xdr_explist(XDR *, caddr_t); 217100117Salfredint xdr_explist_brief(XDR *, caddr_t); 218216587Scharnierint xdr_explist_common(XDR *, caddr_t, int); 21992882Simpint xdr_fhs(XDR *, caddr_t); 22092882Simpint xdr_mlist(XDR *, caddr_t); 22192882Simpvoid terminate(int); 2221558Srgrimes 2231558Srgrimesstruct exportlist *exphead; 2241558Srgrimesstruct mountlist *mlhead; 2251558Srgrimesstruct grouplist *grphead; 226166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 227166440Spjdchar **exnames; 228172827Smatteochar **hosts = NULL; 22972650Sgreenstruct xucred def_anon = { 23091354Sdd XUCRED_VERSION, 23172650Sgreen (uid_t)-2, 2321558Srgrimes 1, 23372650Sgreen { (gid_t)-2 }, 23472650Sgreen NULL 2351558Srgrimes}; 23625087Sdfrint force_v2 = 0; 2379336Sdfrint resvport_only = 1; 238172827Smatteoint nhosts = 0; 2399336Sdfrint dir_only = 1; 240121767Speterint dolog = 0; 24175754Siedowseint got_sighup = 0; 242172827Smatteoint xcreated = 0; 24374462Salfred 244172827Smatteochar *svcport_str = NULL; 245222623Srmacklemstatic int mallocd_svcport = 0; 246222623Srmacklemstatic int *sock_fd; 247222623Srmacklemstatic int sock_fdcnt; 248222623Srmacklemstatic int sock_fdpos; 249241568Srmacklemstatic int suspend_nfsd = 0; 250172827Smatteo 2511558Srgrimesint opt_flags; 25274462Salfredstatic int have_v6 = 1; 25374462Salfred 254192934Srmacklemint v4root_phase = 0; 255192934Srmacklemchar v4root_dirpath[PATH_MAX + 1]; 256220980Srmacklemint run_v4server = 1; 257192934Srmacklemint has_publicfh = 0; 258192934Srmacklem 259149433Spjdstruct pidfh *pfh = NULL; 26075801Siedowse/* Bits for opt_flags above */ 2611558Srgrimes#define OP_MAPROOT 0x01 2621558Srgrimes#define OP_MAPALL 0x02 26383653Speter/* 0x4 free */ 2641558Srgrimes#define OP_MASK 0x08 2651558Srgrimes#define OP_NET 0x10 2661558Srgrimes#define OP_ALLDIRS 0x40 26775801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 268100336Sjoerg#define OP_QUIET 0x100 26974462Salfred#define OP_MASKLEN 0x200 270184588Sdfr#define OP_SEC 0x400 2711558Srgrimes 2721558Srgrimes#ifdef DEBUG 2731558Srgrimesint debug = 1; 27492882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2751558Srgrimes#define syslog SYSLOG 2761558Srgrimes#else 2771558Srgrimesint debug = 0; 2781558Srgrimes#endif 2791558Srgrimes 2801558Srgrimes/* 2811558Srgrimes * Mountd server for NFS mount protocol as described in: 2821558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2831558Srgrimes * The optional arguments are the exports file name 2841558Srgrimes * default: _PATH_EXPORTS 2851558Srgrimes * and "-n" to allow nonroot mount. 2861558Srgrimes */ 2871558Srgrimesint 288216587Scharniermain(int argc, char **argv) 2891558Srgrimes{ 29075754Siedowse fd_set readfds; 291172827Smatteo struct netconfig *nconf; 292172827Smatteo char *endptr, **hosts_bak; 293172827Smatteo void *nc_handle; 294149433Spjd pid_t otherpid; 295172827Smatteo in_port_t svcport; 296172827Smatteo int c, k, s; 297109363Smbr int maxrec = RPC_MAXDATASIZE; 298222623Srmacklem int attempt_cnt, port_len, port_pos, ret; 299222623Srmacklem char **port_list; 3001558Srgrimes 30174462Salfred /* Check that another mountd isn't already running. */ 302150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 303149433Spjd if (pfh == NULL) { 304149433Spjd if (errno == EEXIST) 305149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 306149433Spjd warn("cannot open or create pidfile"); 307149433Spjd } 30874462Salfred 30974462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 31074462Salfred if (s < 0) 31174462Salfred have_v6 = 0; 31274462Salfred else 31374462Salfred close(s); 3142999Swollman 315241568Srmacklem while ((c = getopt(argc, argv, "2deh:lnop:rS")) != -1) 3161558Srgrimes switch (c) { 31725087Sdfr case '2': 31825087Sdfr force_v2 = 1; 31925087Sdfr break; 320192993Srmacklem case 'e': 321220980Srmacklem /* now a no-op, since this is the default */ 322192934Srmacklem break; 3239336Sdfr case 'n': 3249336Sdfr resvport_only = 0; 3259336Sdfr break; 3269336Sdfr case 'r': 3279336Sdfr dir_only = 0; 3289336Sdfr break; 3298688Sphk case 'd': 3308688Sphk debug = debug ? 0 : 1; 3318688Sphk break; 33231656Sguido case 'l': 333121767Speter dolog = 1; 33431656Sguido break; 335220980Srmacklem case 'o': 336220980Srmacklem run_v4server = 0; 337220980Srmacklem break; 338126572Sbms case 'p': 339126572Sbms endptr = NULL; 340126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 341126572Sbms if (endptr == NULL || *endptr != '\0' || 342126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 343126572Sbms usage(); 344172827Smatteo svcport_str = strdup(optarg); 345126572Sbms break; 346172827Smatteo case 'h': 347172827Smatteo ++nhosts; 348172827Smatteo hosts_bak = hosts; 349172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 350172827Smatteo if (hosts_bak == NULL) { 351172827Smatteo if (hosts != NULL) { 352172827Smatteo for (k = 0; k < nhosts; k++) 353172827Smatteo free(hosts[k]); 354172827Smatteo free(hosts); 355172827Smatteo out_of_mem(); 356172827Smatteo } 357172827Smatteo } 358172827Smatteo hosts = hosts_bak; 359172827Smatteo hosts[nhosts - 1] = strdup(optarg); 360172827Smatteo if (hosts[nhosts - 1] == NULL) { 361172827Smatteo for (k = 0; k < (nhosts - 1); k++) 362172827Smatteo free(hosts[k]); 363172827Smatteo free(hosts); 364172827Smatteo out_of_mem(); 365172827Smatteo } 366172827Smatteo break; 367241568Srmacklem case 'S': 368241568Srmacklem suspend_nfsd = 1; 369241568Srmacklem break; 3701558Srgrimes default: 37137663Scharnier usage(); 3721558Srgrimes }; 373192934Srmacklem 374192934Srmacklem /* 375220980Srmacklem * Unless the "-o" option was specified, try and run "nfsd". 376220980Srmacklem * If "-o" was specified, try and run "nfsserver". 377192934Srmacklem */ 378192934Srmacklem if (run_v4server > 0) { 379192934Srmacklem if (modfind("nfsd") < 0) { 380192934Srmacklem /* Not present in kernel, try loading it */ 381192934Srmacklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 382192934Srmacklem errx(1, "NFS server is not available"); 383192934Srmacklem } 384192934Srmacklem } else if (modfind("nfsserver") < 0) { 385192934Srmacklem /* Not present in kernel, try loading it */ 386192934Srmacklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 387192934Srmacklem errx(1, "NFS server is not available"); 388192934Srmacklem } 389192934Srmacklem 3901558Srgrimes argc -= optind; 3911558Srgrimes argv += optind; 3921558Srgrimes grphead = (struct grouplist *)NULL; 3931558Srgrimes exphead = (struct exportlist *)NULL; 3941558Srgrimes mlhead = (struct mountlist *)NULL; 395166440Spjd if (argc > 0) 396166440Spjd exnames = argv; 397166440Spjd else 398166440Spjd exnames = exnames_default; 3991558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 4001558Srgrimes if (debug) 40137663Scharnier warnx("getting export list"); 4021558Srgrimes get_exportlist(); 4031558Srgrimes if (debug) 40437663Scharnier warnx("getting mount list"); 4051558Srgrimes get_mountlist(); 4061558Srgrimes if (debug) 40737663Scharnier warnx("here we go"); 4081558Srgrimes if (debug == 0) { 4091558Srgrimes daemon(0, 0); 4101558Srgrimes signal(SIGINT, SIG_IGN); 4111558Srgrimes signal(SIGQUIT, SIG_IGN); 4121558Srgrimes } 41375754Siedowse signal(SIGHUP, huphandler); 41474462Salfred signal(SIGTERM, terminate); 415164394Srodrigc signal(SIGPIPE, SIG_IGN); 416149433Spjd 417149433Spjd pidfile_write(pfh); 418149433Spjd 419194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 420194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 421109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 422109363Smbr 42324759Sguido if (!resvport_only) { 42483687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 42583687Speter &resvport_only, sizeof(resvport_only)) != 0 && 42683687Speter errno != ENOENT) { 42724759Sguido syslog(LOG_ERR, "sysctl: %m"); 42824759Sguido exit(1); 42924759Sguido } 43024330Sguido } 431126572Sbms 432172827Smatteo /* 433172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 434172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 435172827Smatteo * list. 436172827Smatteo */ 437172827Smatteo if (nhosts == 0) { 438172827Smatteo hosts = malloc(sizeof(char**)); 439172827Smatteo if (hosts == NULL) 440172827Smatteo out_of_mem(); 441172827Smatteo hosts[0] = "*"; 442172827Smatteo nhosts = 1; 443172827Smatteo } else { 444172827Smatteo hosts_bak = hosts; 445172827Smatteo if (have_v6) { 446172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 447172827Smatteo sizeof(char *)); 448172827Smatteo if (hosts_bak == NULL) { 449172827Smatteo for (k = 0; k < nhosts; k++) 450172827Smatteo free(hosts[k]); 451172827Smatteo free(hosts); 452172827Smatteo out_of_mem(); 453172827Smatteo } else 454172827Smatteo hosts = hosts_bak; 455172827Smatteo nhosts += 2; 456172827Smatteo hosts[nhosts - 2] = "::1"; 457172827Smatteo } else { 458172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 459172827Smatteo if (hosts_bak == NULL) { 460172827Smatteo for (k = 0; k < nhosts; k++) 461172827Smatteo free(hosts[k]); 462172827Smatteo free(hosts); 463172827Smatteo out_of_mem(); 464172827Smatteo } else { 465172827Smatteo nhosts += 1; 466172827Smatteo hosts = hosts_bak; 467126572Sbms } 468172827Smatteo } 46974462Salfred 470172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 47174462Salfred } 47274462Salfred 473222623Srmacklem attempt_cnt = 1; 474222623Srmacklem sock_fdcnt = 0; 475222623Srmacklem sock_fd = NULL; 476222623Srmacklem port_list = NULL; 477222623Srmacklem port_len = 0; 478172827Smatteo nc_handle = setnetconfig(); 479172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 480172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 481172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 482172827Smatteo "inet6") == 0) { 483172827Smatteo /* DO NOTHING */ 484222623Srmacklem } else { 485222623Srmacklem ret = create_service(nconf); 486222623Srmacklem if (ret == 1) 487222623Srmacklem /* Ignore this call */ 488222623Srmacklem continue; 489222623Srmacklem if (ret < 0) { 490222623Srmacklem /* 491222623Srmacklem * Failed to bind port, so close off 492222623Srmacklem * all sockets created and try again 493222623Srmacklem * if the port# was dynamically 494222623Srmacklem * assigned via bind(2). 495222623Srmacklem */ 496222623Srmacklem clearout_service(); 497222623Srmacklem if (mallocd_svcport != 0 && 498222623Srmacklem attempt_cnt < GETPORT_MAXTRY) { 499222623Srmacklem free(svcport_str); 500222623Srmacklem svcport_str = NULL; 501222623Srmacklem mallocd_svcport = 0; 502222623Srmacklem } else { 503222623Srmacklem errno = EADDRINUSE; 504222623Srmacklem syslog(LOG_ERR, 505222623Srmacklem "bindresvport_sa: %m"); 506222623Srmacklem exit(1); 507222623Srmacklem } 508222623Srmacklem 509222623Srmacklem /* Start over at the first service. */ 510222623Srmacklem free(sock_fd); 511222623Srmacklem sock_fdcnt = 0; 512222623Srmacklem sock_fd = NULL; 513222623Srmacklem nc_handle = setnetconfig(); 514222623Srmacklem attempt_cnt++; 515222623Srmacklem } else if (mallocd_svcport != 0 && 516222623Srmacklem attempt_cnt == GETPORT_MAXTRY) { 517222623Srmacklem /* 518222623Srmacklem * For the last attempt, allow 519222623Srmacklem * different port #s for each nconf 520222623Srmacklem * by saving the svcport_str and 521222623Srmacklem * setting it back to NULL. 522222623Srmacklem */ 523222623Srmacklem port_list = realloc(port_list, 524222623Srmacklem (port_len + 1) * sizeof(char *)); 525222623Srmacklem if (port_list == NULL) 526222623Srmacklem out_of_mem(); 527222623Srmacklem port_list[port_len++] = svcport_str; 528222623Srmacklem svcport_str = NULL; 529222623Srmacklem mallocd_svcport = 0; 530222623Srmacklem } 531222623Srmacklem } 532222623Srmacklem } 533222623Srmacklem } 534222623Srmacklem 535222623Srmacklem /* 536222623Srmacklem * Successfully bound the ports, so call complete_service() to 537222623Srmacklem * do the rest of the setup on the service(s). 538222623Srmacklem */ 539222623Srmacklem sock_fdpos = 0; 540222623Srmacklem port_pos = 0; 541222623Srmacklem nc_handle = setnetconfig(); 542222623Srmacklem while ((nconf = getnetconfig(nc_handle))) { 543222623Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 544222623Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 545222623Srmacklem "inet6") == 0) { 546222623Srmacklem /* DO NOTHING */ 547222623Srmacklem } else if (port_list != NULL) { 548222623Srmacklem if (port_pos >= port_len) { 549222623Srmacklem syslog(LOG_ERR, "too many port#s"); 550222623Srmacklem exit(1); 551222623Srmacklem } 552222623Srmacklem complete_service(nconf, port_list[port_pos++]); 553172827Smatteo } else 554222623Srmacklem complete_service(nconf, svcport_str); 555172827Smatteo } 55674462Salfred } 557172827Smatteo endnetconfig(nc_handle); 558222623Srmacklem free(sock_fd); 559222623Srmacklem if (port_list != NULL) { 560222623Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 561222623Srmacklem free(port_list[port_pos]); 562222623Srmacklem free(port_list); 563222623Srmacklem } 56474462Salfred 56574462Salfred if (xcreated == 0) { 56674462Salfred syslog(LOG_ERR, "could not create any services"); 5671558Srgrimes exit(1); 5681558Srgrimes } 56975754Siedowse 57075754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 57175754Siedowse for (;;) { 57275754Siedowse if (got_sighup) { 57375754Siedowse get_exportlist(); 57475754Siedowse got_sighup = 0; 57575754Siedowse } 57675754Siedowse readfds = svc_fdset; 57775754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 57875754Siedowse case -1: 57975754Siedowse if (errno == EINTR) 58075754Siedowse continue; 58175754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 58275754Siedowse exit(1); 58375754Siedowse case 0: 58475754Siedowse continue; 58575754Siedowse default: 58675754Siedowse svc_getreqset(&readfds); 58775754Siedowse } 58875754Siedowse } 589172827Smatteo} 590172827Smatteo 591172827Smatteo/* 592172827Smatteo * This routine creates and binds sockets on the appropriate 593222623Srmacklem * addresses. It gets called one time for each transport. 594222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 595222623Srmacklem * bind failed with EADDRINUSE. 596222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and 597222623Srmacklem * the total count of them is maintained in sock_fdcnt. 598172827Smatteo */ 599222623Srmacklemstatic int 600172827Smatteocreate_service(struct netconfig *nconf) 601172827Smatteo{ 602172827Smatteo struct addrinfo hints, *res = NULL; 603172827Smatteo struct sockaddr_in *sin; 604172827Smatteo struct sockaddr_in6 *sin6; 605172827Smatteo struct __rpc_sockinfo si; 606172827Smatteo int aicode; 607172827Smatteo int fd; 608172827Smatteo int nhostsbak; 609172827Smatteo int one = 1; 610172827Smatteo int r; 611172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 612222623Srmacklem int mallocd_res; 613172827Smatteo 614172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 615172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 616172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 617222623Srmacklem return (1); /* not my type */ 618172827Smatteo 619172827Smatteo /* 620172827Smatteo * XXX - using RPC library internal functions. 621172827Smatteo */ 622172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 623172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 624172827Smatteo nconf->nc_netid); 625222623Srmacklem return (1); 626172827Smatteo } 627172827Smatteo 628172827Smatteo /* Get mountd's address on this transport */ 629172827Smatteo memset(&hints, 0, sizeof hints); 630172827Smatteo hints.ai_family = si.si_af; 631172827Smatteo hints.ai_socktype = si.si_socktype; 632172827Smatteo hints.ai_protocol = si.si_proto; 633172827Smatteo 634172827Smatteo /* 635172827Smatteo * Bind to specific IPs if asked to 636172827Smatteo */ 637172827Smatteo nhostsbak = nhosts; 638172827Smatteo while (nhostsbak > 0) { 639172827Smatteo --nhostsbak; 640222623Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 641222623Srmacklem if (sock_fd == NULL) 642222623Srmacklem out_of_mem(); 643222623Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 644222623Srmacklem mallocd_res = 0; 645222623Srmacklem 646277352Srstone hints.ai_flags = AI_PASSIVE; 647277352Srstone 648172827Smatteo /* 649172827Smatteo * XXX - using RPC library internal functions. 650172827Smatteo */ 651172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 652172827Smatteo int non_fatal = 0; 653244538Skevlo if (errno == EAFNOSUPPORT && 654172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 655172827Smatteo non_fatal = 1; 656172827Smatteo 657172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 658172827Smatteo "cannot create socket for %s", nconf->nc_netid); 659222623Srmacklem if (non_fatal != 0) 660222623Srmacklem continue; 661222623Srmacklem exit(1); 662172827Smatteo } 663172827Smatteo 664172827Smatteo switch (hints.ai_family) { 665172827Smatteo case AF_INET: 666172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 667172827Smatteo host_addr) == 1) { 668222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 669172827Smatteo } else { 670172827Smatteo /* 671172827Smatteo * Skip if we have an AF_INET6 address. 672172827Smatteo */ 673172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 674172827Smatteo host_addr) == 1) { 675172827Smatteo close(fd); 676172827Smatteo continue; 677172827Smatteo } 678172827Smatteo } 679172827Smatteo break; 680172827Smatteo case AF_INET6: 681172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 682172827Smatteo host_addr) == 1) { 683222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 684172827Smatteo } else { 685172827Smatteo /* 686172827Smatteo * Skip if we have an AF_INET address. 687172827Smatteo */ 688172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 689172827Smatteo host_addr) == 1) { 690172827Smatteo close(fd); 691172827Smatteo continue; 692172827Smatteo } 693172827Smatteo } 694172827Smatteo 695172827Smatteo /* 696172827Smatteo * We're doing host-based access checks here, so don't 697172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 698172827Smatteo * disable it by default on NFS sockets too. 699172827Smatteo */ 700172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 701172827Smatteo sizeof one) < 0) { 702172827Smatteo syslog(LOG_ERR, 703172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 704172827Smatteo exit(1); 705172827Smatteo } 706172827Smatteo break; 707172827Smatteo default: 708172827Smatteo break; 709172827Smatteo } 710172827Smatteo 711172827Smatteo /* 712172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 713172827Smatteo */ 714172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 715172827Smatteo if (svcport_str == NULL) { 716172827Smatteo res = malloc(sizeof(struct addrinfo)); 717172827Smatteo if (res == NULL) 718172827Smatteo out_of_mem(); 719222623Srmacklem mallocd_res = 1; 720172827Smatteo res->ai_flags = hints.ai_flags; 721172827Smatteo res->ai_family = hints.ai_family; 722172827Smatteo res->ai_protocol = hints.ai_protocol; 723172827Smatteo switch (res->ai_family) { 724172827Smatteo case AF_INET: 725172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 726172827Smatteo if (sin == NULL) 727172827Smatteo out_of_mem(); 728172827Smatteo sin->sin_family = AF_INET; 729172827Smatteo sin->sin_port = htons(0); 730172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 731172827Smatteo res->ai_addr = (struct sockaddr*) sin; 732172827Smatteo res->ai_addrlen = (socklen_t) 733222623Srmacklem sizeof(struct sockaddr_in); 734172827Smatteo break; 735172827Smatteo case AF_INET6: 736172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 737173056Ssimon if (sin6 == NULL) 738172827Smatteo out_of_mem(); 739172827Smatteo sin6->sin6_family = AF_INET6; 740172827Smatteo sin6->sin6_port = htons(0); 741172827Smatteo sin6->sin6_addr = in6addr_any; 742172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 743172827Smatteo res->ai_addrlen = (socklen_t) 744222623Srmacklem sizeof(struct sockaddr_in6); 745222623Srmacklem break; 746172827Smatteo default: 747222623Srmacklem syslog(LOG_ERR, "bad addr fam %d", 748222623Srmacklem res->ai_family); 749222623Srmacklem exit(1); 750172827Smatteo } 751172827Smatteo } else { 752172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 753172827Smatteo &hints, &res)) != 0) { 754172827Smatteo syslog(LOG_ERR, 755172827Smatteo "cannot get local address for %s: %s", 756172827Smatteo nconf->nc_netid, 757172827Smatteo gai_strerror(aicode)); 758222623Srmacklem close(fd); 759172827Smatteo continue; 760172827Smatteo } 761172827Smatteo } 762172827Smatteo } else { 763172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 764172827Smatteo &hints, &res)) != 0) { 765172827Smatteo syslog(LOG_ERR, 766172827Smatteo "cannot get local address for %s: %s", 767172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 768222623Srmacklem close(fd); 769172827Smatteo continue; 770172827Smatteo } 771172827Smatteo } 772172827Smatteo 773222623Srmacklem /* Store the fd. */ 774222623Srmacklem sock_fd[sock_fdcnt - 1] = fd; 775222623Srmacklem 776222623Srmacklem /* Now, attempt the bind. */ 777172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 778172827Smatteo if (r != 0) { 779222623Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 780222623Srmacklem if (mallocd_res != 0) { 781222623Srmacklem free(res->ai_addr); 782222623Srmacklem free(res); 783222623Srmacklem } else 784222623Srmacklem freeaddrinfo(res); 785222623Srmacklem return (-1); 786222623Srmacklem } 787172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 788172827Smatteo exit(1); 789172827Smatteo } 790172827Smatteo 791222623Srmacklem if (svcport_str == NULL) { 792222623Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 793222623Srmacklem if (svcport_str == NULL) 794222623Srmacklem out_of_mem(); 795222623Srmacklem mallocd_svcport = 1; 796222623Srmacklem 797222623Srmacklem if (getnameinfo(res->ai_addr, 798222623Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 799222623Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 800222623Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 801222623Srmacklem errx(1, "Cannot get port number"); 802222623Srmacklem } 803222623Srmacklem if (mallocd_res != 0) { 804222623Srmacklem free(res->ai_addr); 805222623Srmacklem free(res); 806222623Srmacklem } else 807222623Srmacklem freeaddrinfo(res); 808222623Srmacklem res = NULL; 809222623Srmacklem } 810222623Srmacklem return (0); 811222623Srmacklem} 812222623Srmacklem 813222623Srmacklem/* 814222623Srmacklem * Called after all the create_service() calls have succeeded, to complete 815222623Srmacklem * the setup and registration. 816222623Srmacklem */ 817222623Srmacklemstatic void 818222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 819222623Srmacklem{ 820222623Srmacklem struct addrinfo hints, *res = NULL; 821222623Srmacklem struct __rpc_sockinfo si; 822222623Srmacklem struct netbuf servaddr; 823222623Srmacklem SVCXPRT *transp = NULL; 824222623Srmacklem int aicode, fd, nhostsbak; 825222623Srmacklem int registered = 0; 826222623Srmacklem 827222623Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 828222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 829222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 830222623Srmacklem return; /* not my type */ 831222623Srmacklem 832222623Srmacklem /* 833222623Srmacklem * XXX - using RPC library internal functions. 834222623Srmacklem */ 835222623Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 836222623Srmacklem syslog(LOG_ERR, "cannot get information for %s", 837222623Srmacklem nconf->nc_netid); 838222623Srmacklem return; 839222623Srmacklem } 840222623Srmacklem 841222623Srmacklem nhostsbak = nhosts; 842222623Srmacklem while (nhostsbak > 0) { 843222623Srmacklem --nhostsbak; 844222623Srmacklem if (sock_fdpos >= sock_fdcnt) { 845222623Srmacklem /* Should never happen. */ 846222623Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 847222623Srmacklem return; 848222623Srmacklem } 849222623Srmacklem fd = sock_fd[sock_fdpos++]; 850222623Srmacklem if (fd < 0) 851222623Srmacklem continue; 852222623Srmacklem 853172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 854172827Smatteo listen(fd, SOMAXCONN); 855172827Smatteo 856172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 857172827Smatteo transp = svc_dg_create(fd, 0, 0); 858172827Smatteo else 859172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 860172827Smatteo RPC_MAXDATASIZE); 861172827Smatteo 862172827Smatteo if (transp != (SVCXPRT *) NULL) { 863194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 864172827Smatteo NULL)) 865172827Smatteo syslog(LOG_ERR, 866194880Sdfr "can't register %s MOUNTVERS service", 867172827Smatteo nconf->nc_netid); 868172827Smatteo if (!force_v2) { 869194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 870172827Smatteo mntsrv, NULL)) 871172827Smatteo syslog(LOG_ERR, 872194880Sdfr "can't register %s MOUNTVERS3 service", 873172827Smatteo nconf->nc_netid); 874172827Smatteo } 875172827Smatteo } else 876172827Smatteo syslog(LOG_WARNING, "can't create %s services", 877172827Smatteo nconf->nc_netid); 878172827Smatteo 879172827Smatteo if (registered == 0) { 880172827Smatteo registered = 1; 881172827Smatteo memset(&hints, 0, sizeof hints); 882172827Smatteo hints.ai_flags = AI_PASSIVE; 883172827Smatteo hints.ai_family = si.si_af; 884172827Smatteo hints.ai_socktype = si.si_socktype; 885172827Smatteo hints.ai_protocol = si.si_proto; 886172827Smatteo 887222623Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 888172827Smatteo &res)) != 0) { 889172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 890172827Smatteo gai_strerror(aicode)); 891172827Smatteo exit(1); 892172827Smatteo } 893172827Smatteo 894172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 895172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 896172827Smatteo servaddr.len = res->ai_addrlen; 897172827Smatteo 898194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 899194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 900172827Smatteo 901172827Smatteo xcreated++; 902172827Smatteo freeaddrinfo(res); 903172827Smatteo } 904172827Smatteo } /* end while */ 9051558Srgrimes} 9061558Srgrimes 907222623Srmacklem/* 908222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the 909222623Srmacklem * cycle of socket creation/binding can start anew. 910222623Srmacklem */ 91137663Scharnierstatic void 912222623Srmacklemclearout_service(void) 913222623Srmacklem{ 914222623Srmacklem int i; 915222623Srmacklem 916222623Srmacklem for (i = 0; i < sock_fdcnt; i++) { 917222623Srmacklem if (sock_fd[i] >= 0) { 918222623Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 919222623Srmacklem close(sock_fd[i]); 920222623Srmacklem } 921222623Srmacklem } 922222623Srmacklem} 923222623Srmacklem 924222623Srmacklemstatic void 925216587Scharnierusage(void) 92637663Scharnier{ 92737663Scharnier fprintf(stderr, 928192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 929241568Srmacklem "[-S] [-h <bindip>] [export_file ...]\n"); 93037663Scharnier exit(1); 93137663Scharnier} 93237663Scharnier 9331558Srgrimes/* 9341558Srgrimes * The mount rpc service 9351558Srgrimes */ 9361558Srgrimesvoid 937216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp) 9381558Srgrimes{ 9391558Srgrimes struct exportlist *ep; 9401558Srgrimes struct dirlist *dp; 9419336Sdfr struct fhreturn fhr; 9421558Srgrimes struct stat stb; 9431558Srgrimes struct statfs fsb; 94474462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 94574462Salfred int lookup_failed = 1; 94674462Salfred struct sockaddr *saddr; 9479336Sdfr u_short sport; 948194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 94928911Sguido int bad = 0, defset, hostset; 9509336Sdfr sigset_t sighup_mask; 951240902Srmacklem int numsecflavors, *secflavorsp; 9521558Srgrimes 9539336Sdfr sigemptyset(&sighup_mask); 9549336Sdfr sigaddset(&sighup_mask, SIGHUP); 95574462Salfred saddr = svc_getrpccaller(transp)->buf; 95674462Salfred switch (saddr->sa_family) { 95774462Salfred case AF_INET6: 95875635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 95974462Salfred break; 96074462Salfred case AF_INET: 96175635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 96274462Salfred break; 96374462Salfred default: 96474462Salfred syslog(LOG_ERR, "request from unknown address family"); 96574462Salfred return; 96674462Salfred } 96774462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 96874462Salfred NULL, 0, 0); 96974462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 97074462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 9711558Srgrimes switch (rqstp->rq_proc) { 9721558Srgrimes case NULLPROC: 973121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 97437663Scharnier syslog(LOG_ERR, "can't send reply"); 9751558Srgrimes return; 976194880Sdfr case MOUNTPROC_MNT: 9779336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 97831656Sguido syslog(LOG_NOTICE, 97931656Sguido "mount request from %s from unprivileged port", 98074462Salfred numerichost); 9811558Srgrimes svcerr_weakauth(transp); 9821558Srgrimes return; 9831558Srgrimes } 984121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 98531656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 98674462Salfred numerichost); 9871558Srgrimes svcerr_decode(transp); 9881558Srgrimes return; 9891558Srgrimes } 9901558Srgrimes 9911558Srgrimes /* 9921558Srgrimes * Get the real pathname and make sure it is a directory 9939336Sdfr * or a regular file if the -r option was specified 9949336Sdfr * and it exists. 9951558Srgrimes */ 99651968Salfred if (realpath(rpcpath, dirpath) == NULL || 9971558Srgrimes stat(dirpath, &stb) < 0 || 9989336Sdfr (!S_ISDIR(stb.st_mode) && 99974462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 10001558Srgrimes statfs(dirpath, &fsb) < 0) { 10011558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 100231656Sguido syslog(LOG_NOTICE, 100337663Scharnier "mount request from %s for non existent path %s", 100474462Salfred numerichost, dirpath); 10051558Srgrimes if (debug) 100637663Scharnier warnx("stat failed on %s", dirpath); 100728911Sguido bad = ENOENT; /* We will send error reply later */ 10081558Srgrimes } 10091558Srgrimes 10101558Srgrimes /* Check in the exports list */ 10119336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10121558Srgrimes ep = ex_search(&fsb.f_fsid); 10139336Sdfr hostset = defset = 0; 1014240902Srmacklem if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset, 1015240902Srmacklem &numsecflavors, &secflavorsp) || 10161558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 1017240902Srmacklem chk_host(dp, saddr, &defset, &hostset, &numsecflavors, 1018240902Srmacklem &secflavorsp)) || 101974462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 102074462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 102128911Sguido if (bad) { 1022121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 102328911Sguido (caddr_t)&bad)) 102437663Scharnier syslog(LOG_ERR, "can't send reply"); 102528911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 102628911Sguido return; 102728911Sguido } 1028240902Srmacklem if (hostset & DP_HOSTSET) { 10299336Sdfr fhr.fhr_flag = hostset; 1030240902Srmacklem fhr.fhr_numsecflavors = numsecflavors; 1031240902Srmacklem fhr.fhr_secflavors = secflavorsp; 1032240902Srmacklem } else { 10339336Sdfr fhr.fhr_flag = defset; 1034240902Srmacklem fhr.fhr_numsecflavors = ep->ex_defnumsecflavors; 1035240902Srmacklem fhr.fhr_secflavors = ep->ex_defsecflavors; 1036240902Srmacklem } 10379336Sdfr fhr.fhr_vers = rqstp->rq_vers; 10381558Srgrimes /* Get the file handle */ 103923681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 10409336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 10411558Srgrimes bad = errno; 104237663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1043121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 10441558Srgrimes (caddr_t)&bad)) 104537663Scharnier syslog(LOG_ERR, "can't send reply"); 10469336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10471558Srgrimes return; 10481558Srgrimes } 1049121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1050121556Speter (caddr_t)&fhr)) 105137663Scharnier syslog(LOG_ERR, "can't send reply"); 105274462Salfred if (!lookup_failed) 105374462Salfred add_mlist(host, dirpath); 10541558Srgrimes else 105574462Salfred add_mlist(numerichost, dirpath); 10561558Srgrimes if (debug) 105737663Scharnier warnx("mount successful"); 1058121767Speter if (dolog) 105931656Sguido syslog(LOG_NOTICE, 106031656Sguido "mount request succeeded from %s for %s", 106174462Salfred numerichost, dirpath); 106231656Sguido } else { 10631558Srgrimes bad = EACCES; 106431656Sguido syslog(LOG_NOTICE, 106531656Sguido "mount request denied from %s for %s", 106674462Salfred numerichost, dirpath); 106731656Sguido } 106828911Sguido 1069121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1070121556Speter (caddr_t)&bad)) 107137663Scharnier syslog(LOG_ERR, "can't send reply"); 10729336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10731558Srgrimes return; 1074194880Sdfr case MOUNTPROC_DUMP: 1075121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 107637663Scharnier syslog(LOG_ERR, "can't send reply"); 1077121767Speter else if (dolog) 107831656Sguido syslog(LOG_NOTICE, 107931656Sguido "dump request succeeded from %s", 108074462Salfred numerichost); 10811558Srgrimes return; 1082194880Sdfr case MOUNTPROC_UMNT: 10839336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 108431656Sguido syslog(LOG_NOTICE, 108531656Sguido "umount request from %s from unprivileged port", 108674462Salfred numerichost); 10871558Srgrimes svcerr_weakauth(transp); 10881558Srgrimes return; 10891558Srgrimes } 1090121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 109131656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 109274462Salfred numerichost); 10931558Srgrimes svcerr_decode(transp); 10941558Srgrimes return; 10951558Srgrimes } 109651968Salfred if (realpath(rpcpath, dirpath) == NULL) { 109751968Salfred syslog(LOG_NOTICE, "umount request from %s " 109851968Salfred "for non existent path %s", 109974462Salfred numerichost, dirpath); 110051968Salfred } 1101121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 110237663Scharnier syslog(LOG_ERR, "can't send reply"); 110374462Salfred if (!lookup_failed) 110475635Siedowse del_mlist(host, dirpath); 110575635Siedowse del_mlist(numerichost, dirpath); 1106121767Speter if (dolog) 110731656Sguido syslog(LOG_NOTICE, 110831656Sguido "umount request succeeded from %s for %s", 110974462Salfred numerichost, dirpath); 11101558Srgrimes return; 1111194880Sdfr case MOUNTPROC_UMNTALL: 11129336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 111331656Sguido syslog(LOG_NOTICE, 111431656Sguido "umountall request from %s from unprivileged port", 111574462Salfred numerichost); 11161558Srgrimes svcerr_weakauth(transp); 11171558Srgrimes return; 11181558Srgrimes } 1119121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 112037663Scharnier syslog(LOG_ERR, "can't send reply"); 112174462Salfred if (!lookup_failed) 112275635Siedowse del_mlist(host, NULL); 112375635Siedowse del_mlist(numerichost, NULL); 1124121767Speter if (dolog) 112531656Sguido syslog(LOG_NOTICE, 112631656Sguido "umountall request succeeded from %s", 112774462Salfred numerichost); 11281558Srgrimes return; 1129194880Sdfr case MOUNTPROC_EXPORT: 1130121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1131121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1132121556Speter (caddr_t)NULL)) 1133100117Salfred syslog(LOG_ERR, "can't send reply"); 1134121767Speter if (dolog) 113531656Sguido syslog(LOG_NOTICE, 113631656Sguido "export request succeeded from %s", 113774462Salfred numerichost); 11381558Srgrimes return; 11391558Srgrimes default: 11401558Srgrimes svcerr_noproc(transp); 11411558Srgrimes return; 11421558Srgrimes } 11431558Srgrimes} 11441558Srgrimes 11451558Srgrimes/* 11461558Srgrimes * Xdr conversion for a dirpath string 11471558Srgrimes */ 11481558Srgrimesint 1149216587Scharnierxdr_dir(XDR *xdrsp, char *dirp) 11501558Srgrimes{ 1151194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 11521558Srgrimes} 11531558Srgrimes 11541558Srgrimes/* 11559336Sdfr * Xdr routine to generate file handle reply 11561558Srgrimes */ 11571558Srgrimesint 1158216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp) 11591558Srgrimes{ 116092806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 11619336Sdfr u_long ok = 0, len, auth; 1162184588Sdfr int i; 11631558Srgrimes 11641558Srgrimes if (!xdr_long(xdrsp, &ok)) 11651558Srgrimes return (0); 11669336Sdfr switch (fhrp->fhr_vers) { 11679336Sdfr case 1: 11689336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 11699336Sdfr case 3: 11709336Sdfr len = NFSX_V3FH; 11719336Sdfr if (!xdr_long(xdrsp, &len)) 11729336Sdfr return (0); 11739336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 11749336Sdfr return (0); 1175184588Sdfr if (fhrp->fhr_numsecflavors) { 1176184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1177184588Sdfr return (0); 1178184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1179184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1180184588Sdfr return (0); 1181184588Sdfr return (1); 1182184588Sdfr } else { 1183184588Sdfr auth = AUTH_SYS; 1184184588Sdfr len = 1; 1185184588Sdfr if (!xdr_long(xdrsp, &len)) 1186184588Sdfr return (0); 1187184588Sdfr return (xdr_long(xdrsp, &auth)); 1188184588Sdfr } 11899336Sdfr }; 11909336Sdfr return (0); 11911558Srgrimes} 11921558Srgrimes 11931558Srgrimesint 1194216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 11951558Srgrimes{ 11961558Srgrimes struct mountlist *mlp; 11971558Srgrimes int true = 1; 11981558Srgrimes int false = 0; 11991558Srgrimes char *strp; 12001558Srgrimes 12011558Srgrimes mlp = mlhead; 12021558Srgrimes while (mlp) { 12031558Srgrimes if (!xdr_bool(xdrsp, &true)) 12041558Srgrimes return (0); 12051558Srgrimes strp = &mlp->ml_host[0]; 1206194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 12071558Srgrimes return (0); 12081558Srgrimes strp = &mlp->ml_dirp[0]; 1209194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12101558Srgrimes return (0); 12111558Srgrimes mlp = mlp->ml_next; 12121558Srgrimes } 12131558Srgrimes if (!xdr_bool(xdrsp, &false)) 12141558Srgrimes return (0); 12151558Srgrimes return (1); 12161558Srgrimes} 12171558Srgrimes 12181558Srgrimes/* 12191558Srgrimes * Xdr conversion for export list 12201558Srgrimes */ 12211558Srgrimesint 1222216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 12231558Srgrimes{ 12241558Srgrimes struct exportlist *ep; 12251558Srgrimes int false = 0; 12269336Sdfr int putdef; 12279336Sdfr sigset_t sighup_mask; 12281558Srgrimes 12299336Sdfr sigemptyset(&sighup_mask); 12309336Sdfr sigaddset(&sighup_mask, SIGHUP); 12319336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 12321558Srgrimes ep = exphead; 12331558Srgrimes while (ep) { 12341558Srgrimes putdef = 0; 1235100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1236100117Salfred &putdef, brief)) 12371558Srgrimes goto errout; 12381558Srgrimes if (ep->ex_defdir && putdef == 0 && 12391558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1240100117Salfred &putdef, brief)) 12411558Srgrimes goto errout; 12421558Srgrimes ep = ep->ex_next; 12431558Srgrimes } 12449336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12451558Srgrimes if (!xdr_bool(xdrsp, &false)) 12461558Srgrimes return (0); 12471558Srgrimes return (1); 12481558Srgrimeserrout: 12499336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12501558Srgrimes return (0); 12511558Srgrimes} 12521558Srgrimes 12531558Srgrimes/* 12541558Srgrimes * Called from xdr_explist() to traverse the tree and export the 12551558Srgrimes * directory paths. 12561558Srgrimes */ 12571558Srgrimesint 1258216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1259216587Scharnier int brief) 12601558Srgrimes{ 12611558Srgrimes struct grouplist *grp; 12621558Srgrimes struct hostlist *hp; 12631558Srgrimes int true = 1; 12641558Srgrimes int false = 0; 12651558Srgrimes int gotalldir = 0; 12661558Srgrimes char *strp; 12671558Srgrimes 12681558Srgrimes if (dp) { 1269100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 12701558Srgrimes return (1); 12711558Srgrimes if (!xdr_bool(xdrsp, &true)) 12721558Srgrimes return (1); 12731558Srgrimes strp = dp->dp_dirp; 1274194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12751558Srgrimes return (1); 12761558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 12771558Srgrimes gotalldir = 1; 12781558Srgrimes *putdefp = 1; 12791558Srgrimes } 1280100117Salfred if (brief) { 1281100117Salfred if (!xdr_bool(xdrsp, &true)) 1282100117Salfred return (1); 1283100117Salfred strp = "(...)"; 1284194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1285100117Salfred return (1); 1286100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 12871558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 12881558Srgrimes hp = dp->dp_hosts; 12891558Srgrimes while (hp) { 12901558Srgrimes grp = hp->ht_grp; 12911558Srgrimes if (grp->gr_type == GT_HOST) { 12921558Srgrimes if (!xdr_bool(xdrsp, &true)) 12931558Srgrimes return (1); 129474462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 12958871Srgrimes if (!xdr_string(xdrsp, &strp, 1296194880Sdfr MNTNAMLEN)) 12971558Srgrimes return (1); 12981558Srgrimes } else if (grp->gr_type == GT_NET) { 12991558Srgrimes if (!xdr_bool(xdrsp, &true)) 13001558Srgrimes return (1); 13011558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 13028871Srgrimes if (!xdr_string(xdrsp, &strp, 1303194880Sdfr MNTNAMLEN)) 13041558Srgrimes return (1); 13051558Srgrimes } 13061558Srgrimes hp = hp->ht_next; 13071558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 13081558Srgrimes hp = adp->dp_hosts; 13091558Srgrimes gotalldir = 0; 13101558Srgrimes } 13111558Srgrimes } 13121558Srgrimes } 13131558Srgrimes if (!xdr_bool(xdrsp, &false)) 13141558Srgrimes return (1); 1315100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 13161558Srgrimes return (1); 13171558Srgrimes } 13181558Srgrimes return (0); 13191558Srgrimes} 13201558Srgrimes 1321100117Salfredint 1322216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp) 1323100117Salfred{ 1324100117Salfred 1325100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1326100117Salfred} 1327100117Salfred 1328100117Salfredint 1329216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1330100117Salfred{ 1331100117Salfred 1332100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1333100117Salfred} 1334100117Salfred 133596622Siedowsechar *line; 133696622Siedowseint linesize; 13371558SrgrimesFILE *exp_file; 13381558Srgrimes 13391558Srgrimes/* 1340166440Spjd * Get the export list from one, currently open file 13411558Srgrimes */ 1342166440Spjdstatic void 1343216587Scharnierget_exportlist_one(void) 13441558Srgrimes{ 13451558Srgrimes struct exportlist *ep, *ep2; 13461558Srgrimes struct grouplist *grp, *tgrp; 13471558Srgrimes struct exportlist **epp; 13481558Srgrimes struct dirlist *dirhead; 1349166440Spjd struct statfs fsb; 135072650Sgreen struct xucred anon; 13511558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1352166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 13531558Srgrimes 1354192934Srmacklem v4root_phase = 0; 13551558Srgrimes dirhead = (struct dirlist *)NULL; 13561558Srgrimes while (get_line()) { 13571558Srgrimes if (debug) 135837663Scharnier warnx("got line %s", line); 13591558Srgrimes cp = line; 13601558Srgrimes nextfield(&cp, &endcp); 13611558Srgrimes if (*cp == '#') 13621558Srgrimes goto nextline; 13631558Srgrimes 13641558Srgrimes /* 13651558Srgrimes * Set defaults. 13661558Srgrimes */ 13671558Srgrimes has_host = FALSE; 13681558Srgrimes anon = def_anon; 13691558Srgrimes exflags = MNT_EXPORTED; 13701558Srgrimes got_nondir = 0; 13711558Srgrimes opt_flags = 0; 13721558Srgrimes ep = (struct exportlist *)NULL; 1373192934Srmacklem dirp = NULL; 13741558Srgrimes 13751558Srgrimes /* 1376192934Srmacklem * Handle the V4 root dir. 1377192934Srmacklem */ 1378192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1379192934Srmacklem /* 1380192934Srmacklem * V4: just indicates that it is the v4 root point, 1381192934Srmacklem * so skip over that and set v4root_phase. 1382192934Srmacklem */ 1383192934Srmacklem if (v4root_phase > 0) { 1384192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1385192934Srmacklem goto nextline; 1386192934Srmacklem } 1387192934Srmacklem v4root_phase = 1; 1388192934Srmacklem cp += 3; 1389192934Srmacklem nextfield(&cp, &endcp); 1390192934Srmacklem } 1391192934Srmacklem 1392192934Srmacklem /* 13931558Srgrimes * Create new exports list entry 13941558Srgrimes */ 13951558Srgrimes len = endcp-cp; 13961558Srgrimes tgrp = grp = get_grp(); 13971558Srgrimes while (len > 0) { 1398194880Sdfr if (len > MNTNAMLEN) { 13991558Srgrimes getexp_err(ep, tgrp); 14001558Srgrimes goto nextline; 14011558Srgrimes } 14021558Srgrimes if (*cp == '-') { 14031558Srgrimes if (ep == (struct exportlist *)NULL) { 14041558Srgrimes getexp_err(ep, tgrp); 14051558Srgrimes goto nextline; 14061558Srgrimes } 14071558Srgrimes if (debug) 140837663Scharnier warnx("doing opt %s", cp); 14091558Srgrimes got_nondir = 1; 14101558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 14111558Srgrimes &exflags, &anon)) { 14121558Srgrimes getexp_err(ep, tgrp); 14131558Srgrimes goto nextline; 14141558Srgrimes } 14151558Srgrimes } else if (*cp == '/') { 14161558Srgrimes savedc = *endcp; 14171558Srgrimes *endcp = '\0'; 1418192934Srmacklem if (v4root_phase > 1) { 1419192934Srmacklem if (dirp != NULL) { 1420192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 1421192934Srmacklem getexp_err(ep, tgrp); 1422192934Srmacklem goto nextline; 1423192934Srmacklem } 1424192934Srmacklem } 14251558Srgrimes if (check_dirpath(cp) && 14261558Srgrimes statfs(cp, &fsb) >= 0) { 14271558Srgrimes if (got_nondir) { 142837663Scharnier syslog(LOG_ERR, "dirs must be first"); 14291558Srgrimes getexp_err(ep, tgrp); 14301558Srgrimes goto nextline; 14311558Srgrimes } 1432192934Srmacklem if (v4root_phase == 1) { 1433192934Srmacklem if (dirp != NULL) { 1434192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 14351558Srgrimes getexp_err(ep, tgrp); 14361558Srgrimes goto nextline; 14371558Srgrimes } 1438192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1439192934Srmacklem strlcpy(v4root_dirpath, cp, 1440192934Srmacklem sizeof (v4root_dirpath)); 1441192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1442192934Srmacklem != 0) { 1443192934Srmacklem syslog(LOG_ERR, 1444192934Srmacklem "different V4 dirpath %s", cp); 1445192934Srmacklem getexp_err(ep, tgrp); 1446192934Srmacklem goto nextline; 1447192934Srmacklem } 1448192934Srmacklem dirp = cp; 1449192934Srmacklem v4root_phase = 2; 1450192934Srmacklem got_nondir = 1; 1451192934Srmacklem ep = get_exp(); 14521558Srgrimes } else { 1453192934Srmacklem if (ep) { 1454192934Srmacklem if (ep->ex_fs.val[0] != 1455192934Srmacklem fsb.f_fsid.val[0] || 1456192934Srmacklem ep->ex_fs.val[1] != 1457192934Srmacklem fsb.f_fsid.val[1]) { 1458192934Srmacklem getexp_err(ep, tgrp); 1459192934Srmacklem goto nextline; 1460192934Srmacklem } 1461192934Srmacklem } else { 1462192934Srmacklem /* 1463192934Srmacklem * See if this directory is already 1464192934Srmacklem * in the list. 1465192934Srmacklem */ 1466192934Srmacklem ep = ex_search(&fsb.f_fsid); 1467192934Srmacklem if (ep == (struct exportlist *)NULL) { 1468192934Srmacklem ep = get_exp(); 1469192934Srmacklem ep->ex_fs = fsb.f_fsid; 1470192934Srmacklem ep->ex_fsdir = (char *)malloc 1471192934Srmacklem (strlen(fsb.f_mntonname) + 1); 1472192934Srmacklem if (ep->ex_fsdir) 1473192934Srmacklem strcpy(ep->ex_fsdir, 1474192934Srmacklem fsb.f_mntonname); 1475192934Srmacklem else 1476192934Srmacklem out_of_mem(); 1477192934Srmacklem if (debug) 1478192934Srmacklem warnx( 1479192934Srmacklem "making new ep fs=0x%x,0x%x", 1480192934Srmacklem fsb.f_fsid.val[0], 1481192934Srmacklem fsb.f_fsid.val[1]); 1482192934Srmacklem } else if (debug) 1483192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1484192934Srmacklem fsb.f_fsid.val[0], 1485192934Srmacklem fsb.f_fsid.val[1]); 1486192934Srmacklem } 1487192934Srmacklem 14881558Srgrimes /* 1489192934Srmacklem * Add dirpath to export mount point. 14901558Srgrimes */ 1491192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1492192934Srmacklem dirplen = len; 14931558Srgrimes } 14941558Srgrimes } else { 14951558Srgrimes getexp_err(ep, tgrp); 14961558Srgrimes goto nextline; 14971558Srgrimes } 14981558Srgrimes *endcp = savedc; 14991558Srgrimes } else { 15001558Srgrimes savedc = *endcp; 15011558Srgrimes *endcp = '\0'; 15021558Srgrimes got_nondir = 1; 15031558Srgrimes if (ep == (struct exportlist *)NULL) { 15041558Srgrimes getexp_err(ep, tgrp); 15051558Srgrimes goto nextline; 15061558Srgrimes } 15071558Srgrimes 15081558Srgrimes /* 15091558Srgrimes * Get the host or netgroup. 15101558Srgrimes */ 15111558Srgrimes setnetgrent(cp); 15121558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 15131558Srgrimes do { 15141558Srgrimes if (has_host) { 15151558Srgrimes grp->gr_next = get_grp(); 15161558Srgrimes grp = grp->gr_next; 15171558Srgrimes } 15181558Srgrimes if (netgrp) { 151937003Sjoerg if (hst == 0) { 152037663Scharnier syslog(LOG_ERR, 152137663Scharnier "null hostname in netgroup %s, skipping", cp); 152237004Sjoerg grp->gr_type = GT_IGNORE; 152337003Sjoerg } else if (get_host(hst, grp, tgrp)) { 152437663Scharnier syslog(LOG_ERR, 152537663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 152629317Sjlemon grp->gr_type = GT_IGNORE; 15271558Srgrimes } 15287401Swpaul } else if (get_host(cp, grp, tgrp)) { 152937663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 153029317Sjlemon grp->gr_type = GT_IGNORE; 15311558Srgrimes } 15321558Srgrimes has_host = TRUE; 15331558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 15341558Srgrimes endnetgrent(); 15351558Srgrimes *endcp = savedc; 15361558Srgrimes } 15371558Srgrimes cp = endcp; 15381558Srgrimes nextfield(&cp, &endcp); 15391558Srgrimes len = endcp - cp; 15401558Srgrimes } 15411558Srgrimes if (check_options(dirhead)) { 15421558Srgrimes getexp_err(ep, tgrp); 15431558Srgrimes goto nextline; 15441558Srgrimes } 15451558Srgrimes if (!has_host) { 154675641Siedowse grp->gr_type = GT_DEFAULT; 15471558Srgrimes if (debug) 154837663Scharnier warnx("adding a default entry"); 15491558Srgrimes 15501558Srgrimes /* 15511558Srgrimes * Don't allow a network export coincide with a list of 15521558Srgrimes * host(s) on the same line. 15531558Srgrimes */ 15541558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 155575801Siedowse syslog(LOG_ERR, "network/host conflict"); 15561558Srgrimes getexp_err(ep, tgrp); 15571558Srgrimes goto nextline; 155829317Sjlemon 155974462Salfred /* 156074462Salfred * If an export list was specified on this line, make sure 156129317Sjlemon * that we have at least one valid entry, otherwise skip it. 156229317Sjlemon */ 156329317Sjlemon } else { 156429317Sjlemon grp = tgrp; 156574462Salfred while (grp && grp->gr_type == GT_IGNORE) 156629317Sjlemon grp = grp->gr_next; 156729317Sjlemon if (! grp) { 156829317Sjlemon getexp_err(ep, tgrp); 156929317Sjlemon goto nextline; 157029317Sjlemon } 15711558Srgrimes } 15721558Srgrimes 1573192934Srmacklem if (v4root_phase == 1) { 1574192934Srmacklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1575192934Srmacklem getexp_err(ep, tgrp); 1576192934Srmacklem goto nextline; 1577192934Srmacklem } 1578192934Srmacklem 15791558Srgrimes /* 15801558Srgrimes * Loop through hosts, pushing the exports into the kernel. 15811558Srgrimes * After loop, tgrp points to the start of the list and 15821558Srgrimes * grp points to the last entry in the list. 15831558Srgrimes */ 15841558Srgrimes grp = tgrp; 15851558Srgrimes do { 158675635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 158775635Siedowse &fsb)) { 158875635Siedowse getexp_err(ep, tgrp); 158975635Siedowse goto nextline; 159075635Siedowse } 15911558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 15921558Srgrimes 15931558Srgrimes /* 1594192934Srmacklem * For V4: don't enter in mount lists. 1595192934Srmacklem */ 1596194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1597194773Srmacklem /* 1598194773Srmacklem * Since these structures aren't used by mountd, 1599194773Srmacklem * free them up now. 1600194773Srmacklem */ 1601194773Srmacklem if (ep != NULL) 1602194773Srmacklem free_exp(ep); 1603194773Srmacklem while (tgrp != NULL) { 1604194773Srmacklem grp = tgrp; 1605194773Srmacklem tgrp = tgrp->gr_next; 1606194773Srmacklem free_grp(grp); 1607194773Srmacklem } 1608192934Srmacklem goto nextline; 1609194773Srmacklem } 1610192934Srmacklem 1611192934Srmacklem /* 16121558Srgrimes * Success. Update the data structures. 16131558Srgrimes */ 16141558Srgrimes if (has_host) { 16159336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 16161558Srgrimes grp->gr_next = grphead; 16171558Srgrimes grphead = tgrp; 16181558Srgrimes } else { 16191558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 16209336Sdfr opt_flags); 16211558Srgrimes free_grp(grp); 16221558Srgrimes } 16231558Srgrimes dirhead = (struct dirlist *)NULL; 16241558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 16251558Srgrimes ep2 = exphead; 16261558Srgrimes epp = &exphead; 16271558Srgrimes 16281558Srgrimes /* 16291558Srgrimes * Insert in the list in alphabetical order. 16301558Srgrimes */ 16311558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 16321558Srgrimes epp = &ep2->ex_next; 16331558Srgrimes ep2 = ep2->ex_next; 16341558Srgrimes } 16351558Srgrimes if (ep2) 16361558Srgrimes ep->ex_next = ep2; 16371558Srgrimes *epp = ep; 16381558Srgrimes ep->ex_flag |= EX_LINKED; 16391558Srgrimes } 16401558Srgrimesnextline: 1641192934Srmacklem v4root_phase = 0; 16421558Srgrimes if (dirhead) { 16431558Srgrimes free_dir(dirhead); 16441558Srgrimes dirhead = (struct dirlist *)NULL; 16451558Srgrimes } 16461558Srgrimes } 16471558Srgrimes} 16481558Srgrimes 16491558Srgrimes/* 1650166440Spjd * Get the export list from all specified files 1651166440Spjd */ 1652166440Spjdvoid 1653216587Scharnierget_exportlist(void) 1654166440Spjd{ 1655166440Spjd struct exportlist *ep, *ep2; 1656166440Spjd struct grouplist *grp, *tgrp; 1657166440Spjd struct export_args export; 1658166440Spjd struct iovec *iov; 1659166440Spjd struct statfs *fsp, *mntbufp; 1660166440Spjd struct xvfsconf vfc; 1661166440Spjd char errmsg[255]; 1662230352Seadler int num, i; 1663166440Spjd int iovlen; 1664168684Spjd int done; 1665192934Srmacklem struct nfsex_args eargs; 1666166440Spjd 1667241568Srmacklem if (suspend_nfsd != 0) 1668241568Srmacklem (void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); 1669192934Srmacklem v4root_dirpath[0] = '\0'; 1670166440Spjd bzero(&export, sizeof(export)); 1671166440Spjd export.ex_flags = MNT_DELEXPORT; 1672166440Spjd iov = NULL; 1673166440Spjd iovlen = 0; 1674166440Spjd bzero(errmsg, sizeof(errmsg)); 1675166440Spjd 1676166440Spjd /* 1677166440Spjd * First, get rid of the old list 1678166440Spjd */ 1679166440Spjd ep = exphead; 1680166440Spjd while (ep) { 1681166440Spjd ep2 = ep; 1682166440Spjd ep = ep->ex_next; 1683166440Spjd free_exp(ep2); 1684166440Spjd } 1685166440Spjd exphead = (struct exportlist *)NULL; 1686166440Spjd 1687166440Spjd grp = grphead; 1688166440Spjd while (grp) { 1689166440Spjd tgrp = grp; 1690166440Spjd grp = grp->gr_next; 1691166440Spjd free_grp(tgrp); 1692166440Spjd } 1693166440Spjd grphead = (struct grouplist *)NULL; 1694166440Spjd 1695166440Spjd /* 1696192934Srmacklem * and the old V4 root dir. 1697192934Srmacklem */ 1698192934Srmacklem bzero(&eargs, sizeof (eargs)); 1699192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1700192934Srmacklem if (run_v4server > 0 && 1701192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1702192934Srmacklem errno != ENOENT) 1703192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1704192934Srmacklem 1705192934Srmacklem /* 1706192934Srmacklem * and clear flag that notes if a public fh has been exported. 1707192934Srmacklem */ 1708192934Srmacklem has_publicfh = 0; 1709192934Srmacklem 1710192934Srmacklem /* 1711166440Spjd * And delete exports that are in the kernel for all local 1712166440Spjd * filesystems. 1713166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1714166440Spjd */ 1715166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1716166440Spjd 1717166440Spjd if (num > 0) { 1718166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1719166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1720166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1721166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1722166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1723166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1724166440Spjd } 1725166440Spjd 1726166440Spjd for (i = 0; i < num; i++) { 1727166440Spjd fsp = &mntbufp[i]; 1728166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1729166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1730166440Spjd fsp->f_fstypename); 1731166440Spjd continue; 1732166440Spjd } 1733166440Spjd 1734166440Spjd /* 1735166440Spjd * Do not delete export for network filesystem by 1736166440Spjd * passing "export" arg to nmount(). 1737166440Spjd * It only makes sense to do this for local filesystems. 1738166440Spjd */ 1739166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1740166440Spjd continue; 1741166440Spjd 1742166440Spjd iov[1].iov_base = fsp->f_fstypename; 1743166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1744166440Spjd iov[3].iov_base = fsp->f_mntonname; 1745166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1746166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1747166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1748270183Sbdrewery errmsg[0] = '\0'; 1749166440Spjd 1750166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1751166440Spjd errno != ENOENT && errno != ENOTSUP) { 1752166440Spjd syslog(LOG_ERR, 1753166440Spjd "can't delete exports for %s: %m %s", 1754166440Spjd fsp->f_mntonname, errmsg); 1755166440Spjd } 1756166440Spjd } 1757166440Spjd 1758166440Spjd if (iov != NULL) { 1759166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1760166440Spjd free(iov[0].iov_base); /* fstype */ 1761166440Spjd free(iov[2].iov_base); /* fspath */ 1762166440Spjd free(iov[4].iov_base); /* from */ 1763166440Spjd free(iov[6].iov_base); /* update */ 1764166440Spjd free(iov[8].iov_base); /* export */ 1765166440Spjd free(iov[10].iov_base); /* errmsg */ 1766166440Spjd 1767166440Spjd /* free iov, allocated by realloc() */ 1768166440Spjd free(iov); 1769166440Spjd iovlen = 0; 1770166440Spjd } 1771166440Spjd 1772166440Spjd /* 1773166440Spjd * Read in the exports file and build the list, calling 1774166440Spjd * nmount() as we go along to push the export rules into the kernel. 1775166440Spjd */ 1776168684Spjd done = 0; 1777166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1778166440Spjd if (debug) 1779166440Spjd warnx("reading exports from %s", exnames[i]); 1780166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1781168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1782168684Spjd continue; 1783166440Spjd } 1784166440Spjd get_exportlist_one(); 1785166440Spjd fclose(exp_file); 1786168684Spjd done++; 1787166440Spjd } 1788168684Spjd if (done == 0) { 1789168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1790168684Spjd exit(2); 1791168684Spjd } 1792192934Srmacklem 1793192934Srmacklem /* 1794192934Srmacklem * If there was no public fh, clear any previous one set. 1795192934Srmacklem */ 1796192934Srmacklem if (run_v4server > 0 && has_publicfh == 0) 1797192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1798241568Srmacklem 1799241568Srmacklem /* Resume the nfsd. If they weren't suspended, this is harmless. */ 1800241568Srmacklem (void)nfssvc(NFSSVC_RESUMENFSD, NULL); 1801166440Spjd} 1802166440Spjd 1803166440Spjd/* 18041558Srgrimes * Allocate an export list element 18051558Srgrimes */ 18061558Srgrimesstruct exportlist * 1807216587Scharnierget_exp(void) 18081558Srgrimes{ 18091558Srgrimes struct exportlist *ep; 18101558Srgrimes 1811224003Sdelphij ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 18121558Srgrimes if (ep == (struct exportlist *)NULL) 18131558Srgrimes out_of_mem(); 18141558Srgrimes return (ep); 18151558Srgrimes} 18161558Srgrimes 18171558Srgrimes/* 18181558Srgrimes * Allocate a group list element 18191558Srgrimes */ 18201558Srgrimesstruct grouplist * 1821216587Scharnierget_grp(void) 18221558Srgrimes{ 18231558Srgrimes struct grouplist *gp; 18241558Srgrimes 1825224003Sdelphij gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 18261558Srgrimes if (gp == (struct grouplist *)NULL) 18271558Srgrimes out_of_mem(); 18281558Srgrimes return (gp); 18291558Srgrimes} 18301558Srgrimes 18311558Srgrimes/* 18321558Srgrimes * Clean up upon an error in get_exportlist(). 18331558Srgrimes */ 18341558Srgrimesvoid 1835216587Scharniergetexp_err(struct exportlist *ep, struct grouplist *grp) 18361558Srgrimes{ 18371558Srgrimes struct grouplist *tgrp; 18381558Srgrimes 1839100336Sjoerg if (!(opt_flags & OP_QUIET)) 1840100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 18411558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 18421558Srgrimes free_exp(ep); 18431558Srgrimes while (grp) { 18441558Srgrimes tgrp = grp; 18451558Srgrimes grp = grp->gr_next; 18461558Srgrimes free_grp(tgrp); 18471558Srgrimes } 18481558Srgrimes} 18491558Srgrimes 18501558Srgrimes/* 18511558Srgrimes * Search the export list for a matching fs. 18521558Srgrimes */ 18531558Srgrimesstruct exportlist * 1854216587Scharnierex_search(fsid_t *fsid) 18551558Srgrimes{ 18561558Srgrimes struct exportlist *ep; 18571558Srgrimes 18581558Srgrimes ep = exphead; 18591558Srgrimes while (ep) { 18601558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 18611558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 18621558Srgrimes return (ep); 18631558Srgrimes ep = ep->ex_next; 18641558Srgrimes } 18651558Srgrimes return (ep); 18661558Srgrimes} 18671558Srgrimes 18681558Srgrimes/* 18691558Srgrimes * Add a directory path to the list. 18701558Srgrimes */ 18711558Srgrimeschar * 1872216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len) 18731558Srgrimes{ 18741558Srgrimes struct dirlist *dp; 18751558Srgrimes 18761558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 187737663Scharnier if (dp == (struct dirlist *)NULL) 187837663Scharnier out_of_mem(); 18791558Srgrimes dp->dp_left = *dpp; 18801558Srgrimes dp->dp_right = (struct dirlist *)NULL; 18811558Srgrimes dp->dp_flag = 0; 18821558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 18831558Srgrimes strcpy(dp->dp_dirp, cp); 18841558Srgrimes *dpp = dp; 18851558Srgrimes return (dp->dp_dirp); 18861558Srgrimes} 18871558Srgrimes 18881558Srgrimes/* 18891558Srgrimes * Hang the dir list element off the dirpath binary tree as required 18901558Srgrimes * and update the entry for host. 18911558Srgrimes */ 18921558Srgrimesvoid 1893216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1894216587Scharnier int flags) 18951558Srgrimes{ 18961558Srgrimes struct hostlist *hp; 18971558Srgrimes struct dirlist *dp2; 18981558Srgrimes 18999336Sdfr if (flags & OP_ALLDIRS) { 19001558Srgrimes if (ep->ex_defdir) 19011558Srgrimes free((caddr_t)dp); 19021558Srgrimes else 19031558Srgrimes ep->ex_defdir = dp; 19049336Sdfr if (grp == (struct grouplist *)NULL) { 19051558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 1906240902Srmacklem /* Save the default security flavors list. */ 1907240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 1908240902Srmacklem if (ep->ex_numsecflavors > 0) 1909240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 1910240902Srmacklem sizeof(ep->ex_secflavors)); 19119336Sdfr } else while (grp) { 19121558Srgrimes hp = get_ht(); 19131558Srgrimes hp->ht_grp = grp; 19141558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 19151558Srgrimes ep->ex_defdir->dp_hosts = hp; 1916240902Srmacklem /* Save the security flavors list for this host set. */ 1917240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 1918240902Srmacklem if (ep->ex_numsecflavors > 0) 1919240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 1920240902Srmacklem sizeof(ep->ex_secflavors)); 19211558Srgrimes grp = grp->gr_next; 19221558Srgrimes } 19231558Srgrimes } else { 19241558Srgrimes 19251558Srgrimes /* 192637663Scharnier * Loop through the directories adding them to the tree. 19271558Srgrimes */ 19281558Srgrimes while (dp) { 19291558Srgrimes dp2 = dp->dp_left; 1930240902Srmacklem add_dlist(&ep->ex_dirl, dp, grp, flags, ep); 19311558Srgrimes dp = dp2; 19321558Srgrimes } 19331558Srgrimes } 19341558Srgrimes} 19351558Srgrimes 19361558Srgrimes/* 19371558Srgrimes * Traverse the binary tree either updating a node that is already there 19381558Srgrimes * for the new directory or adding the new node. 19391558Srgrimes */ 19401558Srgrimesvoid 1941216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1942240902Srmacklem int flags, struct exportlist *ep) 19431558Srgrimes{ 19441558Srgrimes struct dirlist *dp; 19451558Srgrimes struct hostlist *hp; 19461558Srgrimes int cmp; 19471558Srgrimes 19481558Srgrimes dp = *dpp; 19491558Srgrimes if (dp) { 19501558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 19511558Srgrimes if (cmp > 0) { 1952240902Srmacklem add_dlist(&dp->dp_left, newdp, grp, flags, ep); 19531558Srgrimes return; 19541558Srgrimes } else if (cmp < 0) { 1955240902Srmacklem add_dlist(&dp->dp_right, newdp, grp, flags, ep); 19561558Srgrimes return; 19571558Srgrimes } else 19581558Srgrimes free((caddr_t)newdp); 19591558Srgrimes } else { 19601558Srgrimes dp = newdp; 19611558Srgrimes dp->dp_left = (struct dirlist *)NULL; 19621558Srgrimes *dpp = dp; 19631558Srgrimes } 19641558Srgrimes if (grp) { 19651558Srgrimes 19661558Srgrimes /* 19671558Srgrimes * Hang all of the host(s) off of the directory point. 19681558Srgrimes */ 19691558Srgrimes do { 19701558Srgrimes hp = get_ht(); 19711558Srgrimes hp->ht_grp = grp; 19721558Srgrimes hp->ht_next = dp->dp_hosts; 19731558Srgrimes dp->dp_hosts = hp; 1974240902Srmacklem /* Save the security flavors list for this host set. */ 1975240902Srmacklem grp->gr_numsecflavors = ep->ex_numsecflavors; 1976240902Srmacklem if (ep->ex_numsecflavors > 0) 1977240902Srmacklem memcpy(grp->gr_secflavors, ep->ex_secflavors, 1978240902Srmacklem sizeof(ep->ex_secflavors)); 19791558Srgrimes grp = grp->gr_next; 19801558Srgrimes } while (grp); 19819336Sdfr } else { 19821558Srgrimes dp->dp_flag |= DP_DEFSET; 1983240902Srmacklem /* Save the default security flavors list. */ 1984240902Srmacklem ep->ex_defnumsecflavors = ep->ex_numsecflavors; 1985240902Srmacklem if (ep->ex_numsecflavors > 0) 1986240902Srmacklem memcpy(ep->ex_defsecflavors, ep->ex_secflavors, 1987240902Srmacklem sizeof(ep->ex_secflavors)); 19889336Sdfr } 19891558Srgrimes} 19901558Srgrimes 19911558Srgrimes/* 19921558Srgrimes * Search for a dirpath on the export point. 19931558Srgrimes */ 19941558Srgrimesstruct dirlist * 1995216587Scharnierdirp_search(struct dirlist *dp, char *dirp) 19961558Srgrimes{ 19971558Srgrimes int cmp; 19981558Srgrimes 19991558Srgrimes if (dp) { 200074462Salfred cmp = strcmp(dp->dp_dirp, dirp); 20011558Srgrimes if (cmp > 0) 200274462Salfred return (dirp_search(dp->dp_left, dirp)); 20031558Srgrimes else if (cmp < 0) 200474462Salfred return (dirp_search(dp->dp_right, dirp)); 20051558Srgrimes else 20061558Srgrimes return (dp); 20071558Srgrimes } 20081558Srgrimes return (dp); 20091558Srgrimes} 20101558Srgrimes 20111558Srgrimes/* 20121558Srgrimes * Scan for a host match in a directory tree. 20131558Srgrimes */ 20141558Srgrimesint 2015216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 2016240902Srmacklem int *hostsetp, int *numsecflavors, int **secflavorsp) 20171558Srgrimes{ 20181558Srgrimes struct hostlist *hp; 20191558Srgrimes struct grouplist *grp; 202074462Salfred struct addrinfo *ai; 20211558Srgrimes 20221558Srgrimes if (dp) { 20231558Srgrimes if (dp->dp_flag & DP_DEFSET) 20249336Sdfr *defsetp = dp->dp_flag; 20251558Srgrimes hp = dp->dp_hosts; 20261558Srgrimes while (hp) { 20271558Srgrimes grp = hp->ht_grp; 20281558Srgrimes switch (grp->gr_type) { 20291558Srgrimes case GT_HOST: 203074462Salfred ai = grp->gr_ptr.gt_addrinfo; 203174462Salfred for (; ai; ai = ai->ai_next) { 203275801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 203374462Salfred *hostsetp = 203474462Salfred (hp->ht_flag | DP_HOSTSET); 2035240902Srmacklem if (numsecflavors != NULL) { 2036240902Srmacklem *numsecflavors = 2037240902Srmacklem grp->gr_numsecflavors; 2038240902Srmacklem *secflavorsp = 2039240902Srmacklem grp->gr_secflavors; 2040240902Srmacklem } 204174462Salfred return (1); 204274462Salfred } 20439336Sdfr } 204475801Siedowse break; 20451558Srgrimes case GT_NET: 204675801Siedowse if (!sacmp(saddr, (struct sockaddr *) 204775801Siedowse &grp->gr_ptr.gt_net.nt_net, 204875801Siedowse (struct sockaddr *) 204975801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 205074462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 2051240902Srmacklem if (numsecflavors != NULL) { 2052240902Srmacklem *numsecflavors = 2053240902Srmacklem grp->gr_numsecflavors; 2054240902Srmacklem *secflavorsp = 2055240902Srmacklem grp->gr_secflavors; 2056240902Srmacklem } 205774462Salfred return (1); 205874462Salfred } 205975801Siedowse break; 206075801Siedowse } 20611558Srgrimes hp = hp->ht_next; 20621558Srgrimes } 20631558Srgrimes } 20641558Srgrimes return (0); 20651558Srgrimes} 20661558Srgrimes 20671558Srgrimes/* 20681558Srgrimes * Scan tree for a host that matches the address. 20691558Srgrimes */ 20701558Srgrimesint 2071216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr) 20721558Srgrimes{ 20739336Sdfr int defset, hostset; 20741558Srgrimes 20751558Srgrimes if (dp) { 20761558Srgrimes if (scan_tree(dp->dp_left, saddr)) 20771558Srgrimes return (1); 2078240902Srmacklem if (chk_host(dp, saddr, &defset, &hostset, NULL, NULL)) 20791558Srgrimes return (1); 20801558Srgrimes if (scan_tree(dp->dp_right, saddr)) 20811558Srgrimes return (1); 20821558Srgrimes } 20831558Srgrimes return (0); 20841558Srgrimes} 20851558Srgrimes 20861558Srgrimes/* 20871558Srgrimes * Traverse the dirlist tree and free it up. 20881558Srgrimes */ 20891558Srgrimesvoid 2090216587Scharnierfree_dir(struct dirlist *dp) 20911558Srgrimes{ 20921558Srgrimes 20931558Srgrimes if (dp) { 20941558Srgrimes free_dir(dp->dp_left); 20951558Srgrimes free_dir(dp->dp_right); 20961558Srgrimes free_host(dp->dp_hosts); 20971558Srgrimes free((caddr_t)dp); 20981558Srgrimes } 20991558Srgrimes} 21001558Srgrimes 21011558Srgrimes/* 2102184588Sdfr * Parse a colon separated list of security flavors 2103184588Sdfr */ 2104184588Sdfrint 2105216587Scharnierparsesec(char *seclist, struct exportlist *ep) 2106184588Sdfr{ 2107184588Sdfr char *cp, savedc; 2108184588Sdfr int flavor; 2109184588Sdfr 2110184588Sdfr ep->ex_numsecflavors = 0; 2111184588Sdfr for (;;) { 2112184588Sdfr cp = strchr(seclist, ':'); 2113184588Sdfr if (cp) { 2114184588Sdfr savedc = *cp; 2115184588Sdfr *cp = '\0'; 2116184588Sdfr } 2117184588Sdfr 2118184588Sdfr if (!strcmp(seclist, "sys")) 2119184588Sdfr flavor = AUTH_SYS; 2120184588Sdfr else if (!strcmp(seclist, "krb5")) 2121184588Sdfr flavor = RPCSEC_GSS_KRB5; 2122184588Sdfr else if (!strcmp(seclist, "krb5i")) 2123184588Sdfr flavor = RPCSEC_GSS_KRB5I; 2124184588Sdfr else if (!strcmp(seclist, "krb5p")) 2125184588Sdfr flavor = RPCSEC_GSS_KRB5P; 2126184588Sdfr else { 2127184588Sdfr if (cp) 2128184588Sdfr *cp = savedc; 2129184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2130184588Sdfr return (1); 2131184588Sdfr } 2132184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2133184588Sdfr if (cp) 2134184588Sdfr *cp = savedc; 2135184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2136184588Sdfr return (1); 2137184588Sdfr } 2138184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2139184588Sdfr ep->ex_numsecflavors++; 2140184588Sdfr if (cp) { 2141184588Sdfr *cp = savedc; 2142184588Sdfr seclist = cp + 1; 2143184588Sdfr } else { 2144184588Sdfr break; 2145184588Sdfr } 2146184588Sdfr } 2147184588Sdfr return (0); 2148184588Sdfr} 2149184588Sdfr 2150184588Sdfr/* 21511558Srgrimes * Parse the option string and update fields. 21521558Srgrimes * Option arguments may either be -<option>=<value> or 21531558Srgrimes * -<option> <value> 21541558Srgrimes */ 21551558Srgrimesint 2156216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2157216587Scharnier int *has_hostp, int *exflagsp, struct xucred *cr) 21581558Srgrimes{ 21591558Srgrimes char *cpoptarg, *cpoptend; 21601558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 21611558Srgrimes int allflag, usedarg; 21621558Srgrimes 216351968Salfred savedc2 = '\0'; 21641558Srgrimes cpopt = *cpp; 21651558Srgrimes cpopt++; 21661558Srgrimes cp = *endcpp; 21671558Srgrimes savedc = *cp; 21681558Srgrimes *cp = '\0'; 21691558Srgrimes while (cpopt && *cpopt) { 21701558Srgrimes allflag = 1; 21711558Srgrimes usedarg = -2; 217237663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 21731558Srgrimes *cpoptend++ = '\0'; 217437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 21751558Srgrimes *cpoptarg++ = '\0'; 21761558Srgrimes } else { 217737663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 21781558Srgrimes *cpoptarg++ = '\0'; 21791558Srgrimes else { 21801558Srgrimes *cp = savedc; 21811558Srgrimes nextfield(&cp, &endcp); 21821558Srgrimes **endcpp = '\0'; 21831558Srgrimes if (endcp > cp && *cp != '-') { 21841558Srgrimes cpoptarg = cp; 21851558Srgrimes savedc2 = *endcp; 21861558Srgrimes *endcp = '\0'; 21871558Srgrimes usedarg = 0; 21881558Srgrimes } 21891558Srgrimes } 21901558Srgrimes } 21911558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 21921558Srgrimes *exflagsp |= MNT_EXRDONLY; 21931558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 21941558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 21951558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 21961558Srgrimes usedarg++; 21971558Srgrimes parsecred(cpoptarg, cr); 21981558Srgrimes if (allflag == 0) { 21991558Srgrimes *exflagsp |= MNT_EXPORTANON; 22001558Srgrimes opt_flags |= OP_MAPALL; 22011558Srgrimes } else 22021558Srgrimes opt_flags |= OP_MAPROOT; 22031558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 220475801Siedowse !strcmp(cpopt, "m"))) { 22051558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 220637663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 22071558Srgrimes return (1); 22081558Srgrimes } 22091558Srgrimes usedarg++; 22101558Srgrimes opt_flags |= OP_MASK; 22111558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 22121558Srgrimes !strcmp(cpopt, "n"))) { 221374462Salfred if (strchr(cpoptarg, '/') != NULL) { 221474462Salfred if (debug) 221574462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 221674462Salfred opt_flags |= OP_MASKLEN; 221774462Salfred } 22181558Srgrimes if (grp->gr_type != GT_NULL) { 221937663Scharnier syslog(LOG_ERR, "network/host conflict"); 22201558Srgrimes return (1); 22211558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 222237663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 22231558Srgrimes return (1); 22241558Srgrimes } 22251558Srgrimes grp->gr_type = GT_NET; 22261558Srgrimes *has_hostp = 1; 22271558Srgrimes usedarg++; 22281558Srgrimes opt_flags |= OP_NET; 22291558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 22301558Srgrimes opt_flags |= OP_ALLDIRS; 223127447Sdfr } else if (!strcmp(cpopt, "public")) { 223227447Sdfr *exflagsp |= MNT_EXPUBLIC; 223327447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 223427447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 223527447Sdfr opt_flags |= OP_MAPALL; 223627447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 223727447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2238100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2239100336Sjoerg opt_flags |= OP_QUIET; 2240247034Spluknet } else if (cpoptarg && !strcmp(cpopt, "sec")) { 2241184588Sdfr if (parsesec(cpoptarg, ep)) 2242184588Sdfr return (1); 2243184588Sdfr opt_flags |= OP_SEC; 2244184588Sdfr usedarg++; 22451558Srgrimes } else { 224637663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 22471558Srgrimes return (1); 22481558Srgrimes } 22491558Srgrimes if (usedarg >= 0) { 22501558Srgrimes *endcp = savedc2; 22511558Srgrimes **endcpp = savedc; 22521558Srgrimes if (usedarg > 0) { 22531558Srgrimes *cpp = cp; 22541558Srgrimes *endcpp = endcp; 22551558Srgrimes } 22561558Srgrimes return (0); 22571558Srgrimes } 22581558Srgrimes cpopt = cpoptend; 22591558Srgrimes } 22601558Srgrimes **endcpp = savedc; 22611558Srgrimes return (0); 22621558Srgrimes} 22631558Srgrimes 22641558Srgrimes/* 22651558Srgrimes * Translate a character string to the corresponding list of network 22661558Srgrimes * addresses for a hostname. 22671558Srgrimes */ 22681558Srgrimesint 2269216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 22701558Srgrimes{ 22717401Swpaul struct grouplist *checkgrp; 227275635Siedowse struct addrinfo *ai, *tai, hints; 227374462Salfred int ecode; 227474462Salfred char host[NI_MAXHOST]; 22751558Srgrimes 227674462Salfred if (grp->gr_type != GT_NULL) { 227774462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 22781558Srgrimes return (1); 22791558Srgrimes } 228074462Salfred memset(&hints, 0, sizeof hints); 228174462Salfred hints.ai_flags = AI_CANONNAME; 228274462Salfred hints.ai_protocol = IPPROTO_UDP; 228374462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 228474462Salfred if (ecode != 0) { 228575635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 228674462Salfred return 1; 228774462Salfred } 228874462Salfred grp->gr_ptr.gt_addrinfo = ai; 228974462Salfred while (ai != NULL) { 229074462Salfred if (ai->ai_canonname == NULL) { 229174462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2292146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 229374462Salfred strlcpy(host, "?", sizeof(host)); 229474462Salfred ai->ai_canonname = strdup(host); 229574462Salfred ai->ai_flags |= AI_CANONNAME; 229675641Siedowse } 229774462Salfred if (debug) 229875635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 229975635Siedowse /* 230075635Siedowse * Sanity check: make sure we don't already have an entry 230175635Siedowse * for this host in the grouplist. 230275635Siedowse */ 230375635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 230475635Siedowse checkgrp = checkgrp->gr_next) { 230575635Siedowse if (checkgrp->gr_type != GT_HOST) 230675635Siedowse continue; 230775635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 230875635Siedowse tai = tai->ai_next) { 230975801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 231075635Siedowse continue; 231175635Siedowse if (debug) 231275635Siedowse fprintf(stderr, 231375635Siedowse "ignoring duplicate host %s\n", 231475635Siedowse ai->ai_canonname); 231575635Siedowse grp->gr_type = GT_IGNORE; 231675635Siedowse return (0); 231775635Siedowse } 231875635Siedowse } 231974462Salfred ai = ai->ai_next; 23201558Srgrimes } 232175635Siedowse grp->gr_type = GT_HOST; 23221558Srgrimes return (0); 23231558Srgrimes} 23241558Srgrimes 23251558Srgrimes/* 23261558Srgrimes * Free up an exports list component 23271558Srgrimes */ 23281558Srgrimesvoid 2329216587Scharnierfree_exp(struct exportlist *ep) 23301558Srgrimes{ 23311558Srgrimes 23321558Srgrimes if (ep->ex_defdir) { 23331558Srgrimes free_host(ep->ex_defdir->dp_hosts); 23341558Srgrimes free((caddr_t)ep->ex_defdir); 23351558Srgrimes } 23361558Srgrimes if (ep->ex_fsdir) 23371558Srgrimes free(ep->ex_fsdir); 233827447Sdfr if (ep->ex_indexfile) 233927447Sdfr free(ep->ex_indexfile); 23401558Srgrimes free_dir(ep->ex_dirl); 23411558Srgrimes free((caddr_t)ep); 23421558Srgrimes} 23431558Srgrimes 23441558Srgrimes/* 23451558Srgrimes * Free hosts. 23461558Srgrimes */ 23471558Srgrimesvoid 2348216587Scharnierfree_host(struct hostlist *hp) 23491558Srgrimes{ 23501558Srgrimes struct hostlist *hp2; 23511558Srgrimes 23521558Srgrimes while (hp) { 23531558Srgrimes hp2 = hp; 23541558Srgrimes hp = hp->ht_next; 23551558Srgrimes free((caddr_t)hp2); 23561558Srgrimes } 23571558Srgrimes} 23581558Srgrimes 23591558Srgrimesstruct hostlist * 2360216587Scharnierget_ht(void) 23611558Srgrimes{ 23621558Srgrimes struct hostlist *hp; 23631558Srgrimes 23641558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 23651558Srgrimes if (hp == (struct hostlist *)NULL) 23661558Srgrimes out_of_mem(); 23671558Srgrimes hp->ht_next = (struct hostlist *)NULL; 23689336Sdfr hp->ht_flag = 0; 23691558Srgrimes return (hp); 23701558Srgrimes} 23711558Srgrimes 23721558Srgrimes/* 23731558Srgrimes * Out of memory, fatal 23741558Srgrimes */ 23751558Srgrimesvoid 2376216587Scharnierout_of_mem(void) 23771558Srgrimes{ 23781558Srgrimes 237937663Scharnier syslog(LOG_ERR, "out of memory"); 23801558Srgrimes exit(2); 23811558Srgrimes} 23821558Srgrimes 23831558Srgrimes/* 2384158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 23851558Srgrimes * the kernel. 23861558Srgrimes */ 23871558Srgrimesint 2388158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2389158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 23901558Srgrimes{ 239175841Siedowse struct statfs fsb1; 239274462Salfred struct addrinfo *ai; 2393192934Srmacklem struct export_args ea, *eap; 2394158857Srodrigc char errmsg[255]; 2395158857Srodrigc char *cp; 23961558Srgrimes int done; 2397158857Srodrigc char savedc; 2398158857Srodrigc struct iovec *iov; 2399184588Sdfr int i, iovlen; 2400158857Srodrigc int ret; 2401192934Srmacklem struct nfsex_args nfsea; 24021558Srgrimes 2403192934Srmacklem if (run_v4server > 0) 2404192934Srmacklem eap = &nfsea.export; 2405192934Srmacklem else 2406192934Srmacklem eap = &ea; 2407192934Srmacklem 2408158857Srodrigc cp = NULL; 2409158857Srodrigc savedc = '\0'; 2410158857Srodrigc iov = NULL; 2411158857Srodrigc iovlen = 0; 2412158857Srodrigc ret = 0; 241375801Siedowse 2414192934Srmacklem bzero(eap, sizeof (struct export_args)); 2415158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2416192934Srmacklem eap->ex_flags = exflags; 2417192934Srmacklem eap->ex_anon = *anoncrp; 2418192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 241975641Siedowse if (grp->gr_type == GT_HOST) 242074462Salfred ai = grp->gr_ptr.gt_addrinfo; 242175641Siedowse else 242275641Siedowse ai = NULL; 2423192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2424192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2425192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2426192934Srmacklem if (eap->ex_numsecflavors == 0) { 2427192934Srmacklem eap->ex_numsecflavors = 1; 2428192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2429184588Sdfr } 24301558Srgrimes done = FALSE; 2431158857Srodrigc 2432192934Srmacklem if (v4root_phase == 0) { 2433192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2434192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2435192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2436192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2437192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2438192934Srmacklem sizeof (struct export_args)); 2439192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2440192934Srmacklem } 2441158857Srodrigc 24421558Srgrimes while (!done) { 24431558Srgrimes switch (grp->gr_type) { 24441558Srgrimes case GT_HOST: 244575641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 244674462Salfred goto skip; 2447192934Srmacklem eap->ex_addr = ai->ai_addr; 2448192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2449192934Srmacklem eap->ex_masklen = 0; 24501558Srgrimes break; 24511558Srgrimes case GT_NET: 245275801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 245374462Salfred have_v6 == 0) 245474462Salfred goto skip; 2455192934Srmacklem eap->ex_addr = 245675801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2457192934Srmacklem eap->ex_addrlen = 2458158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2459192934Srmacklem eap->ex_mask = 246075801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2461192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 24621558Srgrimes break; 246375641Siedowse case GT_DEFAULT: 2464192934Srmacklem eap->ex_addr = NULL; 2465192934Srmacklem eap->ex_addrlen = 0; 2466192934Srmacklem eap->ex_mask = NULL; 2467192934Srmacklem eap->ex_masklen = 0; 246875641Siedowse break; 24697401Swpaul case GT_IGNORE: 2470158857Srodrigc ret = 0; 2471158857Srodrigc goto error_exit; 24727401Swpaul break; 24731558Srgrimes default: 247437663Scharnier syslog(LOG_ERR, "bad grouptype"); 24751558Srgrimes if (cp) 24761558Srgrimes *cp = savedc; 2477158857Srodrigc ret = 1; 2478158857Srodrigc goto error_exit; 24791558Srgrimes }; 24801558Srgrimes 24811558Srgrimes /* 2482192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 24831558Srgrimes */ 2484192934Srmacklem if (v4root_phase == 2) { 2485192934Srmacklem nfsea.fspec = v4root_dirpath; 2486192934Srmacklem if (run_v4server > 0 && 2487192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2488192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2489192934Srmacklem return (2); 2490158857Srodrigc } 2491192934Srmacklem } else { 2492192934Srmacklem /* 2493192934Srmacklem * XXX: 2494192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2495192934Srmacklem * instead of looping back up the dirp to the mount 2496192934Srmacklem * point?? 2497192934Srmacklem * Also, needs to know how to export all types of local 2498192934Srmacklem * exportable filesystems and not just "ufs". 2499192934Srmacklem */ 2500192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2501192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2502192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2503192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2504192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2505192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2506270183Sbdrewery errmsg[0] = '\0'; 2507192934Srmacklem 2508192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2509192934Srmacklem if (cp) 2510192934Srmacklem *cp-- = savedc; 2511192934Srmacklem else 2512192934Srmacklem cp = dirp + dirplen - 1; 2513192934Srmacklem if (opt_flags & OP_QUIET) { 2514192934Srmacklem ret = 1; 2515192934Srmacklem goto error_exit; 2516192934Srmacklem } 2517192934Srmacklem if (errno == EPERM) { 2518192934Srmacklem if (debug) 2519239744Sdelphij warnx("can't change attributes for %s: %s", 2520239744Sdelphij dirp, errmsg); 2521192934Srmacklem syslog(LOG_ERR, 2522239744Sdelphij "can't change attributes for %s: %s", 2523239744Sdelphij dirp, errmsg); 2524192934Srmacklem ret = 1; 2525192934Srmacklem goto error_exit; 2526192934Srmacklem } 2527192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2528192934Srmacklem if (errno == EINVAL) 2529192934Srmacklem syslog(LOG_ERR, 2530100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2531192934Srmacklem dirp); 2532192934Srmacklem else 2533192934Srmacklem syslog(LOG_ERR, 2534192934Srmacklem "could not remount %s: %m", 2535192934Srmacklem dirp); 2536192934Srmacklem ret = 1; 2537192934Srmacklem goto error_exit; 2538192934Srmacklem } 2539192934Srmacklem /* back up over the last component */ 2540192934Srmacklem while (*cp == '/' && cp > dirp) 2541192934Srmacklem cp--; 2542192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2543192934Srmacklem cp--; 2544192934Srmacklem if (cp == dirp) { 2545192934Srmacklem if (debug) 2546192934Srmacklem warnx("mnt unsucc"); 2547192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2548192934Srmacklem dirp, errmsg); 2549192934Srmacklem ret = 1; 2550192934Srmacklem goto error_exit; 2551192934Srmacklem } 2552192934Srmacklem savedc = *cp; 2553192934Srmacklem *cp = '\0'; 2554192934Srmacklem /* 2555192934Srmacklem * Check that we're still on the same 2556192934Srmacklem * filesystem. 2557192934Srmacklem */ 2558192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2559192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2560192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2561192934Srmacklem *cp = savedc; 2562100336Sjoerg syslog(LOG_ERR, 2563192934Srmacklem "can't export %s %s", dirp, 2564192934Srmacklem errmsg); 2565192934Srmacklem ret = 1; 2566192934Srmacklem goto error_exit; 2567192934Srmacklem } 25681558Srgrimes } 25691558Srgrimes } 2570192934Srmacklem 2571192934Srmacklem /* 2572192934Srmacklem * For the experimental server: 2573192934Srmacklem * If this is the public directory, get the file handle 2574192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2575192934Srmacklem */ 2576192934Srmacklem if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2577192934Srmacklem fhandle_t fh; 2578192934Srmacklem char *public_name; 2579192934Srmacklem 2580192934Srmacklem if (eap->ex_indexfile != NULL) 2581192934Srmacklem public_name = eap->ex_indexfile; 2582192934Srmacklem else 2583192934Srmacklem public_name = dirp; 2584192934Srmacklem if (getfh(public_name, &fh) < 0) 2585192934Srmacklem syslog(LOG_ERR, 2586192934Srmacklem "Can't get public fh for %s", public_name); 2587192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2588192934Srmacklem syslog(LOG_ERR, 2589192934Srmacklem "Can't set public fh for %s", public_name); 2590192934Srmacklem else 2591192934Srmacklem has_publicfh = 1; 2592192934Srmacklem } 259374462Salfredskip: 259475641Siedowse if (ai != NULL) 259574462Salfred ai = ai->ai_next; 259675641Siedowse if (ai == NULL) 25971558Srgrimes done = TRUE; 25981558Srgrimes } 25991558Srgrimes if (cp) 26001558Srgrimes *cp = savedc; 2601158857Srodrigcerror_exit: 2602158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2603158857Srodrigc if (iov != NULL) { 2604158857Srodrigc free(iov[0].iov_base); /* fstype */ 2605158857Srodrigc free(iov[2].iov_base); /* fspath */ 2606158857Srodrigc free(iov[4].iov_base); /* from */ 2607158857Srodrigc free(iov[6].iov_base); /* update */ 2608158857Srodrigc free(iov[8].iov_base); /* export */ 2609158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2610158857Srodrigc 2611158857Srodrigc /* free iov, allocated by realloc() */ 2612158857Srodrigc free(iov); 2613158857Srodrigc } 2614158857Srodrigc return (ret); 26151558Srgrimes} 26161558Srgrimes 26171558Srgrimes/* 26181558Srgrimes * Translate a net address. 261975801Siedowse * 262075801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 26211558Srgrimes */ 26221558Srgrimesint 2623216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg) 26241558Srgrimes{ 262575861Siedowse struct netent *np = NULL; 262674462Salfred char *name, *p, *prefp; 262775801Siedowse struct sockaddr_in sin; 262875861Siedowse struct sockaddr *sa = NULL; 262974462Salfred struct addrinfo hints, *ai = NULL; 263074462Salfred char netname[NI_MAXHOST]; 263174462Salfred long preflen; 26321558Srgrimes 263375635Siedowse p = prefp = NULL; 263474462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 263574462Salfred p = strchr(cp, '/'); 263674462Salfred *p = '\0'; 263774462Salfred prefp = p + 1; 263874462Salfred } 263974462Salfred 264075861Siedowse /* 264175861Siedowse * Check for a numeric address first. We wish to avoid 264275861Siedowse * possible DNS lookups in getnetbyname(). 264375861Siedowse */ 264475861Siedowse if (isxdigit(*cp) || *cp == ':') { 264574462Salfred memset(&hints, 0, sizeof hints); 264675801Siedowse /* Ensure the mask and the network have the same family. */ 264775801Siedowse if (maskflg && (opt_flags & OP_NET)) 264875801Siedowse hints.ai_family = net->nt_net.ss_family; 264975801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 265075801Siedowse hints.ai_family = net->nt_mask.ss_family; 265175801Siedowse else 265275801Siedowse hints.ai_family = AF_UNSPEC; 265374462Salfred hints.ai_flags = AI_NUMERICHOST; 265475861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 265575861Siedowse sa = ai->ai_addr; 265675861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 265774462Salfred /* 265875801Siedowse * The address in `cp' is really a network address, so 265975801Siedowse * use inet_network() to re-interpret this correctly. 266075801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 266174462Salfred */ 266275801Siedowse bzero(&sin, sizeof sin); 266374462Salfred sin.sin_family = AF_INET; 266474462Salfred sin.sin_len = sizeof sin; 266575801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 266674462Salfred if (debug) 266775801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 266875801Siedowse inet_ntoa(sin.sin_addr)); 266974462Salfred sa = (struct sockaddr *)&sin; 267075861Siedowse } 267175861Siedowse } 267275861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 267375861Siedowse bzero(&sin, sizeof sin); 267475861Siedowse sin.sin_family = AF_INET; 267575861Siedowse sin.sin_len = sizeof sin; 267675861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 267775861Siedowse sa = (struct sockaddr *)&sin; 267875861Siedowse } 267975861Siedowse if (sa == NULL) 268074462Salfred goto fail; 268125318Spst 268275801Siedowse if (maskflg) { 268375801Siedowse /* The specified sockaddr is a mask. */ 268475801Siedowse if (checkmask(sa) != 0) 268575801Siedowse goto fail; 268675801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 268775801Siedowse opt_flags |= OP_HAVEMASK; 268875801Siedowse } else { 268975801Siedowse /* The specified sockaddr is a network address. */ 269075801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 269174462Salfred 269275801Siedowse /* Get a network name for the export list. */ 269375801Siedowse if (np) { 269475801Siedowse name = np->n_name; 269575801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2696146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 269775801Siedowse name = netname; 269875801Siedowse } else { 269975801Siedowse goto fail; 270075801Siedowse } 270175801Siedowse if ((net->nt_name = strdup(name)) == NULL) 270275801Siedowse out_of_mem(); 270375801Siedowse 270475801Siedowse /* 270575801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 270675801Siedowse * from the class of an IPv4 address. 270775801Siedowse */ 270874462Salfred if (opt_flags & OP_MASKLEN) { 270974462Salfred preflen = strtol(prefp, NULL, 10); 271075801Siedowse if (preflen < 0L || preflen == LONG_MAX) 271174462Salfred goto fail; 271275801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 271375801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 271475801Siedowse goto fail; 271575801Siedowse opt_flags |= OP_HAVEMASK; 271674462Salfred *p = '/'; 271775801Siedowse } else if (sa->sa_family == AF_INET && 271875801Siedowse (opt_flags & OP_MASK) == 0) { 271975801Siedowse in_addr_t addr; 272074462Salfred 272175801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 272275801Siedowse if (IN_CLASSA(addr)) 272375801Siedowse preflen = 8; 272475801Siedowse else if (IN_CLASSB(addr)) 272575801Siedowse preflen = 16; 272675801Siedowse else if (IN_CLASSC(addr)) 272775801Siedowse preflen = 24; 272875801Siedowse else if (IN_CLASSD(addr)) 272975801Siedowse preflen = 28; 273075801Siedowse else 273175801Siedowse preflen = 32; /* XXX */ 273275801Siedowse 273375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 273475801Siedowse makemask(&net->nt_mask, (int)preflen); 273575801Siedowse opt_flags |= OP_HAVEMASK; 273674462Salfred } 273774462Salfred } 273874462Salfred 273974462Salfred if (ai) 274074462Salfred freeaddrinfo(ai); 274174462Salfred return 0; 274274462Salfred 274374462Salfredfail: 274474462Salfred if (ai) 274574462Salfred freeaddrinfo(ai); 274674462Salfred return 1; 27471558Srgrimes} 27481558Srgrimes 27491558Srgrimes/* 27501558Srgrimes * Parse out the next white space separated field 27511558Srgrimes */ 27521558Srgrimesvoid 2753216587Scharniernextfield(char **cp, char **endcp) 27541558Srgrimes{ 27551558Srgrimes char *p; 27561558Srgrimes 27571558Srgrimes p = *cp; 27581558Srgrimes while (*p == ' ' || *p == '\t') 27591558Srgrimes p++; 27601558Srgrimes if (*p == '\n' || *p == '\0') 27611558Srgrimes *cp = *endcp = p; 27621558Srgrimes else { 27631558Srgrimes *cp = p++; 27641558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 27651558Srgrimes p++; 27661558Srgrimes *endcp = p; 27671558Srgrimes } 27681558Srgrimes} 27691558Srgrimes 27701558Srgrimes/* 27711558Srgrimes * Get an exports file line. Skip over blank lines and handle line 27721558Srgrimes * continuations. 27731558Srgrimes */ 27741558Srgrimesint 2775216587Scharnierget_line(void) 27761558Srgrimes{ 27771558Srgrimes char *p, *cp; 277896622Siedowse size_t len; 27791558Srgrimes int totlen, cont_line; 27801558Srgrimes 27811558Srgrimes /* 27821558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 27831558Srgrimes */ 27841558Srgrimes p = line; 27851558Srgrimes totlen = 0; 27861558Srgrimes do { 278796622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 27881558Srgrimes return (0); 27891558Srgrimes cp = p + len - 1; 27901558Srgrimes cont_line = 0; 27911558Srgrimes while (cp >= p && 27921558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 27931558Srgrimes if (*cp == '\\') 27941558Srgrimes cont_line = 1; 27951558Srgrimes cp--; 27961558Srgrimes len--; 27971558Srgrimes } 279879117Sdd if (cont_line) { 279979117Sdd *++cp = ' '; 280079117Sdd len++; 280179117Sdd } 280296622Siedowse if (linesize < len + totlen + 1) { 280396622Siedowse linesize = len + totlen + 1; 280496622Siedowse line = realloc(line, linesize); 280596622Siedowse if (line == NULL) 280696622Siedowse out_of_mem(); 28071558Srgrimes } 280896622Siedowse memcpy(line + totlen, p, len); 280996622Siedowse totlen += len; 281096622Siedowse line[totlen] = '\0'; 28111558Srgrimes } while (totlen == 0 || cont_line); 28121558Srgrimes return (1); 28131558Srgrimes} 28141558Srgrimes 28151558Srgrimes/* 28161558Srgrimes * Parse a description of a credential. 28171558Srgrimes */ 28181558Srgrimesvoid 2819216587Scharnierparsecred(char *namelist, struct xucred *cr) 28201558Srgrimes{ 28211558Srgrimes char *name; 28221558Srgrimes int cnt; 28231558Srgrimes char *names; 28241558Srgrimes struct passwd *pw; 28251558Srgrimes struct group *gr; 2826194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2827136051Sstefanf int ngroups; 28281558Srgrimes 282991354Sdd cr->cr_version = XUCRED_VERSION; 28301558Srgrimes /* 283137663Scharnier * Set up the unprivileged user. 28321558Srgrimes */ 28331558Srgrimes cr->cr_uid = -2; 28341558Srgrimes cr->cr_groups[0] = -2; 28351558Srgrimes cr->cr_ngroups = 1; 28361558Srgrimes /* 28371558Srgrimes * Get the user's password table entry. 28381558Srgrimes */ 28391558Srgrimes names = strsep(&namelist, " \t\n"); 28401558Srgrimes name = strsep(&names, ":"); 28411558Srgrimes if (isdigit(*name) || *name == '-') 28421558Srgrimes pw = getpwuid(atoi(name)); 28431558Srgrimes else 28441558Srgrimes pw = getpwnam(name); 28451558Srgrimes /* 28461558Srgrimes * Credentials specified as those of a user. 28471558Srgrimes */ 28481558Srgrimes if (names == NULL) { 28491558Srgrimes if (pw == NULL) { 285037663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 28511558Srgrimes return; 28521558Srgrimes } 28531558Srgrimes cr->cr_uid = pw->pw_uid; 2854194498Sbrooks ngroups = XU_NGROUPS + 1; 28551558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 285637663Scharnier syslog(LOG_ERR, "too many groups"); 28571558Srgrimes /* 2858136051Sstefanf * Compress out duplicate. 28591558Srgrimes */ 28601558Srgrimes cr->cr_ngroups = ngroups - 1; 28611558Srgrimes cr->cr_groups[0] = groups[0]; 28621558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 28631558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 28641558Srgrimes return; 28651558Srgrimes } 28661558Srgrimes /* 28671558Srgrimes * Explicit credential specified as a colon separated list: 28681558Srgrimes * uid:gid:gid:... 28691558Srgrimes */ 28701558Srgrimes if (pw != NULL) 28711558Srgrimes cr->cr_uid = pw->pw_uid; 28721558Srgrimes else if (isdigit(*name) || *name == '-') 28731558Srgrimes cr->cr_uid = atoi(name); 28741558Srgrimes else { 287537663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 28761558Srgrimes return; 28771558Srgrimes } 28781558Srgrimes cr->cr_ngroups = 0; 2879194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 28801558Srgrimes name = strsep(&names, ":"); 28811558Srgrimes if (isdigit(*name) || *name == '-') { 28821558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 28831558Srgrimes } else { 28841558Srgrimes if ((gr = getgrnam(name)) == NULL) { 288537663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 28861558Srgrimes continue; 28871558Srgrimes } 28881558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 28891558Srgrimes } 28901558Srgrimes } 2891194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 289237663Scharnier syslog(LOG_ERR, "too many groups"); 28931558Srgrimes} 28941558Srgrimes 2895194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 28961558Srgrimes/* 28971558Srgrimes * Routines that maintain the remote mounttab 28981558Srgrimes */ 28991558Srgrimesvoid 2900216587Scharnierget_mountlist(void) 29011558Srgrimes{ 29021558Srgrimes struct mountlist *mlp, **mlpp; 290323681Speter char *host, *dirp, *cp; 29041558Srgrimes char str[STRSIZ]; 29051558Srgrimes FILE *mlfile; 29061558Srgrimes 29071558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 290853117Sbillf if (errno == ENOENT) 290953117Sbillf return; 291053117Sbillf else { 291153117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 291253117Sbillf return; 291353117Sbillf } 29141558Srgrimes } 29151558Srgrimes mlpp = &mlhead; 29161558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 291723681Speter cp = str; 291823681Speter host = strsep(&cp, " \t\n"); 291923681Speter dirp = strsep(&cp, " \t\n"); 292023681Speter if (host == NULL || dirp == NULL) 29211558Srgrimes continue; 29221558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 292337663Scharnier if (mlp == (struct mountlist *)NULL) 292437663Scharnier out_of_mem(); 2925194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 2926194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2927194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2928194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 29291558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 29301558Srgrimes *mlpp = mlp; 29311558Srgrimes mlpp = &mlp->ml_next; 29321558Srgrimes } 29331558Srgrimes fclose(mlfile); 29341558Srgrimes} 29351558Srgrimes 293675635Siedowsevoid 293775635Siedowsedel_mlist(char *hostp, char *dirp) 29381558Srgrimes{ 29391558Srgrimes struct mountlist *mlp, **mlpp; 29401558Srgrimes struct mountlist *mlp2; 29411558Srgrimes FILE *mlfile; 29421558Srgrimes int fnd = 0; 29431558Srgrimes 29441558Srgrimes mlpp = &mlhead; 29451558Srgrimes mlp = mlhead; 29461558Srgrimes while (mlp) { 29471558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 29481558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 29491558Srgrimes fnd = 1; 29501558Srgrimes mlp2 = mlp; 29511558Srgrimes *mlpp = mlp = mlp->ml_next; 29521558Srgrimes free((caddr_t)mlp2); 29531558Srgrimes } else { 29541558Srgrimes mlpp = &mlp->ml_next; 29551558Srgrimes mlp = mlp->ml_next; 29561558Srgrimes } 29571558Srgrimes } 29581558Srgrimes if (fnd) { 29591558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 296037663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 29611558Srgrimes return; 29621558Srgrimes } 29631558Srgrimes mlp = mlhead; 29641558Srgrimes while (mlp) { 29651558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 29661558Srgrimes mlp = mlp->ml_next; 29671558Srgrimes } 29681558Srgrimes fclose(mlfile); 29691558Srgrimes } 29701558Srgrimes} 29711558Srgrimes 29721558Srgrimesvoid 2973216587Scharnieradd_mlist(char *hostp, char *dirp) 29741558Srgrimes{ 29751558Srgrimes struct mountlist *mlp, **mlpp; 29761558Srgrimes FILE *mlfile; 29771558Srgrimes 29781558Srgrimes mlpp = &mlhead; 29791558Srgrimes mlp = mlhead; 29801558Srgrimes while (mlp) { 29811558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 29821558Srgrimes return; 29831558Srgrimes mlpp = &mlp->ml_next; 29841558Srgrimes mlp = mlp->ml_next; 29851558Srgrimes } 29861558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 298737663Scharnier if (mlp == (struct mountlist *)NULL) 298837663Scharnier out_of_mem(); 2989194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 2990194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2991194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2992194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 29931558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 29941558Srgrimes *mlpp = mlp; 29951558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 299637663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 29971558Srgrimes return; 29981558Srgrimes } 29991558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 30001558Srgrimes fclose(mlfile); 30011558Srgrimes} 30021558Srgrimes 30031558Srgrimes/* 30041558Srgrimes * Free up a group list. 30051558Srgrimes */ 30061558Srgrimesvoid 3007216587Scharnierfree_grp(struct grouplist *grp) 30081558Srgrimes{ 30091558Srgrimes if (grp->gr_type == GT_HOST) { 301074462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 301174462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 30121558Srgrimes } else if (grp->gr_type == GT_NET) { 30131558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 30141558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 30151558Srgrimes } 30161558Srgrimes free((caddr_t)grp); 30171558Srgrimes} 30181558Srgrimes 30191558Srgrimes#ifdef DEBUG 30201558Srgrimesvoid 30211558SrgrimesSYSLOG(int pri, const char *fmt, ...) 30221558Srgrimes{ 30231558Srgrimes va_list ap; 30241558Srgrimes 30251558Srgrimes va_start(ap, fmt); 30261558Srgrimes vfprintf(stderr, fmt, ap); 30271558Srgrimes va_end(ap); 30281558Srgrimes} 30291558Srgrimes#endif /* DEBUG */ 30301558Srgrimes 30311558Srgrimes/* 30321558Srgrimes * Check options for consistency. 30331558Srgrimes */ 30341558Srgrimesint 3035216587Scharniercheck_options(struct dirlist *dp) 30361558Srgrimes{ 30371558Srgrimes 3038192934Srmacklem if (v4root_phase == 0 && dp == NULL) 30391558Srgrimes return (1); 304083653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 304183653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 30421558Srgrimes return (1); 30431558Srgrimes } 30441558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 304575801Siedowse syslog(LOG_ERR, "-mask requires -network"); 304675801Siedowse return (1); 30471558Srgrimes } 304875801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 304975801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 305075801Siedowse return (1); 305175801Siedowse } 305275801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 305375801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 305475801Siedowse return (1); 305575801Siedowse } 3056192934Srmacklem if (v4root_phase > 0 && 3057192934Srmacklem (opt_flags & 3058192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3059192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3060192934Srmacklem return (1); 3061192934Srmacklem } 3062207689Srmacklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 3063207689Srmacklem syslog(LOG_ERR, "-alldirs has multiple directories"); 3064207689Srmacklem return (1); 3065207689Srmacklem } 30661558Srgrimes return (0); 30671558Srgrimes} 30681558Srgrimes 30691558Srgrimes/* 30701558Srgrimes * Check an absolute directory path for any symbolic links. Return true 30711558Srgrimes */ 30721558Srgrimesint 3073216587Scharniercheck_dirpath(char *dirp) 30741558Srgrimes{ 30751558Srgrimes char *cp; 30761558Srgrimes int ret = 1; 30771558Srgrimes struct stat sb; 30781558Srgrimes 30791558Srgrimes cp = dirp + 1; 30801558Srgrimes while (*cp && ret) { 30811558Srgrimes if (*cp == '/') { 30821558Srgrimes *cp = '\0'; 30839336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 30841558Srgrimes ret = 0; 30851558Srgrimes *cp = '/'; 30861558Srgrimes } 30871558Srgrimes cp++; 30881558Srgrimes } 30899336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 30901558Srgrimes ret = 0; 30911558Srgrimes return (ret); 30921558Srgrimes} 30939336Sdfr 309475801Siedowse/* 309575801Siedowse * Make a netmask according to the specified prefix length. The ss_family 309675801Siedowse * and other non-address fields must be initialised before calling this. 309775801Siedowse */ 309875801Siedowseint 309975801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 310074462Salfred{ 310175801Siedowse u_char *p; 310275801Siedowse int bits, i, len; 310374462Salfred 310475801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 310575801Siedowse return (-1); 3106103949Smike if (bitlen > len * CHAR_BIT) 310775801Siedowse return (-1); 310874462Salfred 310975801Siedowse for (i = 0; i < len; i++) { 3110103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 3111219125Sru *p++ = (u_char)~0 << (CHAR_BIT - bits); 311275801Siedowse bitlen -= bits; 311374462Salfred } 311475801Siedowse return 0; 311574462Salfred} 311674462Salfred 311775801Siedowse/* 311875801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 311975801Siedowse * is acceptable (i.e. of the form 1...10....0). 312075801Siedowse */ 312175801Siedowseint 312275801Siedowsecheckmask(struct sockaddr *sa) 312374462Salfred{ 312475801Siedowse u_char *mask; 312575801Siedowse int i, len; 312674462Salfred 312775801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 312875801Siedowse return (-1); 312975801Siedowse 313075801Siedowse for (i = 0; i < len; i++) 313175801Siedowse if (mask[i] != 0xff) 313275801Siedowse break; 313375801Siedowse if (i < len) { 313475801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 313575801Siedowse return (-1); 313675801Siedowse i++; 313774462Salfred } 313875801Siedowse for (; i < len; i++) 313975801Siedowse if (mask[i] != 0) 314075801Siedowse return (-1); 314175801Siedowse return (0); 314274462Salfred} 314374462Salfred 314475801Siedowse/* 314575801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 314675801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 3147228990Suqs * If samask is NULL, perform a full comparison. 314875801Siedowse */ 314975801Siedowseint 315075801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 315174462Salfred{ 315275801Siedowse unsigned char *p1, *p2, *mask; 315375801Siedowse int len, i; 315474462Salfred 315575801Siedowse if (sa1->sa_family != sa2->sa_family || 315675801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 315775801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 315875801Siedowse return (1); 315975801Siedowse 316075801Siedowse switch (sa1->sa_family) { 316174462Salfred case AF_INET6: 316275801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 316375801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 316475801Siedowse return (1); 316574462Salfred break; 316674462Salfred } 316774462Salfred 316875801Siedowse /* Simple binary comparison if no mask specified. */ 316975801Siedowse if (samask == NULL) 317075801Siedowse return (memcmp(p1, p2, len)); 317174462Salfred 317275801Siedowse /* Set up the mask, and do a mask-based comparison. */ 317375801Siedowse if (sa1->sa_family != samask->sa_family || 317475801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 317575801Siedowse return (1); 317674462Salfred 317775801Siedowse for (i = 0; i < len; i++) 317875801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 317975801Siedowse return (1); 318075801Siedowse return (0); 318174462Salfred} 318274462Salfred 318375801Siedowse/* 318475801Siedowse * Return a pointer to the part of the sockaddr that contains the 318575801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 318675801Siedowse * NULL if the address family is unknown. 318775801Siedowse */ 318875801Siedowsevoid * 318975801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 319075801Siedowse void *p; 319174462Salfred int len; 319274462Salfred 319375801Siedowse switch (sa->sa_family) { 319474462Salfred case AF_INET: 319575801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 319675801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 319774462Salfred break; 319874462Salfred case AF_INET6: 319975801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 320075801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 320174462Salfred break; 320274462Salfred default: 320375801Siedowse p = NULL; 320475801Siedowse len = 0; 320574462Salfred } 320674462Salfred 320775801Siedowse if (nbytes != NULL) 320875801Siedowse *nbytes = len; 320975801Siedowse return (p); 321074462Salfred} 321174462Salfred 321275754Siedowsevoid 3213216587Scharnierhuphandler(int sig __unused) 321475754Siedowse{ 321575754Siedowse got_sighup = 1; 321675754Siedowse} 321775754Siedowse 3218216587Scharniervoid terminate(int sig __unused) 321974462Salfred{ 3220149433Spjd pidfile_remove(pfh); 3221194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3222194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 322374462Salfred exit (0); 322474462Salfred} 3225192934Srmacklem 3226