mountd.c revision 194880
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 194880 2009-06-24 18:42:21Z dfr $"); 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]; 1201558Srgrimes}; 1211558Srgrimes/* ex_flag bits */ 1221558Srgrimes#define EX_LINKED 0x1 1231558Srgrimes 1241558Srgrimesstruct netmsk { 12574462Salfred struct sockaddr_storage nt_net; 12675801Siedowse struct sockaddr_storage nt_mask; 12742144Sdfr char *nt_name; 1281558Srgrimes}; 1291558Srgrimes 1301558Srgrimesunion grouptypes { 13174462Salfred struct addrinfo *gt_addrinfo; 1321558Srgrimes struct netmsk gt_net; 1331558Srgrimes}; 1341558Srgrimes 1351558Srgrimesstruct grouplist { 1361558Srgrimes int gr_type; 1371558Srgrimes union grouptypes gr_ptr; 1381558Srgrimes struct grouplist *gr_next; 1391558Srgrimes}; 1401558Srgrimes/* Group types */ 1411558Srgrimes#define GT_NULL 0x0 1421558Srgrimes#define GT_HOST 0x1 1431558Srgrimes#define GT_NET 0x2 14475641Siedowse#define GT_DEFAULT 0x3 1457401Swpaul#define GT_IGNORE 0x5 1461558Srgrimes 1471558Srgrimesstruct hostlist { 1489336Sdfr int ht_flag; /* Uses DP_xx bits */ 1491558Srgrimes struct grouplist *ht_grp; 1501558Srgrimes struct hostlist *ht_next; 1511558Srgrimes}; 1521558Srgrimes 1539336Sdfrstruct fhreturn { 1549336Sdfr int fhr_flag; 1559336Sdfr int fhr_vers; 1569336Sdfr nfsfh_t fhr_fh; 157184588Sdfr int fhr_numsecflavors; 158184588Sdfr int *fhr_secflavors; 1599336Sdfr}; 1609336Sdfr 1611558Srgrimes/* Global defs */ 16292882Simpchar *add_expdir(struct dirlist **, char *, int); 16392882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16492882Simp struct grouplist *, int); 16592882Simpvoid add_mlist(char *, char *); 16692882Simpint check_dirpath(char *); 16792882Simpint check_options(struct dirlist *); 16875801Siedowseint checkmask(struct sockaddr *sa); 16992882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 170172827Smatteovoid create_service(struct netconfig *nconf); 17175635Siedowsevoid del_mlist(char *hostp, char *dirp); 17292882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 17392882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17492882Simp struct xucred *, char *, int, struct statfs *); 17592882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17692882Simp int *, int *, struct xucred *); 17792882Simpstruct exportlist *ex_search(fsid_t *); 17892882Simpstruct exportlist *get_exp(void); 17992882Simpvoid free_dir(struct dirlist *); 18092882Simpvoid free_exp(struct exportlist *); 18192882Simpvoid free_grp(struct grouplist *); 18292882Simpvoid free_host(struct hostlist *); 18392882Simpvoid get_exportlist(void); 18492882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18592882Simpstruct hostlist *get_ht(void); 18692882Simpint get_line(void); 18792882Simpvoid get_mountlist(void); 18892882Simpint get_net(char *, struct netmsk *, int); 18992882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 19092882Simpstruct grouplist *get_grp(void); 19192882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 19292882Simp struct exportlist *, int); 19375754Siedowsevoid huphandler(int sig); 19475801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19592882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19692882Simpvoid nextfield(char **, char **); 19792882Simpvoid out_of_mem(void); 19892882Simpvoid parsecred(char *, struct xucred *); 199100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 20075801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 20175801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20275801Siedowse struct sockaddr *samask); 20392882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20492882Simpstatic void usage(void); 20592882Simpint xdr_dir(XDR *, char *); 20692882Simpint xdr_explist(XDR *, caddr_t); 207100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20892882Simpint xdr_fhs(XDR *, caddr_t); 20992882Simpint xdr_mlist(XDR *, caddr_t); 21092882Simpvoid terminate(int); 2111558Srgrimes 2121558Srgrimesstruct exportlist *exphead; 2131558Srgrimesstruct mountlist *mlhead; 2141558Srgrimesstruct grouplist *grphead; 215166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 216166440Spjdchar **exnames; 217172827Smatteochar **hosts = NULL; 21872650Sgreenstruct xucred def_anon = { 21991354Sdd XUCRED_VERSION, 22072650Sgreen (uid_t)-2, 2211558Srgrimes 1, 22272650Sgreen { (gid_t)-2 }, 22372650Sgreen NULL 2241558Srgrimes}; 22525087Sdfrint force_v2 = 0; 2269336Sdfrint resvport_only = 1; 227172827Smatteoint nhosts = 0; 2289336Sdfrint dir_only = 1; 229121767Speterint dolog = 0; 23075754Siedowseint got_sighup = 0; 231172827Smatteoint xcreated = 0; 23274462Salfred 233172827Smatteochar *svcport_str = NULL; 234172827Smatteo 2351558Srgrimesint opt_flags; 23674462Salfredstatic int have_v6 = 1; 23774462Salfred 238192934Srmacklemint v4root_phase = 0; 239192934Srmacklemchar v4root_dirpath[PATH_MAX + 1]; 240192934Srmacklemint run_v4server = 0; 241192934Srmacklemint has_publicfh = 0; 242192934Srmacklem 243149433Spjdstruct pidfh *pfh = NULL; 24475801Siedowse/* Bits for opt_flags above */ 2451558Srgrimes#define OP_MAPROOT 0x01 2461558Srgrimes#define OP_MAPALL 0x02 24783653Speter/* 0x4 free */ 2481558Srgrimes#define OP_MASK 0x08 2491558Srgrimes#define OP_NET 0x10 2501558Srgrimes#define OP_ALLDIRS 0x40 25175801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 252100336Sjoerg#define OP_QUIET 0x100 25374462Salfred#define OP_MASKLEN 0x200 254184588Sdfr#define OP_SEC 0x400 2551558Srgrimes 2561558Srgrimes#ifdef DEBUG 2571558Srgrimesint debug = 1; 25892882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2591558Srgrimes#define syslog SYSLOG 2601558Srgrimes#else 2611558Srgrimesint debug = 0; 2621558Srgrimes#endif 2631558Srgrimes 2641558Srgrimes/* 2651558Srgrimes * Mountd server for NFS mount protocol as described in: 2661558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2671558Srgrimes * The optional arguments are the exports file name 2681558Srgrimes * default: _PATH_EXPORTS 2691558Srgrimes * and "-n" to allow nonroot mount. 2701558Srgrimes */ 2711558Srgrimesint 2721558Srgrimesmain(argc, argv) 2731558Srgrimes int argc; 2741558Srgrimes char **argv; 2751558Srgrimes{ 27675754Siedowse fd_set readfds; 277172827Smatteo struct netconfig *nconf; 278172827Smatteo char *endptr, **hosts_bak; 279172827Smatteo void *nc_handle; 280149433Spjd pid_t otherpid; 281172827Smatteo in_port_t svcport; 282172827Smatteo int c, k, s; 283109363Smbr int maxrec = RPC_MAXDATASIZE; 2841558Srgrimes 28574462Salfred /* Check that another mountd isn't already running. */ 286150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 287149433Spjd if (pfh == NULL) { 288149433Spjd if (errno == EEXIST) 289149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 290149433Spjd warn("cannot open or create pidfile"); 291149433Spjd } 29274462Salfred 29374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 29474462Salfred if (s < 0) 29574462Salfred have_v6 = 0; 29674462Salfred else 29774462Salfred close(s); 2982999Swollman 299192993Srmacklem while ((c = getopt(argc, argv, "2deh:lnp:r")) != -1) 3001558Srgrimes switch (c) { 30125087Sdfr case '2': 30225087Sdfr force_v2 = 1; 30325087Sdfr break; 304192993Srmacklem case 'e': 305192934Srmacklem run_v4server = 1; 306192934Srmacklem break; 3079336Sdfr case 'n': 3089336Sdfr resvport_only = 0; 3099336Sdfr break; 3109336Sdfr case 'r': 3119336Sdfr dir_only = 0; 3129336Sdfr break; 3138688Sphk case 'd': 3148688Sphk debug = debug ? 0 : 1; 3158688Sphk break; 31631656Sguido case 'l': 317121767Speter dolog = 1; 31831656Sguido break; 319126572Sbms case 'p': 320126572Sbms endptr = NULL; 321126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 322126572Sbms if (endptr == NULL || *endptr != '\0' || 323126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 324126572Sbms usage(); 325172827Smatteo svcport_str = strdup(optarg); 326126572Sbms break; 327172827Smatteo case 'h': 328172827Smatteo ++nhosts; 329172827Smatteo hosts_bak = hosts; 330172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 331172827Smatteo if (hosts_bak == NULL) { 332172827Smatteo if (hosts != NULL) { 333172827Smatteo for (k = 0; k < nhosts; k++) 334172827Smatteo free(hosts[k]); 335172827Smatteo free(hosts); 336172827Smatteo out_of_mem(); 337172827Smatteo } 338172827Smatteo } 339172827Smatteo hosts = hosts_bak; 340172827Smatteo hosts[nhosts - 1] = strdup(optarg); 341172827Smatteo if (hosts[nhosts - 1] == NULL) { 342172827Smatteo for (k = 0; k < (nhosts - 1); k++) 343172827Smatteo free(hosts[k]); 344172827Smatteo free(hosts); 345172827Smatteo out_of_mem(); 346172827Smatteo } 347172827Smatteo break; 3481558Srgrimes default: 34937663Scharnier usage(); 3501558Srgrimes }; 351192934Srmacklem 352192934Srmacklem /* 353192993Srmacklem * If the "-e" option was specified OR only the nfsd module is 354192934Srmacklem * found in the server, run "nfsd". 355192934Srmacklem * Otherwise, try and run "nfsserver". 356192934Srmacklem */ 357192934Srmacklem if (run_v4server > 0) { 358192934Srmacklem if (modfind("nfsd") < 0) { 359192934Srmacklem /* Not present in kernel, try loading it */ 360192934Srmacklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 361192934Srmacklem errx(1, "NFS server is not available"); 362192934Srmacklem } 363192934Srmacklem } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { 364192934Srmacklem run_v4server = 1; 365192934Srmacklem } else if (modfind("nfsserver") < 0) { 366192934Srmacklem /* Not present in kernel, try loading it */ 367192934Srmacklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 368192934Srmacklem errx(1, "NFS server is not available"); 369192934Srmacklem } 370192934Srmacklem 3711558Srgrimes argc -= optind; 3721558Srgrimes argv += optind; 3731558Srgrimes grphead = (struct grouplist *)NULL; 3741558Srgrimes exphead = (struct exportlist *)NULL; 3751558Srgrimes mlhead = (struct mountlist *)NULL; 376166440Spjd if (argc > 0) 377166440Spjd exnames = argv; 378166440Spjd else 379166440Spjd exnames = exnames_default; 3801558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3811558Srgrimes if (debug) 38237663Scharnier warnx("getting export list"); 3831558Srgrimes get_exportlist(); 3841558Srgrimes if (debug) 38537663Scharnier warnx("getting mount list"); 3861558Srgrimes get_mountlist(); 3871558Srgrimes if (debug) 38837663Scharnier warnx("here we go"); 3891558Srgrimes if (debug == 0) { 3901558Srgrimes daemon(0, 0); 3911558Srgrimes signal(SIGINT, SIG_IGN); 3921558Srgrimes signal(SIGQUIT, SIG_IGN); 3931558Srgrimes } 39475754Siedowse signal(SIGHUP, huphandler); 39574462Salfred signal(SIGTERM, terminate); 396164394Srodrigc signal(SIGPIPE, SIG_IGN); 397149433Spjd 398149433Spjd pidfile_write(pfh); 399149433Spjd 400194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 401194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 402109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 403109363Smbr 40424759Sguido if (!resvport_only) { 40583687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 40683687Speter &resvport_only, sizeof(resvport_only)) != 0 && 40783687Speter errno != ENOENT) { 40824759Sguido syslog(LOG_ERR, "sysctl: %m"); 40924759Sguido exit(1); 41024759Sguido } 41124330Sguido } 412126572Sbms 413172827Smatteo /* 414172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 415172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 416172827Smatteo * list. 417172827Smatteo */ 418172827Smatteo if (nhosts == 0) { 419172827Smatteo hosts = malloc(sizeof(char**)); 420172827Smatteo if (hosts == NULL) 421172827Smatteo out_of_mem(); 422172827Smatteo hosts[0] = "*"; 423172827Smatteo nhosts = 1; 424172827Smatteo } else { 425172827Smatteo hosts_bak = hosts; 426172827Smatteo if (have_v6) { 427172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 428172827Smatteo sizeof(char *)); 429172827Smatteo if (hosts_bak == NULL) { 430172827Smatteo for (k = 0; k < nhosts; k++) 431172827Smatteo free(hosts[k]); 432172827Smatteo free(hosts); 433172827Smatteo out_of_mem(); 434172827Smatteo } else 435172827Smatteo hosts = hosts_bak; 436172827Smatteo nhosts += 2; 437172827Smatteo hosts[nhosts - 2] = "::1"; 438172827Smatteo } else { 439172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 440172827Smatteo if (hosts_bak == NULL) { 441172827Smatteo for (k = 0; k < nhosts; k++) 442172827Smatteo free(hosts[k]); 443172827Smatteo free(hosts); 444172827Smatteo out_of_mem(); 445172827Smatteo } else { 446172827Smatteo nhosts += 1; 447172827Smatteo hosts = hosts_bak; 448126572Sbms } 449172827Smatteo } 45074462Salfred 451172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 45274462Salfred } 45374462Salfred 454172827Smatteo nc_handle = setnetconfig(); 455172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 456172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 457172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 458172827Smatteo "inet6") == 0) { 459172827Smatteo /* DO NOTHING */ 460172827Smatteo } else 461172827Smatteo create_service(nconf); 462172827Smatteo } 46374462Salfred } 464172827Smatteo endnetconfig(nc_handle); 46574462Salfred 46674462Salfred if (xcreated == 0) { 46774462Salfred syslog(LOG_ERR, "could not create any services"); 4681558Srgrimes exit(1); 4691558Srgrimes } 47075754Siedowse 47175754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 47275754Siedowse for (;;) { 47375754Siedowse if (got_sighup) { 47475754Siedowse get_exportlist(); 47575754Siedowse got_sighup = 0; 47675754Siedowse } 47775754Siedowse readfds = svc_fdset; 47875754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 47975754Siedowse case -1: 48075754Siedowse if (errno == EINTR) 48175754Siedowse continue; 48275754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 48375754Siedowse exit(1); 48475754Siedowse case 0: 48575754Siedowse continue; 48675754Siedowse default: 48775754Siedowse svc_getreqset(&readfds); 48875754Siedowse } 48975754Siedowse } 490172827Smatteo} 491172827Smatteo 492172827Smatteo/* 493172827Smatteo * This routine creates and binds sockets on the appropriate 494172827Smatteo * addresses. It gets called one time for each transport and 495172827Smatteo * registrates the service with rpcbind on that trasport. 496172827Smatteo */ 497172827Smatteovoid 498172827Smatteocreate_service(struct netconfig *nconf) 499172827Smatteo{ 500172827Smatteo struct addrinfo hints, *res = NULL; 501172827Smatteo struct sockaddr_in *sin; 502172827Smatteo struct sockaddr_in6 *sin6; 503172827Smatteo struct __rpc_sockinfo si; 504172827Smatteo struct netbuf servaddr; 505172827Smatteo SVCXPRT *transp = NULL; 506172827Smatteo int aicode; 507172827Smatteo int fd; 508172827Smatteo int nhostsbak; 509172827Smatteo int one = 1; 510172827Smatteo int r; 511172827Smatteo int registered = 0; 512172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 513172827Smatteo 514172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 515172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 516172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 517172827Smatteo return; /* not my type */ 518172827Smatteo 519172827Smatteo /* 520172827Smatteo * XXX - using RPC library internal functions. 521172827Smatteo */ 522172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 523172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 524172827Smatteo nconf->nc_netid); 525172827Smatteo return; 526172827Smatteo } 527172827Smatteo 528172827Smatteo /* Get mountd's address on this transport */ 529172827Smatteo memset(&hints, 0, sizeof hints); 530172827Smatteo hints.ai_flags = AI_PASSIVE; 531172827Smatteo hints.ai_family = si.si_af; 532172827Smatteo hints.ai_socktype = si.si_socktype; 533172827Smatteo hints.ai_protocol = si.si_proto; 534172827Smatteo 535172827Smatteo /* 536172827Smatteo * Bind to specific IPs if asked to 537172827Smatteo */ 538172827Smatteo nhostsbak = nhosts; 539172827Smatteo while (nhostsbak > 0) { 540172827Smatteo --nhostsbak; 541172827Smatteo /* 542172827Smatteo * XXX - using RPC library internal functions. 543172827Smatteo */ 544172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 545172827Smatteo int non_fatal = 0; 546172827Smatteo if (errno == EPROTONOSUPPORT && 547172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 548172827Smatteo non_fatal = 1; 549172827Smatteo 550172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 551172827Smatteo "cannot create socket for %s", nconf->nc_netid); 552172827Smatteo return; 553172827Smatteo } 554172827Smatteo 555172827Smatteo switch (hints.ai_family) { 556172827Smatteo case AF_INET: 557172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 558172827Smatteo host_addr) == 1) { 559172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 560172827Smatteo } else { 561172827Smatteo /* 562172827Smatteo * Skip if we have an AF_INET6 address. 563172827Smatteo */ 564172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 565172827Smatteo host_addr) == 1) { 566172827Smatteo close(fd); 567172827Smatteo continue; 568172827Smatteo } 569172827Smatteo } 570172827Smatteo break; 571172827Smatteo case AF_INET6: 572172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 573172827Smatteo host_addr) == 1) { 574172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 575172827Smatteo } else { 576172827Smatteo /* 577172827Smatteo * Skip if we have an AF_INET address. 578172827Smatteo */ 579172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 580172827Smatteo host_addr) == 1) { 581172827Smatteo close(fd); 582172827Smatteo continue; 583172827Smatteo } 584172827Smatteo } 585172827Smatteo 586172827Smatteo /* 587172827Smatteo * We're doing host-based access checks here, so don't 588172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 589172827Smatteo * disable it by default on NFS sockets too. 590172827Smatteo */ 591172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 592172827Smatteo sizeof one) < 0) { 593172827Smatteo syslog(LOG_ERR, 594172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 595172827Smatteo exit(1); 596172827Smatteo } 597172827Smatteo break; 598172827Smatteo default: 599172827Smatteo break; 600172827Smatteo } 601172827Smatteo 602172827Smatteo /* 603172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 604172827Smatteo */ 605172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 606172827Smatteo if (svcport_str == NULL) { 607172827Smatteo res = malloc(sizeof(struct addrinfo)); 608172827Smatteo if (res == NULL) 609172827Smatteo out_of_mem(); 610172827Smatteo res->ai_flags = hints.ai_flags; 611172827Smatteo res->ai_family = hints.ai_family; 612172827Smatteo res->ai_protocol = hints.ai_protocol; 613172827Smatteo switch (res->ai_family) { 614172827Smatteo case AF_INET: 615172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 616172827Smatteo if (sin == NULL) 617172827Smatteo out_of_mem(); 618172827Smatteo sin->sin_family = AF_INET; 619172827Smatteo sin->sin_port = htons(0); 620172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 621172827Smatteo res->ai_addr = (struct sockaddr*) sin; 622172827Smatteo res->ai_addrlen = (socklen_t) 623172827Smatteo sizeof(res->ai_addr); 624172827Smatteo break; 625172827Smatteo case AF_INET6: 626172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 627173056Ssimon if (sin6 == NULL) 628172827Smatteo out_of_mem(); 629172827Smatteo sin6->sin6_family = AF_INET6; 630172827Smatteo sin6->sin6_port = htons(0); 631172827Smatteo sin6->sin6_addr = in6addr_any; 632172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 633172827Smatteo res->ai_addrlen = (socklen_t) 634172827Smatteo sizeof(res->ai_addr); 635172827Smatteo break; 636172827Smatteo default: 637172827Smatteo break; 638172827Smatteo } 639172827Smatteo } else { 640172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 641172827Smatteo &hints, &res)) != 0) { 642172827Smatteo syslog(LOG_ERR, 643172827Smatteo "cannot get local address for %s: %s", 644172827Smatteo nconf->nc_netid, 645172827Smatteo gai_strerror(aicode)); 646172827Smatteo continue; 647172827Smatteo } 648172827Smatteo } 649172827Smatteo } else { 650172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 651172827Smatteo &hints, &res)) != 0) { 652172827Smatteo syslog(LOG_ERR, 653172827Smatteo "cannot get local address for %s: %s", 654172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 655172827Smatteo continue; 656172827Smatteo } 657172827Smatteo } 658172827Smatteo 659172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 660172827Smatteo if (r != 0) { 661172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 662172827Smatteo exit(1); 663172827Smatteo } 664172827Smatteo 665172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 666172827Smatteo listen(fd, SOMAXCONN); 667172827Smatteo 668172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 669172827Smatteo transp = svc_dg_create(fd, 0, 0); 670172827Smatteo else 671172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 672172827Smatteo RPC_MAXDATASIZE); 673172827Smatteo 674172827Smatteo if (transp != (SVCXPRT *) NULL) { 675194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 676172827Smatteo NULL)) 677172827Smatteo syslog(LOG_ERR, 678194880Sdfr "can't register %s MOUNTVERS service", 679172827Smatteo nconf->nc_netid); 680172827Smatteo if (!force_v2) { 681194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 682172827Smatteo mntsrv, NULL)) 683172827Smatteo syslog(LOG_ERR, 684194880Sdfr "can't register %s MOUNTVERS3 service", 685172827Smatteo nconf->nc_netid); 686172827Smatteo } 687172827Smatteo } else 688172827Smatteo syslog(LOG_WARNING, "can't create %s services", 689172827Smatteo nconf->nc_netid); 690172827Smatteo 691172827Smatteo if (registered == 0) { 692172827Smatteo registered = 1; 693172827Smatteo memset(&hints, 0, sizeof hints); 694172827Smatteo hints.ai_flags = AI_PASSIVE; 695172827Smatteo hints.ai_family = si.si_af; 696172827Smatteo hints.ai_socktype = si.si_socktype; 697172827Smatteo hints.ai_protocol = si.si_proto; 698172827Smatteo 699172827Smatteo if (svcport_str == NULL) { 700172827Smatteo svcport_str = malloc(NI_MAXSERV * sizeof(char)); 701172827Smatteo if (svcport_str == NULL) 702172827Smatteo out_of_mem(); 703172827Smatteo 704172827Smatteo if (getnameinfo(res->ai_addr, 705172827Smatteo res->ai_addr->sa_len, NULL, NI_MAXHOST, 706172827Smatteo svcport_str, NI_MAXSERV * sizeof(char), 707172827Smatteo NI_NUMERICHOST | NI_NUMERICSERV)) 708172827Smatteo errx(1, "Cannot get port number"); 709172827Smatteo } 710172827Smatteo 711172827Smatteo if((aicode = getaddrinfo(NULL, svcport_str, &hints, 712172827Smatteo &res)) != 0) { 713172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 714172827Smatteo gai_strerror(aicode)); 715172827Smatteo exit(1); 716172827Smatteo } 717172827Smatteo 718172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 719172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 720172827Smatteo servaddr.len = res->ai_addrlen; 721172827Smatteo 722194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 723194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 724172827Smatteo 725172827Smatteo xcreated++; 726172827Smatteo freeaddrinfo(res); 727172827Smatteo } 728172827Smatteo } /* end while */ 7291558Srgrimes} 7301558Srgrimes 73137663Scharnierstatic void 73237663Scharnierusage() 73337663Scharnier{ 73437663Scharnier fprintf(stderr, 735192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 736172827Smatteo "[-h <bindip>] [export_file ...]\n"); 73737663Scharnier exit(1); 73837663Scharnier} 73937663Scharnier 7401558Srgrimes/* 7411558Srgrimes * The mount rpc service 7421558Srgrimes */ 7431558Srgrimesvoid 7441558Srgrimesmntsrv(rqstp, transp) 7451558Srgrimes struct svc_req *rqstp; 7461558Srgrimes SVCXPRT *transp; 7471558Srgrimes{ 7481558Srgrimes struct exportlist *ep; 7491558Srgrimes struct dirlist *dp; 7509336Sdfr struct fhreturn fhr; 7511558Srgrimes struct stat stb; 7521558Srgrimes struct statfs fsb; 75374462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 75474462Salfred int lookup_failed = 1; 75574462Salfred struct sockaddr *saddr; 7569336Sdfr u_short sport; 757194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 75828911Sguido int bad = 0, defset, hostset; 7599336Sdfr sigset_t sighup_mask; 7601558Srgrimes 7619336Sdfr sigemptyset(&sighup_mask); 7629336Sdfr sigaddset(&sighup_mask, SIGHUP); 76374462Salfred saddr = svc_getrpccaller(transp)->buf; 76474462Salfred switch (saddr->sa_family) { 76574462Salfred case AF_INET6: 76675635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 76774462Salfred break; 76874462Salfred case AF_INET: 76975635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 77074462Salfred break; 77174462Salfred default: 77274462Salfred syslog(LOG_ERR, "request from unknown address family"); 77374462Salfred return; 77474462Salfred } 77574462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 77674462Salfred NULL, 0, 0); 77774462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 77874462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 7791558Srgrimes switch (rqstp->rq_proc) { 7801558Srgrimes case NULLPROC: 781121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 78237663Scharnier syslog(LOG_ERR, "can't send reply"); 7831558Srgrimes return; 784194880Sdfr case MOUNTPROC_MNT: 7859336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 78631656Sguido syslog(LOG_NOTICE, 78731656Sguido "mount request from %s from unprivileged port", 78874462Salfred numerichost); 7891558Srgrimes svcerr_weakauth(transp); 7901558Srgrimes return; 7911558Srgrimes } 792121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 79331656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 79474462Salfred numerichost); 7951558Srgrimes svcerr_decode(transp); 7961558Srgrimes return; 7971558Srgrimes } 7981558Srgrimes 7991558Srgrimes /* 8001558Srgrimes * Get the real pathname and make sure it is a directory 8019336Sdfr * or a regular file if the -r option was specified 8029336Sdfr * and it exists. 8031558Srgrimes */ 80451968Salfred if (realpath(rpcpath, dirpath) == NULL || 8051558Srgrimes stat(dirpath, &stb) < 0 || 8069336Sdfr (!S_ISDIR(stb.st_mode) && 80774462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 8081558Srgrimes statfs(dirpath, &fsb) < 0) { 8091558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 81031656Sguido syslog(LOG_NOTICE, 81137663Scharnier "mount request from %s for non existent path %s", 81274462Salfred numerichost, dirpath); 8131558Srgrimes if (debug) 81437663Scharnier warnx("stat failed on %s", dirpath); 81528911Sguido bad = ENOENT; /* We will send error reply later */ 8161558Srgrimes } 8171558Srgrimes 8181558Srgrimes /* Check in the exports list */ 8199336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 8201558Srgrimes ep = ex_search(&fsb.f_fsid); 8219336Sdfr hostset = defset = 0; 8229336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 8231558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 82474462Salfred chk_host(dp, saddr, &defset, &hostset)) || 82574462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 82674462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 82728911Sguido if (bad) { 828121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 82928911Sguido (caddr_t)&bad)) 83037663Scharnier syslog(LOG_ERR, "can't send reply"); 83128911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 83228911Sguido return; 83328911Sguido } 8349336Sdfr if (hostset & DP_HOSTSET) 8359336Sdfr fhr.fhr_flag = hostset; 8369336Sdfr else 8379336Sdfr fhr.fhr_flag = defset; 8389336Sdfr fhr.fhr_vers = rqstp->rq_vers; 8391558Srgrimes /* Get the file handle */ 84023681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 8419336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 8421558Srgrimes bad = errno; 84337663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 844121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 8451558Srgrimes (caddr_t)&bad)) 84637663Scharnier syslog(LOG_ERR, "can't send reply"); 8479336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8481558Srgrimes return; 8491558Srgrimes } 850184588Sdfr fhr.fhr_numsecflavors = ep->ex_numsecflavors; 851184588Sdfr fhr.fhr_secflavors = ep->ex_secflavors; 852121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 853121556Speter (caddr_t)&fhr)) 85437663Scharnier syslog(LOG_ERR, "can't send reply"); 85574462Salfred if (!lookup_failed) 85674462Salfred add_mlist(host, dirpath); 8571558Srgrimes else 85874462Salfred add_mlist(numerichost, dirpath); 8591558Srgrimes if (debug) 86037663Scharnier warnx("mount successful"); 861121767Speter if (dolog) 86231656Sguido syslog(LOG_NOTICE, 86331656Sguido "mount request succeeded from %s for %s", 86474462Salfred numerichost, dirpath); 86531656Sguido } else { 8661558Srgrimes bad = EACCES; 86731656Sguido syslog(LOG_NOTICE, 86831656Sguido "mount request denied from %s for %s", 86974462Salfred numerichost, dirpath); 87031656Sguido } 87128911Sguido 872121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 873121556Speter (caddr_t)&bad)) 87437663Scharnier syslog(LOG_ERR, "can't send reply"); 8759336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8761558Srgrimes return; 877194880Sdfr case MOUNTPROC_DUMP: 878121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 87937663Scharnier syslog(LOG_ERR, "can't send reply"); 880121767Speter else if (dolog) 88131656Sguido syslog(LOG_NOTICE, 88231656Sguido "dump request succeeded from %s", 88374462Salfred numerichost); 8841558Srgrimes return; 885194880Sdfr case MOUNTPROC_UMNT: 8869336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 88731656Sguido syslog(LOG_NOTICE, 88831656Sguido "umount request from %s from unprivileged port", 88974462Salfred numerichost); 8901558Srgrimes svcerr_weakauth(transp); 8911558Srgrimes return; 8921558Srgrimes } 893121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 89431656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 89574462Salfred numerichost); 8961558Srgrimes svcerr_decode(transp); 8971558Srgrimes return; 8981558Srgrimes } 89951968Salfred if (realpath(rpcpath, dirpath) == NULL) { 90051968Salfred syslog(LOG_NOTICE, "umount request from %s " 90151968Salfred "for non existent path %s", 90274462Salfred numerichost, dirpath); 90351968Salfred } 904121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 90537663Scharnier syslog(LOG_ERR, "can't send reply"); 90674462Salfred if (!lookup_failed) 90775635Siedowse del_mlist(host, dirpath); 90875635Siedowse del_mlist(numerichost, dirpath); 909121767Speter if (dolog) 91031656Sguido syslog(LOG_NOTICE, 91131656Sguido "umount request succeeded from %s for %s", 91274462Salfred numerichost, dirpath); 9131558Srgrimes return; 914194880Sdfr case MOUNTPROC_UMNTALL: 9159336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 91631656Sguido syslog(LOG_NOTICE, 91731656Sguido "umountall request from %s from unprivileged port", 91874462Salfred numerichost); 9191558Srgrimes svcerr_weakauth(transp); 9201558Srgrimes return; 9211558Srgrimes } 922121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 92337663Scharnier syslog(LOG_ERR, "can't send reply"); 92474462Salfred if (!lookup_failed) 92575635Siedowse del_mlist(host, NULL); 92675635Siedowse del_mlist(numerichost, NULL); 927121767Speter if (dolog) 92831656Sguido syslog(LOG_NOTICE, 92931656Sguido "umountall request succeeded from %s", 93074462Salfred numerichost); 9311558Srgrimes return; 932194880Sdfr case MOUNTPROC_EXPORT: 933121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 934121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 935121556Speter (caddr_t)NULL)) 936100117Salfred syslog(LOG_ERR, "can't send reply"); 937121767Speter if (dolog) 93831656Sguido syslog(LOG_NOTICE, 93931656Sguido "export request succeeded from %s", 94074462Salfred numerichost); 9411558Srgrimes return; 9421558Srgrimes default: 9431558Srgrimes svcerr_noproc(transp); 9441558Srgrimes return; 9451558Srgrimes } 9461558Srgrimes} 9471558Srgrimes 9481558Srgrimes/* 9491558Srgrimes * Xdr conversion for a dirpath string 9501558Srgrimes */ 9511558Srgrimesint 9521558Srgrimesxdr_dir(xdrsp, dirp) 9531558Srgrimes XDR *xdrsp; 9541558Srgrimes char *dirp; 9551558Srgrimes{ 956194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 9571558Srgrimes} 9581558Srgrimes 9591558Srgrimes/* 9609336Sdfr * Xdr routine to generate file handle reply 9611558Srgrimes */ 9621558Srgrimesint 9639336Sdfrxdr_fhs(xdrsp, cp) 9641558Srgrimes XDR *xdrsp; 9659336Sdfr caddr_t cp; 9661558Srgrimes{ 96792806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 9689336Sdfr u_long ok = 0, len, auth; 969184588Sdfr int i; 9701558Srgrimes 9711558Srgrimes if (!xdr_long(xdrsp, &ok)) 9721558Srgrimes return (0); 9739336Sdfr switch (fhrp->fhr_vers) { 9749336Sdfr case 1: 9759336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 9769336Sdfr case 3: 9779336Sdfr len = NFSX_V3FH; 9789336Sdfr if (!xdr_long(xdrsp, &len)) 9799336Sdfr return (0); 9809336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 9819336Sdfr return (0); 982184588Sdfr if (fhrp->fhr_numsecflavors) { 983184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 984184588Sdfr return (0); 985184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 986184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 987184588Sdfr return (0); 988184588Sdfr return (1); 989184588Sdfr } else { 990184588Sdfr auth = AUTH_SYS; 991184588Sdfr len = 1; 992184588Sdfr if (!xdr_long(xdrsp, &len)) 993184588Sdfr return (0); 994184588Sdfr return (xdr_long(xdrsp, &auth)); 995184588Sdfr } 9969336Sdfr }; 9979336Sdfr return (0); 9981558Srgrimes} 9991558Srgrimes 10001558Srgrimesint 10011558Srgrimesxdr_mlist(xdrsp, cp) 10021558Srgrimes XDR *xdrsp; 10031558Srgrimes caddr_t cp; 10041558Srgrimes{ 10051558Srgrimes struct mountlist *mlp; 10061558Srgrimes int true = 1; 10071558Srgrimes int false = 0; 10081558Srgrimes char *strp; 10091558Srgrimes 10101558Srgrimes mlp = mlhead; 10111558Srgrimes while (mlp) { 10121558Srgrimes if (!xdr_bool(xdrsp, &true)) 10131558Srgrimes return (0); 10141558Srgrimes strp = &mlp->ml_host[0]; 1015194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 10161558Srgrimes return (0); 10171558Srgrimes strp = &mlp->ml_dirp[0]; 1018194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 10191558Srgrimes return (0); 10201558Srgrimes mlp = mlp->ml_next; 10211558Srgrimes } 10221558Srgrimes if (!xdr_bool(xdrsp, &false)) 10231558Srgrimes return (0); 10241558Srgrimes return (1); 10251558Srgrimes} 10261558Srgrimes 10271558Srgrimes/* 10281558Srgrimes * Xdr conversion for export list 10291558Srgrimes */ 10301558Srgrimesint 1031100117Salfredxdr_explist_common(xdrsp, cp, brief) 10321558Srgrimes XDR *xdrsp; 10331558Srgrimes caddr_t cp; 1034100117Salfred int brief; 10351558Srgrimes{ 10361558Srgrimes struct exportlist *ep; 10371558Srgrimes int false = 0; 10389336Sdfr int putdef; 10399336Sdfr sigset_t sighup_mask; 10401558Srgrimes 10419336Sdfr sigemptyset(&sighup_mask); 10429336Sdfr sigaddset(&sighup_mask, SIGHUP); 10439336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10441558Srgrimes ep = exphead; 10451558Srgrimes while (ep) { 10461558Srgrimes putdef = 0; 1047100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1048100117Salfred &putdef, brief)) 10491558Srgrimes goto errout; 10501558Srgrimes if (ep->ex_defdir && putdef == 0 && 10511558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1052100117Salfred &putdef, brief)) 10531558Srgrimes goto errout; 10541558Srgrimes ep = ep->ex_next; 10551558Srgrimes } 10569336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10571558Srgrimes if (!xdr_bool(xdrsp, &false)) 10581558Srgrimes return (0); 10591558Srgrimes return (1); 10601558Srgrimeserrout: 10619336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10621558Srgrimes return (0); 10631558Srgrimes} 10641558Srgrimes 10651558Srgrimes/* 10661558Srgrimes * Called from xdr_explist() to traverse the tree and export the 10671558Srgrimes * directory paths. 10681558Srgrimes */ 10691558Srgrimesint 1070100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 10711558Srgrimes struct dirlist *dp; 10721558Srgrimes XDR *xdrsp; 10731558Srgrimes struct dirlist *adp; 10741558Srgrimes int *putdefp; 1075100117Salfred int brief; 10761558Srgrimes{ 10771558Srgrimes struct grouplist *grp; 10781558Srgrimes struct hostlist *hp; 10791558Srgrimes int true = 1; 10801558Srgrimes int false = 0; 10811558Srgrimes int gotalldir = 0; 10821558Srgrimes char *strp; 10831558Srgrimes 10841558Srgrimes if (dp) { 1085100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 10861558Srgrimes return (1); 10871558Srgrimes if (!xdr_bool(xdrsp, &true)) 10881558Srgrimes return (1); 10891558Srgrimes strp = dp->dp_dirp; 1090194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 10911558Srgrimes return (1); 10921558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 10931558Srgrimes gotalldir = 1; 10941558Srgrimes *putdefp = 1; 10951558Srgrimes } 1096100117Salfred if (brief) { 1097100117Salfred if (!xdr_bool(xdrsp, &true)) 1098100117Salfred return (1); 1099100117Salfred strp = "(...)"; 1100194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1101100117Salfred return (1); 1102100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 11031558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 11041558Srgrimes hp = dp->dp_hosts; 11051558Srgrimes while (hp) { 11061558Srgrimes grp = hp->ht_grp; 11071558Srgrimes if (grp->gr_type == GT_HOST) { 11081558Srgrimes if (!xdr_bool(xdrsp, &true)) 11091558Srgrimes return (1); 111074462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 11118871Srgrimes if (!xdr_string(xdrsp, &strp, 1112194880Sdfr MNTNAMLEN)) 11131558Srgrimes return (1); 11141558Srgrimes } else if (grp->gr_type == GT_NET) { 11151558Srgrimes if (!xdr_bool(xdrsp, &true)) 11161558Srgrimes return (1); 11171558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 11188871Srgrimes if (!xdr_string(xdrsp, &strp, 1119194880Sdfr MNTNAMLEN)) 11201558Srgrimes return (1); 11211558Srgrimes } 11221558Srgrimes hp = hp->ht_next; 11231558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 11241558Srgrimes hp = adp->dp_hosts; 11251558Srgrimes gotalldir = 0; 11261558Srgrimes } 11271558Srgrimes } 11281558Srgrimes } 11291558Srgrimes if (!xdr_bool(xdrsp, &false)) 11301558Srgrimes return (1); 1131100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 11321558Srgrimes return (1); 11331558Srgrimes } 11341558Srgrimes return (0); 11351558Srgrimes} 11361558Srgrimes 1137100117Salfredint 1138100117Salfredxdr_explist(xdrsp, cp) 1139100117Salfred XDR *xdrsp; 1140100117Salfred caddr_t cp; 1141100117Salfred{ 1142100117Salfred 1143100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1144100117Salfred} 1145100117Salfred 1146100117Salfredint 1147100117Salfredxdr_explist_brief(xdrsp, cp) 1148100117Salfred XDR *xdrsp; 1149100117Salfred caddr_t cp; 1150100117Salfred{ 1151100117Salfred 1152100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1153100117Salfred} 1154100117Salfred 115596622Siedowsechar *line; 115696622Siedowseint linesize; 11571558SrgrimesFILE *exp_file; 11581558Srgrimes 11591558Srgrimes/* 1160166440Spjd * Get the export list from one, currently open file 11611558Srgrimes */ 1162166440Spjdstatic void 1163166440Spjdget_exportlist_one() 11641558Srgrimes{ 11651558Srgrimes struct exportlist *ep, *ep2; 11661558Srgrimes struct grouplist *grp, *tgrp; 11671558Srgrimes struct exportlist **epp; 11681558Srgrimes struct dirlist *dirhead; 1169166440Spjd struct statfs fsb; 117072650Sgreen struct xucred anon; 11711558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1172166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 11731558Srgrimes 1174192934Srmacklem v4root_phase = 0; 11751558Srgrimes dirhead = (struct dirlist *)NULL; 11761558Srgrimes while (get_line()) { 11771558Srgrimes if (debug) 117837663Scharnier warnx("got line %s", line); 11791558Srgrimes cp = line; 11801558Srgrimes nextfield(&cp, &endcp); 11811558Srgrimes if (*cp == '#') 11821558Srgrimes goto nextline; 11831558Srgrimes 11841558Srgrimes /* 11851558Srgrimes * Set defaults. 11861558Srgrimes */ 11871558Srgrimes has_host = FALSE; 11881558Srgrimes anon = def_anon; 11891558Srgrimes exflags = MNT_EXPORTED; 11901558Srgrimes got_nondir = 0; 11911558Srgrimes opt_flags = 0; 11921558Srgrimes ep = (struct exportlist *)NULL; 1193192934Srmacklem dirp = NULL; 11941558Srgrimes 11951558Srgrimes /* 1196192934Srmacklem * Handle the V4 root dir. 1197192934Srmacklem */ 1198192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1199192934Srmacklem /* 1200192934Srmacklem * V4: just indicates that it is the v4 root point, 1201192934Srmacklem * so skip over that and set v4root_phase. 1202192934Srmacklem */ 1203192934Srmacklem if (v4root_phase > 0) { 1204192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1205192934Srmacklem goto nextline; 1206192934Srmacklem } 1207192934Srmacklem v4root_phase = 1; 1208192934Srmacklem cp += 3; 1209192934Srmacklem nextfield(&cp, &endcp); 1210192934Srmacklem } 1211192934Srmacklem 1212192934Srmacklem /* 12131558Srgrimes * Create new exports list entry 12141558Srgrimes */ 12151558Srgrimes len = endcp-cp; 12161558Srgrimes tgrp = grp = get_grp(); 12171558Srgrimes while (len > 0) { 1218194880Sdfr if (len > MNTNAMLEN) { 12191558Srgrimes getexp_err(ep, tgrp); 12201558Srgrimes goto nextline; 12211558Srgrimes } 12221558Srgrimes if (*cp == '-') { 12231558Srgrimes if (ep == (struct exportlist *)NULL) { 12241558Srgrimes getexp_err(ep, tgrp); 12251558Srgrimes goto nextline; 12261558Srgrimes } 12271558Srgrimes if (debug) 122837663Scharnier warnx("doing opt %s", cp); 12291558Srgrimes got_nondir = 1; 12301558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 12311558Srgrimes &exflags, &anon)) { 12321558Srgrimes getexp_err(ep, tgrp); 12331558Srgrimes goto nextline; 12341558Srgrimes } 12351558Srgrimes } else if (*cp == '/') { 12361558Srgrimes savedc = *endcp; 12371558Srgrimes *endcp = '\0'; 1238192934Srmacklem if (v4root_phase > 1) { 1239192934Srmacklem if (dirp != NULL) { 1240192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 1241192934Srmacklem getexp_err(ep, tgrp); 1242192934Srmacklem goto nextline; 1243192934Srmacklem } 1244192934Srmacklem } 12451558Srgrimes if (check_dirpath(cp) && 12461558Srgrimes statfs(cp, &fsb) >= 0) { 12471558Srgrimes if (got_nondir) { 124837663Scharnier syslog(LOG_ERR, "dirs must be first"); 12491558Srgrimes getexp_err(ep, tgrp); 12501558Srgrimes goto nextline; 12511558Srgrimes } 1252192934Srmacklem if (v4root_phase == 1) { 1253192934Srmacklem if (dirp != NULL) { 1254192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 12551558Srgrimes getexp_err(ep, tgrp); 12561558Srgrimes goto nextline; 12571558Srgrimes } 1258192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1259192934Srmacklem strlcpy(v4root_dirpath, cp, 1260192934Srmacklem sizeof (v4root_dirpath)); 1261192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1262192934Srmacklem != 0) { 1263192934Srmacklem syslog(LOG_ERR, 1264192934Srmacklem "different V4 dirpath %s", cp); 1265192934Srmacklem getexp_err(ep, tgrp); 1266192934Srmacklem goto nextline; 1267192934Srmacklem } 1268192934Srmacklem dirp = cp; 1269192934Srmacklem v4root_phase = 2; 1270192934Srmacklem got_nondir = 1; 1271192934Srmacklem ep = get_exp(); 12721558Srgrimes } else { 1273192934Srmacklem if (ep) { 1274192934Srmacklem if (ep->ex_fs.val[0] != 1275192934Srmacklem fsb.f_fsid.val[0] || 1276192934Srmacklem ep->ex_fs.val[1] != 1277192934Srmacklem fsb.f_fsid.val[1]) { 1278192934Srmacklem getexp_err(ep, tgrp); 1279192934Srmacklem goto nextline; 1280192934Srmacklem } 1281192934Srmacklem } else { 1282192934Srmacklem /* 1283192934Srmacklem * See if this directory is already 1284192934Srmacklem * in the list. 1285192934Srmacklem */ 1286192934Srmacklem ep = ex_search(&fsb.f_fsid); 1287192934Srmacklem if (ep == (struct exportlist *)NULL) { 1288192934Srmacklem ep = get_exp(); 1289192934Srmacklem ep->ex_fs = fsb.f_fsid; 1290192934Srmacklem ep->ex_fsdir = (char *)malloc 1291192934Srmacklem (strlen(fsb.f_mntonname) + 1); 1292192934Srmacklem if (ep->ex_fsdir) 1293192934Srmacklem strcpy(ep->ex_fsdir, 1294192934Srmacklem fsb.f_mntonname); 1295192934Srmacklem else 1296192934Srmacklem out_of_mem(); 1297192934Srmacklem if (debug) 1298192934Srmacklem warnx( 1299192934Srmacklem "making new ep fs=0x%x,0x%x", 1300192934Srmacklem fsb.f_fsid.val[0], 1301192934Srmacklem fsb.f_fsid.val[1]); 1302192934Srmacklem } else if (debug) 1303192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1304192934Srmacklem fsb.f_fsid.val[0], 1305192934Srmacklem fsb.f_fsid.val[1]); 1306192934Srmacklem } 1307192934Srmacklem 13081558Srgrimes /* 1309192934Srmacklem * Add dirpath to export mount point. 13101558Srgrimes */ 1311192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1312192934Srmacklem dirplen = len; 13131558Srgrimes } 13141558Srgrimes } else { 13151558Srgrimes getexp_err(ep, tgrp); 13161558Srgrimes goto nextline; 13171558Srgrimes } 13181558Srgrimes *endcp = savedc; 13191558Srgrimes } else { 13201558Srgrimes savedc = *endcp; 13211558Srgrimes *endcp = '\0'; 13221558Srgrimes got_nondir = 1; 13231558Srgrimes if (ep == (struct exportlist *)NULL) { 13241558Srgrimes getexp_err(ep, tgrp); 13251558Srgrimes goto nextline; 13261558Srgrimes } 13271558Srgrimes 13281558Srgrimes /* 13291558Srgrimes * Get the host or netgroup. 13301558Srgrimes */ 13311558Srgrimes setnetgrent(cp); 13321558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 13331558Srgrimes do { 13341558Srgrimes if (has_host) { 13351558Srgrimes grp->gr_next = get_grp(); 13361558Srgrimes grp = grp->gr_next; 13371558Srgrimes } 13381558Srgrimes if (netgrp) { 133937003Sjoerg if (hst == 0) { 134037663Scharnier syslog(LOG_ERR, 134137663Scharnier "null hostname in netgroup %s, skipping", cp); 134237004Sjoerg grp->gr_type = GT_IGNORE; 134337003Sjoerg } else if (get_host(hst, grp, tgrp)) { 134437663Scharnier syslog(LOG_ERR, 134537663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 134629317Sjlemon grp->gr_type = GT_IGNORE; 13471558Srgrimes } 13487401Swpaul } else if (get_host(cp, grp, tgrp)) { 134937663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 135029317Sjlemon grp->gr_type = GT_IGNORE; 13511558Srgrimes } 13521558Srgrimes has_host = TRUE; 13531558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 13541558Srgrimes endnetgrent(); 13551558Srgrimes *endcp = savedc; 13561558Srgrimes } 13571558Srgrimes cp = endcp; 13581558Srgrimes nextfield(&cp, &endcp); 13591558Srgrimes len = endcp - cp; 13601558Srgrimes } 13611558Srgrimes if (check_options(dirhead)) { 13621558Srgrimes getexp_err(ep, tgrp); 13631558Srgrimes goto nextline; 13641558Srgrimes } 13651558Srgrimes if (!has_host) { 136675641Siedowse grp->gr_type = GT_DEFAULT; 13671558Srgrimes if (debug) 136837663Scharnier warnx("adding a default entry"); 13691558Srgrimes 13701558Srgrimes /* 13711558Srgrimes * Don't allow a network export coincide with a list of 13721558Srgrimes * host(s) on the same line. 13731558Srgrimes */ 13741558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 137575801Siedowse syslog(LOG_ERR, "network/host conflict"); 13761558Srgrimes getexp_err(ep, tgrp); 13771558Srgrimes goto nextline; 137829317Sjlemon 137974462Salfred /* 138074462Salfred * If an export list was specified on this line, make sure 138129317Sjlemon * that we have at least one valid entry, otherwise skip it. 138229317Sjlemon */ 138329317Sjlemon } else { 138429317Sjlemon grp = tgrp; 138574462Salfred while (grp && grp->gr_type == GT_IGNORE) 138629317Sjlemon grp = grp->gr_next; 138729317Sjlemon if (! grp) { 138829317Sjlemon getexp_err(ep, tgrp); 138929317Sjlemon goto nextline; 139029317Sjlemon } 13911558Srgrimes } 13921558Srgrimes 1393192934Srmacklem if (v4root_phase == 1) { 1394192934Srmacklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1395192934Srmacklem getexp_err(ep, tgrp); 1396192934Srmacklem goto nextline; 1397192934Srmacklem } 1398192934Srmacklem 13991558Srgrimes /* 14001558Srgrimes * Loop through hosts, pushing the exports into the kernel. 14011558Srgrimes * After loop, tgrp points to the start of the list and 14021558Srgrimes * grp points to the last entry in the list. 14031558Srgrimes */ 14041558Srgrimes grp = tgrp; 14051558Srgrimes do { 140675635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 140775635Siedowse &fsb)) { 140875635Siedowse getexp_err(ep, tgrp); 140975635Siedowse goto nextline; 141075635Siedowse } 14111558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 14121558Srgrimes 14131558Srgrimes /* 1414192934Srmacklem * For V4: don't enter in mount lists. 1415192934Srmacklem */ 1416194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1417194773Srmacklem /* 1418194773Srmacklem * Since these structures aren't used by mountd, 1419194773Srmacklem * free them up now. 1420194773Srmacklem */ 1421194773Srmacklem if (ep != NULL) 1422194773Srmacklem free_exp(ep); 1423194773Srmacklem while (tgrp != NULL) { 1424194773Srmacklem grp = tgrp; 1425194773Srmacklem tgrp = tgrp->gr_next; 1426194773Srmacklem free_grp(grp); 1427194773Srmacklem } 1428192934Srmacklem goto nextline; 1429194773Srmacklem } 1430192934Srmacklem 1431192934Srmacklem /* 14321558Srgrimes * Success. Update the data structures. 14331558Srgrimes */ 14341558Srgrimes if (has_host) { 14359336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 14361558Srgrimes grp->gr_next = grphead; 14371558Srgrimes grphead = tgrp; 14381558Srgrimes } else { 14391558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 14409336Sdfr opt_flags); 14411558Srgrimes free_grp(grp); 14421558Srgrimes } 14431558Srgrimes dirhead = (struct dirlist *)NULL; 14441558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 14451558Srgrimes ep2 = exphead; 14461558Srgrimes epp = &exphead; 14471558Srgrimes 14481558Srgrimes /* 14491558Srgrimes * Insert in the list in alphabetical order. 14501558Srgrimes */ 14511558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 14521558Srgrimes epp = &ep2->ex_next; 14531558Srgrimes ep2 = ep2->ex_next; 14541558Srgrimes } 14551558Srgrimes if (ep2) 14561558Srgrimes ep->ex_next = ep2; 14571558Srgrimes *epp = ep; 14581558Srgrimes ep->ex_flag |= EX_LINKED; 14591558Srgrimes } 14601558Srgrimesnextline: 1461192934Srmacklem v4root_phase = 0; 14621558Srgrimes if (dirhead) { 14631558Srgrimes free_dir(dirhead); 14641558Srgrimes dirhead = (struct dirlist *)NULL; 14651558Srgrimes } 14661558Srgrimes } 14671558Srgrimes} 14681558Srgrimes 14691558Srgrimes/* 1470166440Spjd * Get the export list from all specified files 1471166440Spjd */ 1472166440Spjdvoid 1473166440Spjdget_exportlist() 1474166440Spjd{ 1475166440Spjd struct exportlist *ep, *ep2; 1476166440Spjd struct grouplist *grp, *tgrp; 1477166440Spjd struct export_args export; 1478166440Spjd struct iovec *iov; 1479166440Spjd struct statfs *fsp, *mntbufp; 1480166440Spjd struct xvfsconf vfc; 1481166440Spjd char *dirp; 1482166440Spjd char errmsg[255]; 1483166440Spjd int dirplen, num, i; 1484166440Spjd int iovlen; 1485168684Spjd int done; 1486192934Srmacklem struct nfsex_args eargs; 1487166440Spjd 1488192934Srmacklem v4root_dirpath[0] = '\0'; 1489166440Spjd bzero(&export, sizeof(export)); 1490166440Spjd export.ex_flags = MNT_DELEXPORT; 1491166440Spjd dirp = NULL; 1492166440Spjd dirplen = 0; 1493166440Spjd iov = NULL; 1494166440Spjd iovlen = 0; 1495166440Spjd bzero(errmsg, sizeof(errmsg)); 1496166440Spjd 1497166440Spjd /* 1498166440Spjd * First, get rid of the old list 1499166440Spjd */ 1500166440Spjd ep = exphead; 1501166440Spjd while (ep) { 1502166440Spjd ep2 = ep; 1503166440Spjd ep = ep->ex_next; 1504166440Spjd free_exp(ep2); 1505166440Spjd } 1506166440Spjd exphead = (struct exportlist *)NULL; 1507166440Spjd 1508166440Spjd grp = grphead; 1509166440Spjd while (grp) { 1510166440Spjd tgrp = grp; 1511166440Spjd grp = grp->gr_next; 1512166440Spjd free_grp(tgrp); 1513166440Spjd } 1514166440Spjd grphead = (struct grouplist *)NULL; 1515166440Spjd 1516166440Spjd /* 1517192934Srmacklem * and the old V4 root dir. 1518192934Srmacklem */ 1519192934Srmacklem bzero(&eargs, sizeof (eargs)); 1520192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1521192934Srmacklem if (run_v4server > 0 && 1522192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1523192934Srmacklem errno != ENOENT) 1524192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1525192934Srmacklem 1526192934Srmacklem /* 1527192934Srmacklem * and clear flag that notes if a public fh has been exported. 1528192934Srmacklem */ 1529192934Srmacklem has_publicfh = 0; 1530192934Srmacklem 1531192934Srmacklem /* 1532166440Spjd * And delete exports that are in the kernel for all local 1533166440Spjd * filesystems. 1534166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1535166440Spjd */ 1536166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1537166440Spjd 1538166440Spjd if (num > 0) { 1539166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1540166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1541166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1542166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1543166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1544166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1545166440Spjd } 1546166440Spjd 1547166440Spjd for (i = 0; i < num; i++) { 1548166440Spjd fsp = &mntbufp[i]; 1549166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1550166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1551166440Spjd fsp->f_fstypename); 1552166440Spjd continue; 1553166440Spjd } 1554166440Spjd 1555166440Spjd /* 1556166440Spjd * Do not delete export for network filesystem by 1557166440Spjd * passing "export" arg to nmount(). 1558166440Spjd * It only makes sense to do this for local filesystems. 1559166440Spjd */ 1560166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1561166440Spjd continue; 1562166440Spjd 1563166440Spjd iov[1].iov_base = fsp->f_fstypename; 1564166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1565166440Spjd iov[3].iov_base = fsp->f_mntonname; 1566166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1567166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1568166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1569166440Spjd 1570166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1571166440Spjd errno != ENOENT && errno != ENOTSUP) { 1572166440Spjd syslog(LOG_ERR, 1573166440Spjd "can't delete exports for %s: %m %s", 1574166440Spjd fsp->f_mntonname, errmsg); 1575166440Spjd } 1576166440Spjd } 1577166440Spjd 1578166440Spjd if (iov != NULL) { 1579166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1580166440Spjd free(iov[0].iov_base); /* fstype */ 1581166440Spjd free(iov[2].iov_base); /* fspath */ 1582166440Spjd free(iov[4].iov_base); /* from */ 1583166440Spjd free(iov[6].iov_base); /* update */ 1584166440Spjd free(iov[8].iov_base); /* export */ 1585166440Spjd free(iov[10].iov_base); /* errmsg */ 1586166440Spjd 1587166440Spjd /* free iov, allocated by realloc() */ 1588166440Spjd free(iov); 1589166440Spjd iovlen = 0; 1590166440Spjd } 1591166440Spjd 1592166440Spjd /* 1593166440Spjd * Read in the exports file and build the list, calling 1594166440Spjd * nmount() as we go along to push the export rules into the kernel. 1595166440Spjd */ 1596168684Spjd done = 0; 1597166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1598166440Spjd if (debug) 1599166440Spjd warnx("reading exports from %s", exnames[i]); 1600166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1601168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1602168684Spjd continue; 1603166440Spjd } 1604166440Spjd get_exportlist_one(); 1605166440Spjd fclose(exp_file); 1606168684Spjd done++; 1607166440Spjd } 1608168684Spjd if (done == 0) { 1609168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1610168684Spjd exit(2); 1611168684Spjd } 1612192934Srmacklem 1613192934Srmacklem /* 1614192934Srmacklem * If there was no public fh, clear any previous one set. 1615192934Srmacklem */ 1616192934Srmacklem if (run_v4server > 0 && has_publicfh == 0) 1617192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1618166440Spjd} 1619166440Spjd 1620166440Spjd/* 16211558Srgrimes * Allocate an export list element 16221558Srgrimes */ 16231558Srgrimesstruct exportlist * 16241558Srgrimesget_exp() 16251558Srgrimes{ 16261558Srgrimes struct exportlist *ep; 16271558Srgrimes 16281558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 16291558Srgrimes if (ep == (struct exportlist *)NULL) 16301558Srgrimes out_of_mem(); 163123681Speter memset(ep, 0, sizeof(struct exportlist)); 16321558Srgrimes return (ep); 16331558Srgrimes} 16341558Srgrimes 16351558Srgrimes/* 16361558Srgrimes * Allocate a group list element 16371558Srgrimes */ 16381558Srgrimesstruct grouplist * 16391558Srgrimesget_grp() 16401558Srgrimes{ 16411558Srgrimes struct grouplist *gp; 16421558Srgrimes 16431558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 16441558Srgrimes if (gp == (struct grouplist *)NULL) 16451558Srgrimes out_of_mem(); 164623681Speter memset(gp, 0, sizeof(struct grouplist)); 16471558Srgrimes return (gp); 16481558Srgrimes} 16491558Srgrimes 16501558Srgrimes/* 16511558Srgrimes * Clean up upon an error in get_exportlist(). 16521558Srgrimes */ 16531558Srgrimesvoid 16541558Srgrimesgetexp_err(ep, grp) 16551558Srgrimes struct exportlist *ep; 16561558Srgrimes struct grouplist *grp; 16571558Srgrimes{ 16581558Srgrimes struct grouplist *tgrp; 16591558Srgrimes 1660100336Sjoerg if (!(opt_flags & OP_QUIET)) 1661100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 16621558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 16631558Srgrimes free_exp(ep); 16641558Srgrimes while (grp) { 16651558Srgrimes tgrp = grp; 16661558Srgrimes grp = grp->gr_next; 16671558Srgrimes free_grp(tgrp); 16681558Srgrimes } 16691558Srgrimes} 16701558Srgrimes 16711558Srgrimes/* 16721558Srgrimes * Search the export list for a matching fs. 16731558Srgrimes */ 16741558Srgrimesstruct exportlist * 16751558Srgrimesex_search(fsid) 16761558Srgrimes fsid_t *fsid; 16771558Srgrimes{ 16781558Srgrimes struct exportlist *ep; 16791558Srgrimes 16801558Srgrimes ep = exphead; 16811558Srgrimes while (ep) { 16821558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 16831558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 16841558Srgrimes return (ep); 16851558Srgrimes ep = ep->ex_next; 16861558Srgrimes } 16871558Srgrimes return (ep); 16881558Srgrimes} 16891558Srgrimes 16901558Srgrimes/* 16911558Srgrimes * Add a directory path to the list. 16921558Srgrimes */ 16931558Srgrimeschar * 16941558Srgrimesadd_expdir(dpp, cp, len) 16951558Srgrimes struct dirlist **dpp; 16961558Srgrimes char *cp; 16971558Srgrimes int len; 16981558Srgrimes{ 16991558Srgrimes struct dirlist *dp; 17001558Srgrimes 17011558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 170237663Scharnier if (dp == (struct dirlist *)NULL) 170337663Scharnier out_of_mem(); 17041558Srgrimes dp->dp_left = *dpp; 17051558Srgrimes dp->dp_right = (struct dirlist *)NULL; 17061558Srgrimes dp->dp_flag = 0; 17071558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 17081558Srgrimes strcpy(dp->dp_dirp, cp); 17091558Srgrimes *dpp = dp; 17101558Srgrimes return (dp->dp_dirp); 17111558Srgrimes} 17121558Srgrimes 17131558Srgrimes/* 17141558Srgrimes * Hang the dir list element off the dirpath binary tree as required 17151558Srgrimes * and update the entry for host. 17161558Srgrimes */ 17171558Srgrimesvoid 17189336Sdfrhang_dirp(dp, grp, ep, flags) 17191558Srgrimes struct dirlist *dp; 17201558Srgrimes struct grouplist *grp; 17211558Srgrimes struct exportlist *ep; 17229336Sdfr int flags; 17231558Srgrimes{ 17241558Srgrimes struct hostlist *hp; 17251558Srgrimes struct dirlist *dp2; 17261558Srgrimes 17279336Sdfr if (flags & OP_ALLDIRS) { 17281558Srgrimes if (ep->ex_defdir) 17291558Srgrimes free((caddr_t)dp); 17301558Srgrimes else 17311558Srgrimes ep->ex_defdir = dp; 17329336Sdfr if (grp == (struct grouplist *)NULL) { 17331558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 17349336Sdfr } else while (grp) { 17351558Srgrimes hp = get_ht(); 17361558Srgrimes hp->ht_grp = grp; 17371558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 17381558Srgrimes ep->ex_defdir->dp_hosts = hp; 17391558Srgrimes grp = grp->gr_next; 17401558Srgrimes } 17411558Srgrimes } else { 17421558Srgrimes 17431558Srgrimes /* 174437663Scharnier * Loop through the directories adding them to the tree. 17451558Srgrimes */ 17461558Srgrimes while (dp) { 17471558Srgrimes dp2 = dp->dp_left; 17489336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 17491558Srgrimes dp = dp2; 17501558Srgrimes } 17511558Srgrimes } 17521558Srgrimes} 17531558Srgrimes 17541558Srgrimes/* 17551558Srgrimes * Traverse the binary tree either updating a node that is already there 17561558Srgrimes * for the new directory or adding the new node. 17571558Srgrimes */ 17581558Srgrimesvoid 17599336Sdfradd_dlist(dpp, newdp, grp, flags) 17601558Srgrimes struct dirlist **dpp; 17611558Srgrimes struct dirlist *newdp; 17621558Srgrimes struct grouplist *grp; 17639336Sdfr int flags; 17641558Srgrimes{ 17651558Srgrimes struct dirlist *dp; 17661558Srgrimes struct hostlist *hp; 17671558Srgrimes int cmp; 17681558Srgrimes 17691558Srgrimes dp = *dpp; 17701558Srgrimes if (dp) { 17711558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 17721558Srgrimes if (cmp > 0) { 17739336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 17741558Srgrimes return; 17751558Srgrimes } else if (cmp < 0) { 17769336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 17771558Srgrimes return; 17781558Srgrimes } else 17791558Srgrimes free((caddr_t)newdp); 17801558Srgrimes } else { 17811558Srgrimes dp = newdp; 17821558Srgrimes dp->dp_left = (struct dirlist *)NULL; 17831558Srgrimes *dpp = dp; 17841558Srgrimes } 17851558Srgrimes if (grp) { 17861558Srgrimes 17871558Srgrimes /* 17881558Srgrimes * Hang all of the host(s) off of the directory point. 17891558Srgrimes */ 17901558Srgrimes do { 17911558Srgrimes hp = get_ht(); 17921558Srgrimes hp->ht_grp = grp; 17931558Srgrimes hp->ht_next = dp->dp_hosts; 17941558Srgrimes dp->dp_hosts = hp; 17951558Srgrimes grp = grp->gr_next; 17961558Srgrimes } while (grp); 17979336Sdfr } else { 17981558Srgrimes dp->dp_flag |= DP_DEFSET; 17999336Sdfr } 18001558Srgrimes} 18011558Srgrimes 18021558Srgrimes/* 18031558Srgrimes * Search for a dirpath on the export point. 18041558Srgrimes */ 18051558Srgrimesstruct dirlist * 180674462Salfreddirp_search(dp, dirp) 18071558Srgrimes struct dirlist *dp; 180874462Salfred char *dirp; 18091558Srgrimes{ 18101558Srgrimes int cmp; 18111558Srgrimes 18121558Srgrimes if (dp) { 181374462Salfred cmp = strcmp(dp->dp_dirp, dirp); 18141558Srgrimes if (cmp > 0) 181574462Salfred return (dirp_search(dp->dp_left, dirp)); 18161558Srgrimes else if (cmp < 0) 181774462Salfred return (dirp_search(dp->dp_right, dirp)); 18181558Srgrimes else 18191558Srgrimes return (dp); 18201558Srgrimes } 18211558Srgrimes return (dp); 18221558Srgrimes} 18231558Srgrimes 18241558Srgrimes/* 18251558Srgrimes * Scan for a host match in a directory tree. 18261558Srgrimes */ 18271558Srgrimesint 18289336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 18291558Srgrimes struct dirlist *dp; 183074462Salfred struct sockaddr *saddr; 18311558Srgrimes int *defsetp; 18329336Sdfr int *hostsetp; 18331558Srgrimes{ 18341558Srgrimes struct hostlist *hp; 18351558Srgrimes struct grouplist *grp; 183674462Salfred struct addrinfo *ai; 18371558Srgrimes 18381558Srgrimes if (dp) { 18391558Srgrimes if (dp->dp_flag & DP_DEFSET) 18409336Sdfr *defsetp = dp->dp_flag; 18411558Srgrimes hp = dp->dp_hosts; 18421558Srgrimes while (hp) { 18431558Srgrimes grp = hp->ht_grp; 18441558Srgrimes switch (grp->gr_type) { 18451558Srgrimes case GT_HOST: 184674462Salfred ai = grp->gr_ptr.gt_addrinfo; 184774462Salfred for (; ai; ai = ai->ai_next) { 184875801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 184974462Salfred *hostsetp = 185074462Salfred (hp->ht_flag | DP_HOSTSET); 185174462Salfred return (1); 185274462Salfred } 18539336Sdfr } 185475801Siedowse break; 18551558Srgrimes case GT_NET: 185675801Siedowse if (!sacmp(saddr, (struct sockaddr *) 185775801Siedowse &grp->gr_ptr.gt_net.nt_net, 185875801Siedowse (struct sockaddr *) 185975801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 186074462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 186174462Salfred return (1); 186274462Salfred } 186375801Siedowse break; 186475801Siedowse } 18651558Srgrimes hp = hp->ht_next; 18661558Srgrimes } 18671558Srgrimes } 18681558Srgrimes return (0); 18691558Srgrimes} 18701558Srgrimes 18711558Srgrimes/* 18721558Srgrimes * Scan tree for a host that matches the address. 18731558Srgrimes */ 18741558Srgrimesint 18751558Srgrimesscan_tree(dp, saddr) 18761558Srgrimes struct dirlist *dp; 187774462Salfred struct sockaddr *saddr; 18781558Srgrimes{ 18799336Sdfr int defset, hostset; 18801558Srgrimes 18811558Srgrimes if (dp) { 18821558Srgrimes if (scan_tree(dp->dp_left, saddr)) 18831558Srgrimes return (1); 18849336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 18851558Srgrimes return (1); 18861558Srgrimes if (scan_tree(dp->dp_right, saddr)) 18871558Srgrimes return (1); 18881558Srgrimes } 18891558Srgrimes return (0); 18901558Srgrimes} 18911558Srgrimes 18921558Srgrimes/* 18931558Srgrimes * Traverse the dirlist tree and free it up. 18941558Srgrimes */ 18951558Srgrimesvoid 18961558Srgrimesfree_dir(dp) 18971558Srgrimes struct dirlist *dp; 18981558Srgrimes{ 18991558Srgrimes 19001558Srgrimes if (dp) { 19011558Srgrimes free_dir(dp->dp_left); 19021558Srgrimes free_dir(dp->dp_right); 19031558Srgrimes free_host(dp->dp_hosts); 19041558Srgrimes free((caddr_t)dp); 19051558Srgrimes } 19061558Srgrimes} 19071558Srgrimes 19081558Srgrimes/* 1909184588Sdfr * Parse a colon separated list of security flavors 1910184588Sdfr */ 1911184588Sdfrint 1912184588Sdfrparsesec(seclist, ep) 1913184588Sdfr char *seclist; 1914184588Sdfr struct exportlist *ep; 1915184588Sdfr{ 1916184588Sdfr char *cp, savedc; 1917184588Sdfr int flavor; 1918184588Sdfr 1919184588Sdfr ep->ex_numsecflavors = 0; 1920184588Sdfr for (;;) { 1921184588Sdfr cp = strchr(seclist, ':'); 1922184588Sdfr if (cp) { 1923184588Sdfr savedc = *cp; 1924184588Sdfr *cp = '\0'; 1925184588Sdfr } 1926184588Sdfr 1927184588Sdfr if (!strcmp(seclist, "sys")) 1928184588Sdfr flavor = AUTH_SYS; 1929184588Sdfr else if (!strcmp(seclist, "krb5")) 1930184588Sdfr flavor = RPCSEC_GSS_KRB5; 1931184588Sdfr else if (!strcmp(seclist, "krb5i")) 1932184588Sdfr flavor = RPCSEC_GSS_KRB5I; 1933184588Sdfr else if (!strcmp(seclist, "krb5p")) 1934184588Sdfr flavor = RPCSEC_GSS_KRB5P; 1935184588Sdfr else { 1936184588Sdfr if (cp) 1937184588Sdfr *cp = savedc; 1938184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1939184588Sdfr return (1); 1940184588Sdfr } 1941184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1942184588Sdfr if (cp) 1943184588Sdfr *cp = savedc; 1944184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1945184588Sdfr return (1); 1946184588Sdfr } 1947184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1948184588Sdfr ep->ex_numsecflavors++; 1949184588Sdfr if (cp) { 1950184588Sdfr *cp = savedc; 1951184588Sdfr seclist = cp + 1; 1952184588Sdfr } else { 1953184588Sdfr break; 1954184588Sdfr } 1955184588Sdfr } 1956184588Sdfr return (0); 1957184588Sdfr} 1958184588Sdfr 1959184588Sdfr/* 19601558Srgrimes * Parse the option string and update fields. 19611558Srgrimes * Option arguments may either be -<option>=<value> or 19621558Srgrimes * -<option> <value> 19631558Srgrimes */ 19641558Srgrimesint 19651558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 19661558Srgrimes char **cpp, **endcpp; 19671558Srgrimes struct exportlist *ep; 19681558Srgrimes struct grouplist *grp; 19691558Srgrimes int *has_hostp; 19701558Srgrimes int *exflagsp; 197172650Sgreen struct xucred *cr; 19721558Srgrimes{ 19731558Srgrimes char *cpoptarg, *cpoptend; 19741558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 19751558Srgrimes int allflag, usedarg; 19761558Srgrimes 197751968Salfred savedc2 = '\0'; 19781558Srgrimes cpopt = *cpp; 19791558Srgrimes cpopt++; 19801558Srgrimes cp = *endcpp; 19811558Srgrimes savedc = *cp; 19821558Srgrimes *cp = '\0'; 19831558Srgrimes while (cpopt && *cpopt) { 19841558Srgrimes allflag = 1; 19851558Srgrimes usedarg = -2; 198637663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 19871558Srgrimes *cpoptend++ = '\0'; 198837663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 19891558Srgrimes *cpoptarg++ = '\0'; 19901558Srgrimes } else { 199137663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 19921558Srgrimes *cpoptarg++ = '\0'; 19931558Srgrimes else { 19941558Srgrimes *cp = savedc; 19951558Srgrimes nextfield(&cp, &endcp); 19961558Srgrimes **endcpp = '\0'; 19971558Srgrimes if (endcp > cp && *cp != '-') { 19981558Srgrimes cpoptarg = cp; 19991558Srgrimes savedc2 = *endcp; 20001558Srgrimes *endcp = '\0'; 20011558Srgrimes usedarg = 0; 20021558Srgrimes } 20031558Srgrimes } 20041558Srgrimes } 20051558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 20061558Srgrimes *exflagsp |= MNT_EXRDONLY; 20071558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 20081558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 20091558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 20101558Srgrimes usedarg++; 20111558Srgrimes parsecred(cpoptarg, cr); 20121558Srgrimes if (allflag == 0) { 20131558Srgrimes *exflagsp |= MNT_EXPORTANON; 20141558Srgrimes opt_flags |= OP_MAPALL; 20151558Srgrimes } else 20161558Srgrimes opt_flags |= OP_MAPROOT; 20171558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 201875801Siedowse !strcmp(cpopt, "m"))) { 20191558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 202037663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 20211558Srgrimes return (1); 20221558Srgrimes } 20231558Srgrimes usedarg++; 20241558Srgrimes opt_flags |= OP_MASK; 20251558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 20261558Srgrimes !strcmp(cpopt, "n"))) { 202774462Salfred if (strchr(cpoptarg, '/') != NULL) { 202874462Salfred if (debug) 202974462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 203074462Salfred opt_flags |= OP_MASKLEN; 203174462Salfred } 20321558Srgrimes if (grp->gr_type != GT_NULL) { 203337663Scharnier syslog(LOG_ERR, "network/host conflict"); 20341558Srgrimes return (1); 20351558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 203637663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 20371558Srgrimes return (1); 20381558Srgrimes } 20391558Srgrimes grp->gr_type = GT_NET; 20401558Srgrimes *has_hostp = 1; 20411558Srgrimes usedarg++; 20421558Srgrimes opt_flags |= OP_NET; 20431558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 20441558Srgrimes opt_flags |= OP_ALLDIRS; 204527447Sdfr } else if (!strcmp(cpopt, "public")) { 204627447Sdfr *exflagsp |= MNT_EXPUBLIC; 204727447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 204827447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 204927447Sdfr opt_flags |= OP_MAPALL; 205027447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 205127447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2052100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2053100336Sjoerg opt_flags |= OP_QUIET; 2054184588Sdfr } else if (!strcmp(cpopt, "sec")) { 2055184588Sdfr if (parsesec(cpoptarg, ep)) 2056184588Sdfr return (1); 2057184588Sdfr opt_flags |= OP_SEC; 2058184588Sdfr usedarg++; 20591558Srgrimes } else { 206037663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 20611558Srgrimes return (1); 20621558Srgrimes } 20631558Srgrimes if (usedarg >= 0) { 20641558Srgrimes *endcp = savedc2; 20651558Srgrimes **endcpp = savedc; 20661558Srgrimes if (usedarg > 0) { 20671558Srgrimes *cpp = cp; 20681558Srgrimes *endcpp = endcp; 20691558Srgrimes } 20701558Srgrimes return (0); 20711558Srgrimes } 20721558Srgrimes cpopt = cpoptend; 20731558Srgrimes } 20741558Srgrimes **endcpp = savedc; 20751558Srgrimes return (0); 20761558Srgrimes} 20771558Srgrimes 20781558Srgrimes/* 20791558Srgrimes * Translate a character string to the corresponding list of network 20801558Srgrimes * addresses for a hostname. 20811558Srgrimes */ 20821558Srgrimesint 20837401Swpaulget_host(cp, grp, tgrp) 20841558Srgrimes char *cp; 20851558Srgrimes struct grouplist *grp; 20867401Swpaul struct grouplist *tgrp; 20871558Srgrimes{ 20887401Swpaul struct grouplist *checkgrp; 208975635Siedowse struct addrinfo *ai, *tai, hints; 209074462Salfred int ecode; 209174462Salfred char host[NI_MAXHOST]; 20921558Srgrimes 209374462Salfred if (grp->gr_type != GT_NULL) { 209474462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 20951558Srgrimes return (1); 20961558Srgrimes } 209774462Salfred memset(&hints, 0, sizeof hints); 209874462Salfred hints.ai_flags = AI_CANONNAME; 209974462Salfred hints.ai_protocol = IPPROTO_UDP; 210074462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 210174462Salfred if (ecode != 0) { 210275635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 210374462Salfred return 1; 210474462Salfred } 210574462Salfred grp->gr_ptr.gt_addrinfo = ai; 210674462Salfred while (ai != NULL) { 210774462Salfred if (ai->ai_canonname == NULL) { 210874462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2109146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 211074462Salfred strlcpy(host, "?", sizeof(host)); 211174462Salfred ai->ai_canonname = strdup(host); 211274462Salfred ai->ai_flags |= AI_CANONNAME; 211375641Siedowse } 211474462Salfred if (debug) 211575635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 211675635Siedowse /* 211775635Siedowse * Sanity check: make sure we don't already have an entry 211875635Siedowse * for this host in the grouplist. 211975635Siedowse */ 212075635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 212175635Siedowse checkgrp = checkgrp->gr_next) { 212275635Siedowse if (checkgrp->gr_type != GT_HOST) 212375635Siedowse continue; 212475635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 212575635Siedowse tai = tai->ai_next) { 212675801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 212775635Siedowse continue; 212875635Siedowse if (debug) 212975635Siedowse fprintf(stderr, 213075635Siedowse "ignoring duplicate host %s\n", 213175635Siedowse ai->ai_canonname); 213275635Siedowse grp->gr_type = GT_IGNORE; 213375635Siedowse return (0); 213475635Siedowse } 213575635Siedowse } 213674462Salfred ai = ai->ai_next; 21371558Srgrimes } 213875635Siedowse grp->gr_type = GT_HOST; 21391558Srgrimes return (0); 21401558Srgrimes} 21411558Srgrimes 21421558Srgrimes/* 21431558Srgrimes * Free up an exports list component 21441558Srgrimes */ 21451558Srgrimesvoid 21461558Srgrimesfree_exp(ep) 21471558Srgrimes struct exportlist *ep; 21481558Srgrimes{ 21491558Srgrimes 21501558Srgrimes if (ep->ex_defdir) { 21511558Srgrimes free_host(ep->ex_defdir->dp_hosts); 21521558Srgrimes free((caddr_t)ep->ex_defdir); 21531558Srgrimes } 21541558Srgrimes if (ep->ex_fsdir) 21551558Srgrimes free(ep->ex_fsdir); 215627447Sdfr if (ep->ex_indexfile) 215727447Sdfr free(ep->ex_indexfile); 21581558Srgrimes free_dir(ep->ex_dirl); 21591558Srgrimes free((caddr_t)ep); 21601558Srgrimes} 21611558Srgrimes 21621558Srgrimes/* 21631558Srgrimes * Free hosts. 21641558Srgrimes */ 21651558Srgrimesvoid 21661558Srgrimesfree_host(hp) 21671558Srgrimes struct hostlist *hp; 21681558Srgrimes{ 21691558Srgrimes struct hostlist *hp2; 21701558Srgrimes 21711558Srgrimes while (hp) { 21721558Srgrimes hp2 = hp; 21731558Srgrimes hp = hp->ht_next; 21741558Srgrimes free((caddr_t)hp2); 21751558Srgrimes } 21761558Srgrimes} 21771558Srgrimes 21781558Srgrimesstruct hostlist * 21791558Srgrimesget_ht() 21801558Srgrimes{ 21811558Srgrimes struct hostlist *hp; 21821558Srgrimes 21831558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 21841558Srgrimes if (hp == (struct hostlist *)NULL) 21851558Srgrimes out_of_mem(); 21861558Srgrimes hp->ht_next = (struct hostlist *)NULL; 21879336Sdfr hp->ht_flag = 0; 21881558Srgrimes return (hp); 21891558Srgrimes} 21901558Srgrimes 21911558Srgrimes/* 21921558Srgrimes * Out of memory, fatal 21931558Srgrimes */ 21941558Srgrimesvoid 21951558Srgrimesout_of_mem() 21961558Srgrimes{ 21971558Srgrimes 219837663Scharnier syslog(LOG_ERR, "out of memory"); 21991558Srgrimes exit(2); 22001558Srgrimes} 22011558Srgrimes 22021558Srgrimes/* 2203158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 22041558Srgrimes * the kernel. 22051558Srgrimes */ 22061558Srgrimesint 2207158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2208158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 22091558Srgrimes{ 221075841Siedowse struct statfs fsb1; 221174462Salfred struct addrinfo *ai; 2212192934Srmacklem struct export_args ea, *eap; 2213158857Srodrigc char errmsg[255]; 2214158857Srodrigc char *cp; 22151558Srgrimes int done; 2216158857Srodrigc char savedc; 2217158857Srodrigc struct iovec *iov; 2218184588Sdfr int i, iovlen; 2219158857Srodrigc int ret; 2220192934Srmacklem struct nfsex_args nfsea; 22211558Srgrimes 2222192934Srmacklem if (run_v4server > 0) 2223192934Srmacklem eap = &nfsea.export; 2224192934Srmacklem else 2225192934Srmacklem eap = &ea; 2226192934Srmacklem 2227158857Srodrigc cp = NULL; 2228158857Srodrigc savedc = '\0'; 2229158857Srodrigc iov = NULL; 2230158857Srodrigc iovlen = 0; 2231158857Srodrigc ret = 0; 223275801Siedowse 2233192934Srmacklem bzero(eap, sizeof (struct export_args)); 2234158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2235192934Srmacklem eap->ex_flags = exflags; 2236192934Srmacklem eap->ex_anon = *anoncrp; 2237192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 223875641Siedowse if (grp->gr_type == GT_HOST) 223974462Salfred ai = grp->gr_ptr.gt_addrinfo; 224075641Siedowse else 224175641Siedowse ai = NULL; 2242192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2243192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2244192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2245192934Srmacklem if (eap->ex_numsecflavors == 0) { 2246192934Srmacklem eap->ex_numsecflavors = 1; 2247192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2248184588Sdfr } 22491558Srgrimes done = FALSE; 2250158857Srodrigc 2251192934Srmacklem if (v4root_phase == 0) { 2252192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2253192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2254192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2255192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2256192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2257192934Srmacklem sizeof (struct export_args)); 2258192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2259192934Srmacklem } 2260158857Srodrigc 22611558Srgrimes while (!done) { 22621558Srgrimes switch (grp->gr_type) { 22631558Srgrimes case GT_HOST: 226475641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 226574462Salfred goto skip; 2266192934Srmacklem eap->ex_addr = ai->ai_addr; 2267192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2268192934Srmacklem eap->ex_masklen = 0; 22691558Srgrimes break; 22701558Srgrimes case GT_NET: 227175801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 227274462Salfred have_v6 == 0) 227374462Salfred goto skip; 2274192934Srmacklem eap->ex_addr = 227575801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2276192934Srmacklem eap->ex_addrlen = 2277158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2278192934Srmacklem eap->ex_mask = 227975801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2280192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 22811558Srgrimes break; 228275641Siedowse case GT_DEFAULT: 2283192934Srmacklem eap->ex_addr = NULL; 2284192934Srmacklem eap->ex_addrlen = 0; 2285192934Srmacklem eap->ex_mask = NULL; 2286192934Srmacklem eap->ex_masklen = 0; 228775641Siedowse break; 22887401Swpaul case GT_IGNORE: 2289158857Srodrigc ret = 0; 2290158857Srodrigc goto error_exit; 22917401Swpaul break; 22921558Srgrimes default: 229337663Scharnier syslog(LOG_ERR, "bad grouptype"); 22941558Srgrimes if (cp) 22951558Srgrimes *cp = savedc; 2296158857Srodrigc ret = 1; 2297158857Srodrigc goto error_exit; 22981558Srgrimes }; 22991558Srgrimes 23001558Srgrimes /* 2301192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 23021558Srgrimes */ 2303192934Srmacklem if (v4root_phase == 2) { 2304192934Srmacklem nfsea.fspec = v4root_dirpath; 2305192934Srmacklem if (run_v4server > 0 && 2306192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2307192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2308192934Srmacklem return (2); 2309158857Srodrigc } 2310192934Srmacklem } else { 2311192934Srmacklem /* 2312192934Srmacklem * XXX: 2313192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2314192934Srmacklem * instead of looping back up the dirp to the mount 2315192934Srmacklem * point?? 2316192934Srmacklem * Also, needs to know how to export all types of local 2317192934Srmacklem * exportable filesystems and not just "ufs". 2318192934Srmacklem */ 2319192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2320192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2321192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2322192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2323192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2324192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2325192934Srmacklem 2326192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2327192934Srmacklem if (cp) 2328192934Srmacklem *cp-- = savedc; 2329192934Srmacklem else 2330192934Srmacklem cp = dirp + dirplen - 1; 2331192934Srmacklem if (opt_flags & OP_QUIET) { 2332192934Srmacklem ret = 1; 2333192934Srmacklem goto error_exit; 2334192934Srmacklem } 2335192934Srmacklem if (errno == EPERM) { 2336192934Srmacklem if (debug) 2337192934Srmacklem warnx("can't change attributes for %s", 2338192934Srmacklem dirp); 2339192934Srmacklem syslog(LOG_ERR, 2340192934Srmacklem "can't change attributes for %s", 234175635Siedowse dirp); 2342192934Srmacklem ret = 1; 2343192934Srmacklem goto error_exit; 2344192934Srmacklem } 2345192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2346192934Srmacklem if (errno == EINVAL) 2347192934Srmacklem syslog(LOG_ERR, 2348100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2349192934Srmacklem dirp); 2350192934Srmacklem else 2351192934Srmacklem syslog(LOG_ERR, 2352192934Srmacklem "could not remount %s: %m", 2353192934Srmacklem dirp); 2354192934Srmacklem ret = 1; 2355192934Srmacklem goto error_exit; 2356192934Srmacklem } 2357192934Srmacklem /* back up over the last component */ 2358192934Srmacklem while (*cp == '/' && cp > dirp) 2359192934Srmacklem cp--; 2360192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2361192934Srmacklem cp--; 2362192934Srmacklem if (cp == dirp) { 2363192934Srmacklem if (debug) 2364192934Srmacklem warnx("mnt unsucc"); 2365192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2366192934Srmacklem dirp, errmsg); 2367192934Srmacklem ret = 1; 2368192934Srmacklem goto error_exit; 2369192934Srmacklem } 2370192934Srmacklem savedc = *cp; 2371192934Srmacklem *cp = '\0'; 2372192934Srmacklem /* 2373192934Srmacklem * Check that we're still on the same 2374192934Srmacklem * filesystem. 2375192934Srmacklem */ 2376192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2377192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2378192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2379192934Srmacklem *cp = savedc; 2380100336Sjoerg syslog(LOG_ERR, 2381192934Srmacklem "can't export %s %s", dirp, 2382192934Srmacklem errmsg); 2383192934Srmacklem ret = 1; 2384192934Srmacklem goto error_exit; 2385192934Srmacklem } 23861558Srgrimes } 23871558Srgrimes } 2388192934Srmacklem 2389192934Srmacklem /* 2390192934Srmacklem * For the experimental server: 2391192934Srmacklem * If this is the public directory, get the file handle 2392192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2393192934Srmacklem */ 2394192934Srmacklem if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2395192934Srmacklem fhandle_t fh; 2396192934Srmacklem char *public_name; 2397192934Srmacklem 2398192934Srmacklem if (eap->ex_indexfile != NULL) 2399192934Srmacklem public_name = eap->ex_indexfile; 2400192934Srmacklem else 2401192934Srmacklem public_name = dirp; 2402192934Srmacklem if (getfh(public_name, &fh) < 0) 2403192934Srmacklem syslog(LOG_ERR, 2404192934Srmacklem "Can't get public fh for %s", public_name); 2405192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2406192934Srmacklem syslog(LOG_ERR, 2407192934Srmacklem "Can't set public fh for %s", public_name); 2408192934Srmacklem else 2409192934Srmacklem has_publicfh = 1; 2410192934Srmacklem } 241174462Salfredskip: 241275641Siedowse if (ai != NULL) 241374462Salfred ai = ai->ai_next; 241475641Siedowse if (ai == NULL) 24151558Srgrimes done = TRUE; 24161558Srgrimes } 24171558Srgrimes if (cp) 24181558Srgrimes *cp = savedc; 2419158857Srodrigcerror_exit: 2420158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2421158857Srodrigc if (iov != NULL) { 2422158857Srodrigc free(iov[0].iov_base); /* fstype */ 2423158857Srodrigc free(iov[2].iov_base); /* fspath */ 2424158857Srodrigc free(iov[4].iov_base); /* from */ 2425158857Srodrigc free(iov[6].iov_base); /* update */ 2426158857Srodrigc free(iov[8].iov_base); /* export */ 2427158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2428158857Srodrigc 2429158857Srodrigc /* free iov, allocated by realloc() */ 2430158857Srodrigc free(iov); 2431158857Srodrigc } 2432158857Srodrigc return (ret); 24331558Srgrimes} 24341558Srgrimes 24351558Srgrimes/* 24361558Srgrimes * Translate a net address. 243775801Siedowse * 243875801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 24391558Srgrimes */ 24401558Srgrimesint 24411558Srgrimesget_net(cp, net, maskflg) 24421558Srgrimes char *cp; 24431558Srgrimes struct netmsk *net; 24441558Srgrimes int maskflg; 24451558Srgrimes{ 244675861Siedowse struct netent *np = NULL; 244774462Salfred char *name, *p, *prefp; 244875801Siedowse struct sockaddr_in sin; 244975861Siedowse struct sockaddr *sa = NULL; 245074462Salfred struct addrinfo hints, *ai = NULL; 245174462Salfred char netname[NI_MAXHOST]; 245274462Salfred long preflen; 24531558Srgrimes 245475635Siedowse p = prefp = NULL; 245574462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 245674462Salfred p = strchr(cp, '/'); 245774462Salfred *p = '\0'; 245874462Salfred prefp = p + 1; 245974462Salfred } 246074462Salfred 246175861Siedowse /* 246275861Siedowse * Check for a numeric address first. We wish to avoid 246375861Siedowse * possible DNS lookups in getnetbyname(). 246475861Siedowse */ 246575861Siedowse if (isxdigit(*cp) || *cp == ':') { 246674462Salfred memset(&hints, 0, sizeof hints); 246775801Siedowse /* Ensure the mask and the network have the same family. */ 246875801Siedowse if (maskflg && (opt_flags & OP_NET)) 246975801Siedowse hints.ai_family = net->nt_net.ss_family; 247075801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 247175801Siedowse hints.ai_family = net->nt_mask.ss_family; 247275801Siedowse else 247375801Siedowse hints.ai_family = AF_UNSPEC; 247474462Salfred hints.ai_flags = AI_NUMERICHOST; 247575861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 247675861Siedowse sa = ai->ai_addr; 247775861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 247874462Salfred /* 247975801Siedowse * The address in `cp' is really a network address, so 248075801Siedowse * use inet_network() to re-interpret this correctly. 248175801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 248274462Salfred */ 248375801Siedowse bzero(&sin, sizeof sin); 248474462Salfred sin.sin_family = AF_INET; 248574462Salfred sin.sin_len = sizeof sin; 248675801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 248774462Salfred if (debug) 248875801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 248975801Siedowse inet_ntoa(sin.sin_addr)); 249074462Salfred sa = (struct sockaddr *)&sin; 249175861Siedowse } 249275861Siedowse } 249375861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 249475861Siedowse bzero(&sin, sizeof sin); 249575861Siedowse sin.sin_family = AF_INET; 249675861Siedowse sin.sin_len = sizeof sin; 249775861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 249875861Siedowse sa = (struct sockaddr *)&sin; 249975861Siedowse } 250075861Siedowse if (sa == NULL) 250174462Salfred goto fail; 250225318Spst 250375801Siedowse if (maskflg) { 250475801Siedowse /* The specified sockaddr is a mask. */ 250575801Siedowse if (checkmask(sa) != 0) 250675801Siedowse goto fail; 250775801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 250875801Siedowse opt_flags |= OP_HAVEMASK; 250975801Siedowse } else { 251075801Siedowse /* The specified sockaddr is a network address. */ 251175801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 251274462Salfred 251375801Siedowse /* Get a network name for the export list. */ 251475801Siedowse if (np) { 251575801Siedowse name = np->n_name; 251675801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2517146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 251875801Siedowse name = netname; 251975801Siedowse } else { 252075801Siedowse goto fail; 252175801Siedowse } 252275801Siedowse if ((net->nt_name = strdup(name)) == NULL) 252375801Siedowse out_of_mem(); 252475801Siedowse 252575801Siedowse /* 252675801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 252775801Siedowse * from the class of an IPv4 address. 252875801Siedowse */ 252974462Salfred if (opt_flags & OP_MASKLEN) { 253074462Salfred preflen = strtol(prefp, NULL, 10); 253175801Siedowse if (preflen < 0L || preflen == LONG_MAX) 253274462Salfred goto fail; 253375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 253475801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 253575801Siedowse goto fail; 253675801Siedowse opt_flags |= OP_HAVEMASK; 253774462Salfred *p = '/'; 253875801Siedowse } else if (sa->sa_family == AF_INET && 253975801Siedowse (opt_flags & OP_MASK) == 0) { 254075801Siedowse in_addr_t addr; 254174462Salfred 254275801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 254375801Siedowse if (IN_CLASSA(addr)) 254475801Siedowse preflen = 8; 254575801Siedowse else if (IN_CLASSB(addr)) 254675801Siedowse preflen = 16; 254775801Siedowse else if (IN_CLASSC(addr)) 254875801Siedowse preflen = 24; 254975801Siedowse else if (IN_CLASSD(addr)) 255075801Siedowse preflen = 28; 255175801Siedowse else 255275801Siedowse preflen = 32; /* XXX */ 255375801Siedowse 255475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 255575801Siedowse makemask(&net->nt_mask, (int)preflen); 255675801Siedowse opt_flags |= OP_HAVEMASK; 255774462Salfred } 255874462Salfred } 255974462Salfred 256074462Salfred if (ai) 256174462Salfred freeaddrinfo(ai); 256274462Salfred return 0; 256374462Salfred 256474462Salfredfail: 256574462Salfred if (ai) 256674462Salfred freeaddrinfo(ai); 256774462Salfred return 1; 25681558Srgrimes} 25691558Srgrimes 25701558Srgrimes/* 25711558Srgrimes * Parse out the next white space separated field 25721558Srgrimes */ 25731558Srgrimesvoid 25741558Srgrimesnextfield(cp, endcp) 25751558Srgrimes char **cp; 25761558Srgrimes char **endcp; 25771558Srgrimes{ 25781558Srgrimes char *p; 25791558Srgrimes 25801558Srgrimes p = *cp; 25811558Srgrimes while (*p == ' ' || *p == '\t') 25821558Srgrimes p++; 25831558Srgrimes if (*p == '\n' || *p == '\0') 25841558Srgrimes *cp = *endcp = p; 25851558Srgrimes else { 25861558Srgrimes *cp = p++; 25871558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 25881558Srgrimes p++; 25891558Srgrimes *endcp = p; 25901558Srgrimes } 25911558Srgrimes} 25921558Srgrimes 25931558Srgrimes/* 25941558Srgrimes * Get an exports file line. Skip over blank lines and handle line 25951558Srgrimes * continuations. 25961558Srgrimes */ 25971558Srgrimesint 25981558Srgrimesget_line() 25991558Srgrimes{ 26001558Srgrimes char *p, *cp; 260196622Siedowse size_t len; 26021558Srgrimes int totlen, cont_line; 26031558Srgrimes 26041558Srgrimes /* 26051558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 26061558Srgrimes */ 26071558Srgrimes p = line; 26081558Srgrimes totlen = 0; 26091558Srgrimes do { 261096622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 26111558Srgrimes return (0); 26121558Srgrimes cp = p + len - 1; 26131558Srgrimes cont_line = 0; 26141558Srgrimes while (cp >= p && 26151558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 26161558Srgrimes if (*cp == '\\') 26171558Srgrimes cont_line = 1; 26181558Srgrimes cp--; 26191558Srgrimes len--; 26201558Srgrimes } 262179117Sdd if (cont_line) { 262279117Sdd *++cp = ' '; 262379117Sdd len++; 262479117Sdd } 262596622Siedowse if (linesize < len + totlen + 1) { 262696622Siedowse linesize = len + totlen + 1; 262796622Siedowse line = realloc(line, linesize); 262896622Siedowse if (line == NULL) 262996622Siedowse out_of_mem(); 26301558Srgrimes } 263196622Siedowse memcpy(line + totlen, p, len); 263296622Siedowse totlen += len; 263396622Siedowse line[totlen] = '\0'; 26341558Srgrimes } while (totlen == 0 || cont_line); 26351558Srgrimes return (1); 26361558Srgrimes} 26371558Srgrimes 26381558Srgrimes/* 26391558Srgrimes * Parse a description of a credential. 26401558Srgrimes */ 26411558Srgrimesvoid 26421558Srgrimesparsecred(namelist, cr) 26431558Srgrimes char *namelist; 264472650Sgreen struct xucred *cr; 26451558Srgrimes{ 26461558Srgrimes char *name; 26471558Srgrimes int cnt; 26481558Srgrimes char *names; 26491558Srgrimes struct passwd *pw; 26501558Srgrimes struct group *gr; 2651194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2652136051Sstefanf int ngroups; 26531558Srgrimes 265491354Sdd cr->cr_version = XUCRED_VERSION; 26551558Srgrimes /* 265637663Scharnier * Set up the unprivileged user. 26571558Srgrimes */ 26581558Srgrimes cr->cr_uid = -2; 26591558Srgrimes cr->cr_groups[0] = -2; 26601558Srgrimes cr->cr_ngroups = 1; 26611558Srgrimes /* 26621558Srgrimes * Get the user's password table entry. 26631558Srgrimes */ 26641558Srgrimes names = strsep(&namelist, " \t\n"); 26651558Srgrimes name = strsep(&names, ":"); 26661558Srgrimes if (isdigit(*name) || *name == '-') 26671558Srgrimes pw = getpwuid(atoi(name)); 26681558Srgrimes else 26691558Srgrimes pw = getpwnam(name); 26701558Srgrimes /* 26711558Srgrimes * Credentials specified as those of a user. 26721558Srgrimes */ 26731558Srgrimes if (names == NULL) { 26741558Srgrimes if (pw == NULL) { 267537663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 26761558Srgrimes return; 26771558Srgrimes } 26781558Srgrimes cr->cr_uid = pw->pw_uid; 2679194498Sbrooks ngroups = XU_NGROUPS + 1; 26801558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 268137663Scharnier syslog(LOG_ERR, "too many groups"); 26821558Srgrimes /* 2683136051Sstefanf * Compress out duplicate. 26841558Srgrimes */ 26851558Srgrimes cr->cr_ngroups = ngroups - 1; 26861558Srgrimes cr->cr_groups[0] = groups[0]; 26871558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 26881558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 26891558Srgrimes return; 26901558Srgrimes } 26911558Srgrimes /* 26921558Srgrimes * Explicit credential specified as a colon separated list: 26931558Srgrimes * uid:gid:gid:... 26941558Srgrimes */ 26951558Srgrimes if (pw != NULL) 26961558Srgrimes cr->cr_uid = pw->pw_uid; 26971558Srgrimes else if (isdigit(*name) || *name == '-') 26981558Srgrimes cr->cr_uid = atoi(name); 26991558Srgrimes else { 270037663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 27011558Srgrimes return; 27021558Srgrimes } 27031558Srgrimes cr->cr_ngroups = 0; 2704194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 27051558Srgrimes name = strsep(&names, ":"); 27061558Srgrimes if (isdigit(*name) || *name == '-') { 27071558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 27081558Srgrimes } else { 27091558Srgrimes if ((gr = getgrnam(name)) == NULL) { 271037663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 27111558Srgrimes continue; 27121558Srgrimes } 27131558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 27141558Srgrimes } 27151558Srgrimes } 2716194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 271737663Scharnier syslog(LOG_ERR, "too many groups"); 27181558Srgrimes} 27191558Srgrimes 2720194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 27211558Srgrimes/* 27221558Srgrimes * Routines that maintain the remote mounttab 27231558Srgrimes */ 27241558Srgrimesvoid 27251558Srgrimesget_mountlist() 27261558Srgrimes{ 27271558Srgrimes struct mountlist *mlp, **mlpp; 272823681Speter char *host, *dirp, *cp; 27291558Srgrimes char str[STRSIZ]; 27301558Srgrimes FILE *mlfile; 27311558Srgrimes 27321558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 273353117Sbillf if (errno == ENOENT) 273453117Sbillf return; 273553117Sbillf else { 273653117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 273753117Sbillf return; 273853117Sbillf } 27391558Srgrimes } 27401558Srgrimes mlpp = &mlhead; 27411558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 274223681Speter cp = str; 274323681Speter host = strsep(&cp, " \t\n"); 274423681Speter dirp = strsep(&cp, " \t\n"); 274523681Speter if (host == NULL || dirp == NULL) 27461558Srgrimes continue; 27471558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 274837663Scharnier if (mlp == (struct mountlist *)NULL) 274937663Scharnier out_of_mem(); 2750194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 2751194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2752194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2753194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 27541558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 27551558Srgrimes *mlpp = mlp; 27561558Srgrimes mlpp = &mlp->ml_next; 27571558Srgrimes } 27581558Srgrimes fclose(mlfile); 27591558Srgrimes} 27601558Srgrimes 276175635Siedowsevoid 276275635Siedowsedel_mlist(char *hostp, char *dirp) 27631558Srgrimes{ 27641558Srgrimes struct mountlist *mlp, **mlpp; 27651558Srgrimes struct mountlist *mlp2; 27661558Srgrimes FILE *mlfile; 27671558Srgrimes int fnd = 0; 27681558Srgrimes 27691558Srgrimes mlpp = &mlhead; 27701558Srgrimes mlp = mlhead; 27711558Srgrimes while (mlp) { 27721558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 27731558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 27741558Srgrimes fnd = 1; 27751558Srgrimes mlp2 = mlp; 27761558Srgrimes *mlpp = mlp = mlp->ml_next; 27771558Srgrimes free((caddr_t)mlp2); 27781558Srgrimes } else { 27791558Srgrimes mlpp = &mlp->ml_next; 27801558Srgrimes mlp = mlp->ml_next; 27811558Srgrimes } 27821558Srgrimes } 27831558Srgrimes if (fnd) { 27841558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 278537663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 27861558Srgrimes return; 27871558Srgrimes } 27881558Srgrimes mlp = mlhead; 27891558Srgrimes while (mlp) { 27901558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 27911558Srgrimes mlp = mlp->ml_next; 27921558Srgrimes } 27931558Srgrimes fclose(mlfile); 27941558Srgrimes } 27951558Srgrimes} 27961558Srgrimes 27971558Srgrimesvoid 27981558Srgrimesadd_mlist(hostp, dirp) 27991558Srgrimes char *hostp, *dirp; 28001558Srgrimes{ 28011558Srgrimes struct mountlist *mlp, **mlpp; 28021558Srgrimes FILE *mlfile; 28031558Srgrimes 28041558Srgrimes mlpp = &mlhead; 28051558Srgrimes mlp = mlhead; 28061558Srgrimes while (mlp) { 28071558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 28081558Srgrimes return; 28091558Srgrimes mlpp = &mlp->ml_next; 28101558Srgrimes mlp = mlp->ml_next; 28111558Srgrimes } 28121558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 281337663Scharnier if (mlp == (struct mountlist *)NULL) 281437663Scharnier out_of_mem(); 2815194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 2816194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2817194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2818194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 28191558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 28201558Srgrimes *mlpp = mlp; 28211558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 282237663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 28231558Srgrimes return; 28241558Srgrimes } 28251558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 28261558Srgrimes fclose(mlfile); 28271558Srgrimes} 28281558Srgrimes 28291558Srgrimes/* 28301558Srgrimes * Free up a group list. 28311558Srgrimes */ 28321558Srgrimesvoid 28331558Srgrimesfree_grp(grp) 28341558Srgrimes struct grouplist *grp; 28351558Srgrimes{ 28361558Srgrimes if (grp->gr_type == GT_HOST) { 283774462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 283874462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 28391558Srgrimes } else if (grp->gr_type == GT_NET) { 28401558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 28411558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 28421558Srgrimes } 28431558Srgrimes free((caddr_t)grp); 28441558Srgrimes} 28451558Srgrimes 28461558Srgrimes#ifdef DEBUG 28471558Srgrimesvoid 28481558SrgrimesSYSLOG(int pri, const char *fmt, ...) 28491558Srgrimes{ 28501558Srgrimes va_list ap; 28511558Srgrimes 28521558Srgrimes va_start(ap, fmt); 28531558Srgrimes vfprintf(stderr, fmt, ap); 28541558Srgrimes va_end(ap); 28551558Srgrimes} 28561558Srgrimes#endif /* DEBUG */ 28571558Srgrimes 28581558Srgrimes/* 28591558Srgrimes * Check options for consistency. 28601558Srgrimes */ 28611558Srgrimesint 28621558Srgrimescheck_options(dp) 28631558Srgrimes struct dirlist *dp; 28641558Srgrimes{ 28651558Srgrimes 2866192934Srmacklem if (v4root_phase == 0 && dp == NULL) 28671558Srgrimes return (1); 286883653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 286983653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 28701558Srgrimes return (1); 28711558Srgrimes } 28721558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 287375801Siedowse syslog(LOG_ERR, "-mask requires -network"); 287475801Siedowse return (1); 28751558Srgrimes } 287675801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 287775801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 287875801Siedowse return (1); 287975801Siedowse } 288075801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 288175801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 288275801Siedowse return (1); 288375801Siedowse } 28841558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 288545927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 28861558Srgrimes return (1); 28871558Srgrimes } 2888192934Srmacklem if (v4root_phase > 0 && 2889192934Srmacklem (opt_flags & 2890192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 2891192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 2892192934Srmacklem return (1); 2893192934Srmacklem } 28941558Srgrimes return (0); 28951558Srgrimes} 28961558Srgrimes 28971558Srgrimes/* 28981558Srgrimes * Check an absolute directory path for any symbolic links. Return true 28991558Srgrimes */ 29001558Srgrimesint 29011558Srgrimescheck_dirpath(dirp) 29021558Srgrimes char *dirp; 29031558Srgrimes{ 29041558Srgrimes char *cp; 29051558Srgrimes int ret = 1; 29061558Srgrimes struct stat sb; 29071558Srgrimes 29081558Srgrimes cp = dirp + 1; 29091558Srgrimes while (*cp && ret) { 29101558Srgrimes if (*cp == '/') { 29111558Srgrimes *cp = '\0'; 29129336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 29131558Srgrimes ret = 0; 29141558Srgrimes *cp = '/'; 29151558Srgrimes } 29161558Srgrimes cp++; 29171558Srgrimes } 29189336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 29191558Srgrimes ret = 0; 29201558Srgrimes return (ret); 29211558Srgrimes} 29229336Sdfr 292375801Siedowse/* 292475801Siedowse * Make a netmask according to the specified prefix length. The ss_family 292575801Siedowse * and other non-address fields must be initialised before calling this. 292675801Siedowse */ 292775801Siedowseint 292875801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 292974462Salfred{ 293075801Siedowse u_char *p; 293175801Siedowse int bits, i, len; 293274462Salfred 293375801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 293475801Siedowse return (-1); 2935103949Smike if (bitlen > len * CHAR_BIT) 293675801Siedowse return (-1); 293774462Salfred 293875801Siedowse for (i = 0; i < len; i++) { 2939103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 294075801Siedowse *p++ = (1 << bits) - 1; 294175801Siedowse bitlen -= bits; 294274462Salfred } 294375801Siedowse return 0; 294474462Salfred} 294574462Salfred 294675801Siedowse/* 294775801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 294875801Siedowse * is acceptable (i.e. of the form 1...10....0). 294975801Siedowse */ 295075801Siedowseint 295175801Siedowsecheckmask(struct sockaddr *sa) 295274462Salfred{ 295375801Siedowse u_char *mask; 295475801Siedowse int i, len; 295574462Salfred 295675801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 295775801Siedowse return (-1); 295875801Siedowse 295975801Siedowse for (i = 0; i < len; i++) 296075801Siedowse if (mask[i] != 0xff) 296175801Siedowse break; 296275801Siedowse if (i < len) { 296375801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 296475801Siedowse return (-1); 296575801Siedowse i++; 296674462Salfred } 296775801Siedowse for (; i < len; i++) 296875801Siedowse if (mask[i] != 0) 296975801Siedowse return (-1); 297075801Siedowse return (0); 297174462Salfred} 297274462Salfred 297375801Siedowse/* 297475801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 297575801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 297675801Siedowse * If samask is NULL, perform a full comparision. 297775801Siedowse */ 297875801Siedowseint 297975801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 298074462Salfred{ 298175801Siedowse unsigned char *p1, *p2, *mask; 298275801Siedowse int len, i; 298374462Salfred 298475801Siedowse if (sa1->sa_family != sa2->sa_family || 298575801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 298675801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 298775801Siedowse return (1); 298875801Siedowse 298975801Siedowse switch (sa1->sa_family) { 299074462Salfred case AF_INET6: 299175801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 299275801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 299375801Siedowse return (1); 299474462Salfred break; 299574462Salfred } 299674462Salfred 299775801Siedowse /* Simple binary comparison if no mask specified. */ 299875801Siedowse if (samask == NULL) 299975801Siedowse return (memcmp(p1, p2, len)); 300074462Salfred 300175801Siedowse /* Set up the mask, and do a mask-based comparison. */ 300275801Siedowse if (sa1->sa_family != samask->sa_family || 300375801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 300475801Siedowse return (1); 300574462Salfred 300675801Siedowse for (i = 0; i < len; i++) 300775801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 300875801Siedowse return (1); 300975801Siedowse return (0); 301074462Salfred} 301174462Salfred 301275801Siedowse/* 301375801Siedowse * Return a pointer to the part of the sockaddr that contains the 301475801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 301575801Siedowse * NULL if the address family is unknown. 301675801Siedowse */ 301775801Siedowsevoid * 301875801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 301975801Siedowse void *p; 302074462Salfred int len; 302174462Salfred 302275801Siedowse switch (sa->sa_family) { 302374462Salfred case AF_INET: 302475801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 302575801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 302674462Salfred break; 302774462Salfred case AF_INET6: 302875801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 302975801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 303074462Salfred break; 303174462Salfred default: 303275801Siedowse p = NULL; 303375801Siedowse len = 0; 303474462Salfred } 303574462Salfred 303675801Siedowse if (nbytes != NULL) 303775801Siedowse *nbytes = len; 303875801Siedowse return (p); 303974462Salfred} 304074462Salfred 304175754Siedowsevoid 304275754Siedowsehuphandler(int sig) 304375754Siedowse{ 304475754Siedowse got_sighup = 1; 304575754Siedowse} 304675754Siedowse 304774462Salfredvoid terminate(sig) 304874462Salfredint sig; 304974462Salfred{ 3050149433Spjd pidfile_remove(pfh); 3051194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3052194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 305374462Salfred exit (0); 305474462Salfred} 3055192934Srmacklem 3056