mountd.c revision 224003
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 224003 2011-07-14 07:35:28Z delphij $"); 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 161222623Srmacklem#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 162222623Srmacklem 1631558Srgrimes/* Global defs */ 16492882Simpchar *add_expdir(struct dirlist **, char *, int); 16592882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16692882Simp struct grouplist *, int); 16792882Simpvoid add_mlist(char *, char *); 16892882Simpint check_dirpath(char *); 16992882Simpint check_options(struct dirlist *); 17075801Siedowseint checkmask(struct sockaddr *sa); 17192882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 172222623Srmacklemstatic int create_service(struct netconfig *nconf); 173222623Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 174222623Srmacklemstatic void clearout_service(void); 17575635Siedowsevoid del_mlist(char *hostp, char *dirp); 17692882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 17792882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17892882Simp struct xucred *, char *, int, struct statfs *); 17992882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 18092882Simp int *, int *, struct xucred *); 18192882Simpstruct exportlist *ex_search(fsid_t *); 18292882Simpstruct exportlist *get_exp(void); 18392882Simpvoid free_dir(struct dirlist *); 18492882Simpvoid free_exp(struct exportlist *); 18592882Simpvoid free_grp(struct grouplist *); 18692882Simpvoid free_host(struct hostlist *); 18792882Simpvoid get_exportlist(void); 18892882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18992882Simpstruct hostlist *get_ht(void); 19092882Simpint get_line(void); 19192882Simpvoid get_mountlist(void); 19292882Simpint get_net(char *, struct netmsk *, int); 19392882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 19492882Simpstruct grouplist *get_grp(void); 19592882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 19692882Simp struct exportlist *, int); 19775754Siedowsevoid huphandler(int sig); 19875801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19992882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 20092882Simpvoid nextfield(char **, char **); 20192882Simpvoid out_of_mem(void); 20292882Simpvoid parsecred(char *, struct xucred *); 203216587Scharnierint parsesec(char *, struct exportlist *); 204100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 20575801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 20675801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20775801Siedowse struct sockaddr *samask); 20892882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20992882Simpstatic void usage(void); 21092882Simpint xdr_dir(XDR *, char *); 21192882Simpint xdr_explist(XDR *, caddr_t); 212100117Salfredint xdr_explist_brief(XDR *, caddr_t); 213216587Scharnierint xdr_explist_common(XDR *, caddr_t, int); 21492882Simpint xdr_fhs(XDR *, caddr_t); 21592882Simpint xdr_mlist(XDR *, caddr_t); 21692882Simpvoid terminate(int); 2171558Srgrimes 2181558Srgrimesstruct exportlist *exphead; 2191558Srgrimesstruct mountlist *mlhead; 2201558Srgrimesstruct grouplist *grphead; 221166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 222166440Spjdchar **exnames; 223172827Smatteochar **hosts = NULL; 22472650Sgreenstruct xucred def_anon = { 22591354Sdd XUCRED_VERSION, 22672650Sgreen (uid_t)-2, 2271558Srgrimes 1, 22872650Sgreen { (gid_t)-2 }, 22972650Sgreen NULL 2301558Srgrimes}; 23125087Sdfrint force_v2 = 0; 2329336Sdfrint resvport_only = 1; 233172827Smatteoint nhosts = 0; 2349336Sdfrint dir_only = 1; 235121767Speterint dolog = 0; 23675754Siedowseint got_sighup = 0; 237172827Smatteoint xcreated = 0; 23874462Salfred 239172827Smatteochar *svcport_str = NULL; 240222623Srmacklemstatic int mallocd_svcport = 0; 241222623Srmacklemstatic int *sock_fd; 242222623Srmacklemstatic int sock_fdcnt; 243222623Srmacklemstatic int sock_fdpos; 244172827Smatteo 2451558Srgrimesint opt_flags; 24674462Salfredstatic int have_v6 = 1; 24774462Salfred 248192934Srmacklemint v4root_phase = 0; 249192934Srmacklemchar v4root_dirpath[PATH_MAX + 1]; 250220980Srmacklemint run_v4server = 1; 251192934Srmacklemint has_publicfh = 0; 252192934Srmacklem 253149433Spjdstruct pidfh *pfh = NULL; 25475801Siedowse/* Bits for opt_flags above */ 2551558Srgrimes#define OP_MAPROOT 0x01 2561558Srgrimes#define OP_MAPALL 0x02 25783653Speter/* 0x4 free */ 2581558Srgrimes#define OP_MASK 0x08 2591558Srgrimes#define OP_NET 0x10 2601558Srgrimes#define OP_ALLDIRS 0x40 26175801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 262100336Sjoerg#define OP_QUIET 0x100 26374462Salfred#define OP_MASKLEN 0x200 264184588Sdfr#define OP_SEC 0x400 2651558Srgrimes 2661558Srgrimes#ifdef DEBUG 2671558Srgrimesint debug = 1; 26892882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2691558Srgrimes#define syslog SYSLOG 2701558Srgrimes#else 2711558Srgrimesint debug = 0; 2721558Srgrimes#endif 2731558Srgrimes 2741558Srgrimes/* 2751558Srgrimes * Mountd server for NFS mount protocol as described in: 2761558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2771558Srgrimes * The optional arguments are the exports file name 2781558Srgrimes * default: _PATH_EXPORTS 2791558Srgrimes * and "-n" to allow nonroot mount. 2801558Srgrimes */ 2811558Srgrimesint 282216587Scharniermain(int argc, char **argv) 2831558Srgrimes{ 28475754Siedowse fd_set readfds; 285172827Smatteo struct netconfig *nconf; 286172827Smatteo char *endptr, **hosts_bak; 287172827Smatteo void *nc_handle; 288149433Spjd pid_t otherpid; 289172827Smatteo in_port_t svcport; 290172827Smatteo int c, k, s; 291109363Smbr int maxrec = RPC_MAXDATASIZE; 292222623Srmacklem int attempt_cnt, port_len, port_pos, ret; 293222623Srmacklem char **port_list; 2941558Srgrimes 29574462Salfred /* Check that another mountd isn't already running. */ 296150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 297149433Spjd if (pfh == NULL) { 298149433Spjd if (errno == EEXIST) 299149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 300149433Spjd warn("cannot open or create pidfile"); 301149433Spjd } 30274462Salfred 30374462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 30474462Salfred if (s < 0) 30574462Salfred have_v6 = 0; 30674462Salfred else 30774462Salfred close(s); 3082999Swollman 309220980Srmacklem while ((c = getopt(argc, argv, "2deh:lnop:r")) != -1) 3101558Srgrimes switch (c) { 31125087Sdfr case '2': 31225087Sdfr force_v2 = 1; 31325087Sdfr break; 314192993Srmacklem case 'e': 315220980Srmacklem /* now a no-op, since this is the default */ 316192934Srmacklem break; 3179336Sdfr case 'n': 3189336Sdfr resvport_only = 0; 3199336Sdfr break; 3209336Sdfr case 'r': 3219336Sdfr dir_only = 0; 3229336Sdfr break; 3238688Sphk case 'd': 3248688Sphk debug = debug ? 0 : 1; 3258688Sphk break; 32631656Sguido case 'l': 327121767Speter dolog = 1; 32831656Sguido break; 329220980Srmacklem case 'o': 330220980Srmacklem run_v4server = 0; 331220980Srmacklem break; 332126572Sbms case 'p': 333126572Sbms endptr = NULL; 334126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 335126572Sbms if (endptr == NULL || *endptr != '\0' || 336126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 337126572Sbms usage(); 338172827Smatteo svcport_str = strdup(optarg); 339126572Sbms break; 340172827Smatteo case 'h': 341172827Smatteo ++nhosts; 342172827Smatteo hosts_bak = hosts; 343172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 344172827Smatteo if (hosts_bak == NULL) { 345172827Smatteo if (hosts != NULL) { 346172827Smatteo for (k = 0; k < nhosts; k++) 347172827Smatteo free(hosts[k]); 348172827Smatteo free(hosts); 349172827Smatteo out_of_mem(); 350172827Smatteo } 351172827Smatteo } 352172827Smatteo hosts = hosts_bak; 353172827Smatteo hosts[nhosts - 1] = strdup(optarg); 354172827Smatteo if (hosts[nhosts - 1] == NULL) { 355172827Smatteo for (k = 0; k < (nhosts - 1); k++) 356172827Smatteo free(hosts[k]); 357172827Smatteo free(hosts); 358172827Smatteo out_of_mem(); 359172827Smatteo } 360172827Smatteo break; 3611558Srgrimes default: 36237663Scharnier usage(); 3631558Srgrimes }; 364192934Srmacklem 365192934Srmacklem /* 366220980Srmacklem * Unless the "-o" option was specified, try and run "nfsd". 367220980Srmacklem * If "-o" was specified, try and run "nfsserver". 368192934Srmacklem */ 369192934Srmacklem if (run_v4server > 0) { 370192934Srmacklem if (modfind("nfsd") < 0) { 371192934Srmacklem /* Not present in kernel, try loading it */ 372192934Srmacklem if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 373192934Srmacklem errx(1, "NFS server is not available"); 374192934Srmacklem } 375192934Srmacklem } else if (modfind("nfsserver") < 0) { 376192934Srmacklem /* Not present in kernel, try loading it */ 377192934Srmacklem if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 378192934Srmacklem errx(1, "NFS server is not available"); 379192934Srmacklem } 380192934Srmacklem 3811558Srgrimes argc -= optind; 3821558Srgrimes argv += optind; 3831558Srgrimes grphead = (struct grouplist *)NULL; 3841558Srgrimes exphead = (struct exportlist *)NULL; 3851558Srgrimes mlhead = (struct mountlist *)NULL; 386166440Spjd if (argc > 0) 387166440Spjd exnames = argv; 388166440Spjd else 389166440Spjd exnames = exnames_default; 3901558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3911558Srgrimes if (debug) 39237663Scharnier warnx("getting export list"); 3931558Srgrimes get_exportlist(); 3941558Srgrimes if (debug) 39537663Scharnier warnx("getting mount list"); 3961558Srgrimes get_mountlist(); 3971558Srgrimes if (debug) 39837663Scharnier warnx("here we go"); 3991558Srgrimes if (debug == 0) { 4001558Srgrimes daemon(0, 0); 4011558Srgrimes signal(SIGINT, SIG_IGN); 4021558Srgrimes signal(SIGQUIT, SIG_IGN); 4031558Srgrimes } 40475754Siedowse signal(SIGHUP, huphandler); 40574462Salfred signal(SIGTERM, terminate); 406164394Srodrigc signal(SIGPIPE, SIG_IGN); 407149433Spjd 408149433Spjd pidfile_write(pfh); 409149433Spjd 410194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 411194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 412109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 413109363Smbr 41424759Sguido if (!resvport_only) { 41583687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 41683687Speter &resvport_only, sizeof(resvport_only)) != 0 && 41783687Speter errno != ENOENT) { 41824759Sguido syslog(LOG_ERR, "sysctl: %m"); 41924759Sguido exit(1); 42024759Sguido } 42124330Sguido } 422126572Sbms 423172827Smatteo /* 424172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 425172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 426172827Smatteo * list. 427172827Smatteo */ 428172827Smatteo if (nhosts == 0) { 429172827Smatteo hosts = malloc(sizeof(char**)); 430172827Smatteo if (hosts == NULL) 431172827Smatteo out_of_mem(); 432172827Smatteo hosts[0] = "*"; 433172827Smatteo nhosts = 1; 434172827Smatteo } else { 435172827Smatteo hosts_bak = hosts; 436172827Smatteo if (have_v6) { 437172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 438172827Smatteo sizeof(char *)); 439172827Smatteo if (hosts_bak == NULL) { 440172827Smatteo for (k = 0; k < nhosts; k++) 441172827Smatteo free(hosts[k]); 442172827Smatteo free(hosts); 443172827Smatteo out_of_mem(); 444172827Smatteo } else 445172827Smatteo hosts = hosts_bak; 446172827Smatteo nhosts += 2; 447172827Smatteo hosts[nhosts - 2] = "::1"; 448172827Smatteo } else { 449172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 450172827Smatteo if (hosts_bak == NULL) { 451172827Smatteo for (k = 0; k < nhosts; k++) 452172827Smatteo free(hosts[k]); 453172827Smatteo free(hosts); 454172827Smatteo out_of_mem(); 455172827Smatteo } else { 456172827Smatteo nhosts += 1; 457172827Smatteo hosts = hosts_bak; 458126572Sbms } 459172827Smatteo } 46074462Salfred 461172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 46274462Salfred } 46374462Salfred 464222623Srmacklem attempt_cnt = 1; 465222623Srmacklem sock_fdcnt = 0; 466222623Srmacklem sock_fd = NULL; 467222623Srmacklem port_list = NULL; 468222623Srmacklem port_len = 0; 469172827Smatteo nc_handle = setnetconfig(); 470172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 471172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 472172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 473172827Smatteo "inet6") == 0) { 474172827Smatteo /* DO NOTHING */ 475222623Srmacklem } else { 476222623Srmacklem ret = create_service(nconf); 477222623Srmacklem if (ret == 1) 478222623Srmacklem /* Ignore this call */ 479222623Srmacklem continue; 480222623Srmacklem if (ret < 0) { 481222623Srmacklem /* 482222623Srmacklem * Failed to bind port, so close off 483222623Srmacklem * all sockets created and try again 484222623Srmacklem * if the port# was dynamically 485222623Srmacklem * assigned via bind(2). 486222623Srmacklem */ 487222623Srmacklem clearout_service(); 488222623Srmacklem if (mallocd_svcport != 0 && 489222623Srmacklem attempt_cnt < GETPORT_MAXTRY) { 490222623Srmacklem free(svcport_str); 491222623Srmacklem svcport_str = NULL; 492222623Srmacklem mallocd_svcport = 0; 493222623Srmacklem } else { 494222623Srmacklem errno = EADDRINUSE; 495222623Srmacklem syslog(LOG_ERR, 496222623Srmacklem "bindresvport_sa: %m"); 497222623Srmacklem exit(1); 498222623Srmacklem } 499222623Srmacklem 500222623Srmacklem /* Start over at the first service. */ 501222623Srmacklem free(sock_fd); 502222623Srmacklem sock_fdcnt = 0; 503222623Srmacklem sock_fd = NULL; 504222623Srmacklem nc_handle = setnetconfig(); 505222623Srmacklem attempt_cnt++; 506222623Srmacklem } else if (mallocd_svcport != 0 && 507222623Srmacklem attempt_cnt == GETPORT_MAXTRY) { 508222623Srmacklem /* 509222623Srmacklem * For the last attempt, allow 510222623Srmacklem * different port #s for each nconf 511222623Srmacklem * by saving the svcport_str and 512222623Srmacklem * setting it back to NULL. 513222623Srmacklem */ 514222623Srmacklem port_list = realloc(port_list, 515222623Srmacklem (port_len + 1) * sizeof(char *)); 516222623Srmacklem if (port_list == NULL) 517222623Srmacklem out_of_mem(); 518222623Srmacklem port_list[port_len++] = svcport_str; 519222623Srmacklem svcport_str = NULL; 520222623Srmacklem mallocd_svcport = 0; 521222623Srmacklem } 522222623Srmacklem } 523222623Srmacklem } 524222623Srmacklem } 525222623Srmacklem 526222623Srmacklem /* 527222623Srmacklem * Successfully bound the ports, so call complete_service() to 528222623Srmacklem * do the rest of the setup on the service(s). 529222623Srmacklem */ 530222623Srmacklem sock_fdpos = 0; 531222623Srmacklem port_pos = 0; 532222623Srmacklem nc_handle = setnetconfig(); 533222623Srmacklem while ((nconf = getnetconfig(nc_handle))) { 534222623Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 535222623Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 536222623Srmacklem "inet6") == 0) { 537222623Srmacklem /* DO NOTHING */ 538222623Srmacklem } else if (port_list != NULL) { 539222623Srmacklem if (port_pos >= port_len) { 540222623Srmacklem syslog(LOG_ERR, "too many port#s"); 541222623Srmacklem exit(1); 542222623Srmacklem } 543222623Srmacklem complete_service(nconf, port_list[port_pos++]); 544172827Smatteo } else 545222623Srmacklem complete_service(nconf, svcport_str); 546172827Smatteo } 54774462Salfred } 548172827Smatteo endnetconfig(nc_handle); 549222623Srmacklem free(sock_fd); 550222623Srmacklem if (port_list != NULL) { 551222623Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 552222623Srmacklem free(port_list[port_pos]); 553222623Srmacklem free(port_list); 554222623Srmacklem } 55574462Salfred 55674462Salfred if (xcreated == 0) { 55774462Salfred syslog(LOG_ERR, "could not create any services"); 5581558Srgrimes exit(1); 5591558Srgrimes } 56075754Siedowse 56175754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 56275754Siedowse for (;;) { 56375754Siedowse if (got_sighup) { 56475754Siedowse get_exportlist(); 56575754Siedowse got_sighup = 0; 56675754Siedowse } 56775754Siedowse readfds = svc_fdset; 56875754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 56975754Siedowse case -1: 57075754Siedowse if (errno == EINTR) 57175754Siedowse continue; 57275754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 57375754Siedowse exit(1); 57475754Siedowse case 0: 57575754Siedowse continue; 57675754Siedowse default: 57775754Siedowse svc_getreqset(&readfds); 57875754Siedowse } 57975754Siedowse } 580172827Smatteo} 581172827Smatteo 582172827Smatteo/* 583172827Smatteo * This routine creates and binds sockets on the appropriate 584222623Srmacklem * addresses. It gets called one time for each transport. 585222623Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 586222623Srmacklem * bind failed with EADDRINUSE. 587222623Srmacklem * Any file descriptors that have been created are stored in sock_fd and 588222623Srmacklem * the total count of them is maintained in sock_fdcnt. 589172827Smatteo */ 590222623Srmacklemstatic int 591172827Smatteocreate_service(struct netconfig *nconf) 592172827Smatteo{ 593172827Smatteo struct addrinfo hints, *res = NULL; 594172827Smatteo struct sockaddr_in *sin; 595172827Smatteo struct sockaddr_in6 *sin6; 596172827Smatteo struct __rpc_sockinfo si; 597172827Smatteo int aicode; 598172827Smatteo int fd; 599172827Smatteo int nhostsbak; 600172827Smatteo int one = 1; 601172827Smatteo int r; 602172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 603222623Srmacklem int mallocd_res; 604172827Smatteo 605172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 606172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 607172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 608222623Srmacklem return (1); /* not my type */ 609172827Smatteo 610172827Smatteo /* 611172827Smatteo * XXX - using RPC library internal functions. 612172827Smatteo */ 613172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 614172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 615172827Smatteo nconf->nc_netid); 616222623Srmacklem return (1); 617172827Smatteo } 618172827Smatteo 619172827Smatteo /* Get mountd's address on this transport */ 620172827Smatteo memset(&hints, 0, sizeof hints); 621172827Smatteo hints.ai_flags = AI_PASSIVE; 622172827Smatteo hints.ai_family = si.si_af; 623172827Smatteo hints.ai_socktype = si.si_socktype; 624172827Smatteo hints.ai_protocol = si.si_proto; 625172827Smatteo 626172827Smatteo /* 627172827Smatteo * Bind to specific IPs if asked to 628172827Smatteo */ 629172827Smatteo nhostsbak = nhosts; 630172827Smatteo while (nhostsbak > 0) { 631172827Smatteo --nhostsbak; 632222623Srmacklem sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 633222623Srmacklem if (sock_fd == NULL) 634222623Srmacklem out_of_mem(); 635222623Srmacklem sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 636222623Srmacklem mallocd_res = 0; 637222623Srmacklem 638172827Smatteo /* 639172827Smatteo * XXX - using RPC library internal functions. 640172827Smatteo */ 641172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 642172827Smatteo int non_fatal = 0; 643172827Smatteo if (errno == EPROTONOSUPPORT && 644172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 645172827Smatteo non_fatal = 1; 646172827Smatteo 647172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 648172827Smatteo "cannot create socket for %s", nconf->nc_netid); 649222623Srmacklem if (non_fatal != 0) 650222623Srmacklem continue; 651222623Srmacklem exit(1); 652172827Smatteo } 653172827Smatteo 654172827Smatteo switch (hints.ai_family) { 655172827Smatteo case AF_INET: 656172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 657172827Smatteo host_addr) == 1) { 658222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 659172827Smatteo } else { 660172827Smatteo /* 661172827Smatteo * Skip if we have an AF_INET6 address. 662172827Smatteo */ 663172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 664172827Smatteo host_addr) == 1) { 665172827Smatteo close(fd); 666172827Smatteo continue; 667172827Smatteo } 668172827Smatteo } 669172827Smatteo break; 670172827Smatteo case AF_INET6: 671172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 672172827Smatteo host_addr) == 1) { 673222623Srmacklem hints.ai_flags |= AI_NUMERICHOST; 674172827Smatteo } else { 675172827Smatteo /* 676172827Smatteo * Skip if we have an AF_INET address. 677172827Smatteo */ 678172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 679172827Smatteo host_addr) == 1) { 680172827Smatteo close(fd); 681172827Smatteo continue; 682172827Smatteo } 683172827Smatteo } 684172827Smatteo 685172827Smatteo /* 686172827Smatteo * We're doing host-based access checks here, so don't 687172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 688172827Smatteo * disable it by default on NFS sockets too. 689172827Smatteo */ 690172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 691172827Smatteo sizeof one) < 0) { 692172827Smatteo syslog(LOG_ERR, 693172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 694172827Smatteo exit(1); 695172827Smatteo } 696172827Smatteo break; 697172827Smatteo default: 698172827Smatteo break; 699172827Smatteo } 700172827Smatteo 701172827Smatteo /* 702172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 703172827Smatteo */ 704172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 705172827Smatteo if (svcport_str == NULL) { 706172827Smatteo res = malloc(sizeof(struct addrinfo)); 707172827Smatteo if (res == NULL) 708172827Smatteo out_of_mem(); 709222623Srmacklem mallocd_res = 1; 710172827Smatteo res->ai_flags = hints.ai_flags; 711172827Smatteo res->ai_family = hints.ai_family; 712172827Smatteo res->ai_protocol = hints.ai_protocol; 713172827Smatteo switch (res->ai_family) { 714172827Smatteo case AF_INET: 715172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 716172827Smatteo if (sin == NULL) 717172827Smatteo out_of_mem(); 718172827Smatteo sin->sin_family = AF_INET; 719172827Smatteo sin->sin_port = htons(0); 720172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 721172827Smatteo res->ai_addr = (struct sockaddr*) sin; 722172827Smatteo res->ai_addrlen = (socklen_t) 723222623Srmacklem sizeof(struct sockaddr_in); 724172827Smatteo break; 725172827Smatteo case AF_INET6: 726172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 727173056Ssimon if (sin6 == NULL) 728172827Smatteo out_of_mem(); 729172827Smatteo sin6->sin6_family = AF_INET6; 730172827Smatteo sin6->sin6_port = htons(0); 731172827Smatteo sin6->sin6_addr = in6addr_any; 732172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 733172827Smatteo res->ai_addrlen = (socklen_t) 734222623Srmacklem sizeof(struct sockaddr_in6); 735222623Srmacklem break; 736172827Smatteo default: 737222623Srmacklem syslog(LOG_ERR, "bad addr fam %d", 738222623Srmacklem res->ai_family); 739222623Srmacklem exit(1); 740172827Smatteo } 741172827Smatteo } else { 742172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 743172827Smatteo &hints, &res)) != 0) { 744172827Smatteo syslog(LOG_ERR, 745172827Smatteo "cannot get local address for %s: %s", 746172827Smatteo nconf->nc_netid, 747172827Smatteo gai_strerror(aicode)); 748222623Srmacklem close(fd); 749172827Smatteo continue; 750172827Smatteo } 751172827Smatteo } 752172827Smatteo } else { 753172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 754172827Smatteo &hints, &res)) != 0) { 755172827Smatteo syslog(LOG_ERR, 756172827Smatteo "cannot get local address for %s: %s", 757172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 758222623Srmacklem close(fd); 759172827Smatteo continue; 760172827Smatteo } 761172827Smatteo } 762172827Smatteo 763222623Srmacklem /* Store the fd. */ 764222623Srmacklem sock_fd[sock_fdcnt - 1] = fd; 765222623Srmacklem 766222623Srmacklem /* Now, attempt the bind. */ 767172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 768172827Smatteo if (r != 0) { 769222623Srmacklem if (errno == EADDRINUSE && mallocd_svcport != 0) { 770222623Srmacklem if (mallocd_res != 0) { 771222623Srmacklem free(res->ai_addr); 772222623Srmacklem free(res); 773222623Srmacklem } else 774222623Srmacklem freeaddrinfo(res); 775222623Srmacklem return (-1); 776222623Srmacklem } 777172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 778172827Smatteo exit(1); 779172827Smatteo } 780172827Smatteo 781222623Srmacklem if (svcport_str == NULL) { 782222623Srmacklem svcport_str = malloc(NI_MAXSERV * sizeof(char)); 783222623Srmacklem if (svcport_str == NULL) 784222623Srmacklem out_of_mem(); 785222623Srmacklem mallocd_svcport = 1; 786222623Srmacklem 787222623Srmacklem if (getnameinfo(res->ai_addr, 788222623Srmacklem res->ai_addr->sa_len, NULL, NI_MAXHOST, 789222623Srmacklem svcport_str, NI_MAXSERV * sizeof(char), 790222623Srmacklem NI_NUMERICHOST | NI_NUMERICSERV)) 791222623Srmacklem errx(1, "Cannot get port number"); 792222623Srmacklem } 793222623Srmacklem if (mallocd_res != 0) { 794222623Srmacklem free(res->ai_addr); 795222623Srmacklem free(res); 796222623Srmacklem } else 797222623Srmacklem freeaddrinfo(res); 798222623Srmacklem res = NULL; 799222623Srmacklem } 800222623Srmacklem return (0); 801222623Srmacklem} 802222623Srmacklem 803222623Srmacklem/* 804222623Srmacklem * Called after all the create_service() calls have succeeded, to complete 805222623Srmacklem * the setup and registration. 806222623Srmacklem */ 807222623Srmacklemstatic void 808222623Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 809222623Srmacklem{ 810222623Srmacklem struct addrinfo hints, *res = NULL; 811222623Srmacklem struct __rpc_sockinfo si; 812222623Srmacklem struct netbuf servaddr; 813222623Srmacklem SVCXPRT *transp = NULL; 814222623Srmacklem int aicode, fd, nhostsbak; 815222623Srmacklem int registered = 0; 816222623Srmacklem 817222623Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 818222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 819222623Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 820222623Srmacklem return; /* not my type */ 821222623Srmacklem 822222623Srmacklem /* 823222623Srmacklem * XXX - using RPC library internal functions. 824222623Srmacklem */ 825222623Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 826222623Srmacklem syslog(LOG_ERR, "cannot get information for %s", 827222623Srmacklem nconf->nc_netid); 828222623Srmacklem return; 829222623Srmacklem } 830222623Srmacklem 831222623Srmacklem nhostsbak = nhosts; 832222623Srmacklem while (nhostsbak > 0) { 833222623Srmacklem --nhostsbak; 834222623Srmacklem if (sock_fdpos >= sock_fdcnt) { 835222623Srmacklem /* Should never happen. */ 836222623Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 837222623Srmacklem return; 838222623Srmacklem } 839222623Srmacklem fd = sock_fd[sock_fdpos++]; 840222623Srmacklem if (fd < 0) 841222623Srmacklem continue; 842222623Srmacklem 843172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 844172827Smatteo listen(fd, SOMAXCONN); 845172827Smatteo 846172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 847172827Smatteo transp = svc_dg_create(fd, 0, 0); 848172827Smatteo else 849172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 850172827Smatteo RPC_MAXDATASIZE); 851172827Smatteo 852172827Smatteo if (transp != (SVCXPRT *) NULL) { 853194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 854172827Smatteo NULL)) 855172827Smatteo syslog(LOG_ERR, 856194880Sdfr "can't register %s MOUNTVERS service", 857172827Smatteo nconf->nc_netid); 858172827Smatteo if (!force_v2) { 859194880Sdfr if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 860172827Smatteo mntsrv, NULL)) 861172827Smatteo syslog(LOG_ERR, 862194880Sdfr "can't register %s MOUNTVERS3 service", 863172827Smatteo nconf->nc_netid); 864172827Smatteo } 865172827Smatteo } else 866172827Smatteo syslog(LOG_WARNING, "can't create %s services", 867172827Smatteo nconf->nc_netid); 868172827Smatteo 869172827Smatteo if (registered == 0) { 870172827Smatteo registered = 1; 871172827Smatteo memset(&hints, 0, sizeof hints); 872172827Smatteo hints.ai_flags = AI_PASSIVE; 873172827Smatteo hints.ai_family = si.si_af; 874172827Smatteo hints.ai_socktype = si.si_socktype; 875172827Smatteo hints.ai_protocol = si.si_proto; 876172827Smatteo 877222623Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 878172827Smatteo &res)) != 0) { 879172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 880172827Smatteo gai_strerror(aicode)); 881172827Smatteo exit(1); 882172827Smatteo } 883172827Smatteo 884172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 885172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 886172827Smatteo servaddr.len = res->ai_addrlen; 887172827Smatteo 888194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 889194880Sdfr rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 890172827Smatteo 891172827Smatteo xcreated++; 892172827Smatteo freeaddrinfo(res); 893172827Smatteo } 894172827Smatteo } /* end while */ 8951558Srgrimes} 8961558Srgrimes 897222623Srmacklem/* 898222623Srmacklem * Clear out sockets after a failure to bind one of them, so that the 899222623Srmacklem * cycle of socket creation/binding can start anew. 900222623Srmacklem */ 90137663Scharnierstatic void 902222623Srmacklemclearout_service(void) 903222623Srmacklem{ 904222623Srmacklem int i; 905222623Srmacklem 906222623Srmacklem for (i = 0; i < sock_fdcnt; i++) { 907222623Srmacklem if (sock_fd[i] >= 0) { 908222623Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 909222623Srmacklem close(sock_fd[i]); 910222623Srmacklem } 911222623Srmacklem } 912222623Srmacklem} 913222623Srmacklem 914222623Srmacklemstatic void 915216587Scharnierusage(void) 91637663Scharnier{ 91737663Scharnier fprintf(stderr, 918192993Srmacklem "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 919172827Smatteo "[-h <bindip>] [export_file ...]\n"); 92037663Scharnier exit(1); 92137663Scharnier} 92237663Scharnier 9231558Srgrimes/* 9241558Srgrimes * The mount rpc service 9251558Srgrimes */ 9261558Srgrimesvoid 927216587Scharniermntsrv(struct svc_req *rqstp, SVCXPRT *transp) 9281558Srgrimes{ 9291558Srgrimes struct exportlist *ep; 9301558Srgrimes struct dirlist *dp; 9319336Sdfr struct fhreturn fhr; 9321558Srgrimes struct stat stb; 9331558Srgrimes struct statfs fsb; 93474462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 93574462Salfred int lookup_failed = 1; 93674462Salfred struct sockaddr *saddr; 9379336Sdfr u_short sport; 938194880Sdfr char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 93928911Sguido int bad = 0, defset, hostset; 9409336Sdfr sigset_t sighup_mask; 9411558Srgrimes 9429336Sdfr sigemptyset(&sighup_mask); 9439336Sdfr sigaddset(&sighup_mask, SIGHUP); 94474462Salfred saddr = svc_getrpccaller(transp)->buf; 94574462Salfred switch (saddr->sa_family) { 94674462Salfred case AF_INET6: 94775635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 94874462Salfred break; 94974462Salfred case AF_INET: 95075635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 95174462Salfred break; 95274462Salfred default: 95374462Salfred syslog(LOG_ERR, "request from unknown address family"); 95474462Salfred return; 95574462Salfred } 95674462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 95774462Salfred NULL, 0, 0); 95874462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 95974462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 9601558Srgrimes switch (rqstp->rq_proc) { 9611558Srgrimes case NULLPROC: 962121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 96337663Scharnier syslog(LOG_ERR, "can't send reply"); 9641558Srgrimes return; 965194880Sdfr case MOUNTPROC_MNT: 9669336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 96731656Sguido syslog(LOG_NOTICE, 96831656Sguido "mount request from %s from unprivileged port", 96974462Salfred numerichost); 9701558Srgrimes svcerr_weakauth(transp); 9711558Srgrimes return; 9721558Srgrimes } 973121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 97431656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 97574462Salfred numerichost); 9761558Srgrimes svcerr_decode(transp); 9771558Srgrimes return; 9781558Srgrimes } 9791558Srgrimes 9801558Srgrimes /* 9811558Srgrimes * Get the real pathname and make sure it is a directory 9829336Sdfr * or a regular file if the -r option was specified 9839336Sdfr * and it exists. 9841558Srgrimes */ 98551968Salfred if (realpath(rpcpath, dirpath) == NULL || 9861558Srgrimes stat(dirpath, &stb) < 0 || 9879336Sdfr (!S_ISDIR(stb.st_mode) && 98874462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 9891558Srgrimes statfs(dirpath, &fsb) < 0) { 9901558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 99131656Sguido syslog(LOG_NOTICE, 99237663Scharnier "mount request from %s for non existent path %s", 99374462Salfred numerichost, dirpath); 9941558Srgrimes if (debug) 99537663Scharnier warnx("stat failed on %s", dirpath); 99628911Sguido bad = ENOENT; /* We will send error reply later */ 9971558Srgrimes } 9981558Srgrimes 9991558Srgrimes /* Check in the exports list */ 10009336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10011558Srgrimes ep = ex_search(&fsb.f_fsid); 10029336Sdfr hostset = defset = 0; 10039336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 10041558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 100574462Salfred chk_host(dp, saddr, &defset, &hostset)) || 100674462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 100774462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 100828911Sguido if (bad) { 1009121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 101028911Sguido (caddr_t)&bad)) 101137663Scharnier syslog(LOG_ERR, "can't send reply"); 101228911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 101328911Sguido return; 101428911Sguido } 10159336Sdfr if (hostset & DP_HOSTSET) 10169336Sdfr fhr.fhr_flag = hostset; 10179336Sdfr else 10189336Sdfr fhr.fhr_flag = defset; 10199336Sdfr fhr.fhr_vers = rqstp->rq_vers; 10201558Srgrimes /* Get the file handle */ 102123681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 10229336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 10231558Srgrimes bad = errno; 102437663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 1025121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 10261558Srgrimes (caddr_t)&bad)) 102737663Scharnier syslog(LOG_ERR, "can't send reply"); 10289336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10291558Srgrimes return; 10301558Srgrimes } 1031184588Sdfr fhr.fhr_numsecflavors = ep->ex_numsecflavors; 1032184588Sdfr fhr.fhr_secflavors = ep->ex_secflavors; 1033121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 1034121556Speter (caddr_t)&fhr)) 103537663Scharnier syslog(LOG_ERR, "can't send reply"); 103674462Salfred if (!lookup_failed) 103774462Salfred add_mlist(host, dirpath); 10381558Srgrimes else 103974462Salfred add_mlist(numerichost, dirpath); 10401558Srgrimes if (debug) 104137663Scharnier warnx("mount successful"); 1042121767Speter if (dolog) 104331656Sguido syslog(LOG_NOTICE, 104431656Sguido "mount request succeeded from %s for %s", 104574462Salfred numerichost, dirpath); 104631656Sguido } else { 10471558Srgrimes bad = EACCES; 104831656Sguido syslog(LOG_NOTICE, 104931656Sguido "mount request denied from %s for %s", 105074462Salfred numerichost, dirpath); 105131656Sguido } 105228911Sguido 1053121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 1054121556Speter (caddr_t)&bad)) 105537663Scharnier syslog(LOG_ERR, "can't send reply"); 10569336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10571558Srgrimes return; 1058194880Sdfr case MOUNTPROC_DUMP: 1059121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 106037663Scharnier syslog(LOG_ERR, "can't send reply"); 1061121767Speter else if (dolog) 106231656Sguido syslog(LOG_NOTICE, 106331656Sguido "dump request succeeded from %s", 106474462Salfred numerichost); 10651558Srgrimes return; 1066194880Sdfr case MOUNTPROC_UMNT: 10679336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 106831656Sguido syslog(LOG_NOTICE, 106931656Sguido "umount request from %s from unprivileged port", 107074462Salfred numerichost); 10711558Srgrimes svcerr_weakauth(transp); 10721558Srgrimes return; 10731558Srgrimes } 1074121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 107531656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 107674462Salfred numerichost); 10771558Srgrimes svcerr_decode(transp); 10781558Srgrimes return; 10791558Srgrimes } 108051968Salfred if (realpath(rpcpath, dirpath) == NULL) { 108151968Salfred syslog(LOG_NOTICE, "umount request from %s " 108251968Salfred "for non existent path %s", 108374462Salfred numerichost, dirpath); 108451968Salfred } 1085121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 108637663Scharnier syslog(LOG_ERR, "can't send reply"); 108774462Salfred if (!lookup_failed) 108875635Siedowse del_mlist(host, dirpath); 108975635Siedowse del_mlist(numerichost, dirpath); 1090121767Speter if (dolog) 109131656Sguido syslog(LOG_NOTICE, 109231656Sguido "umount request succeeded from %s for %s", 109374462Salfred numerichost, dirpath); 10941558Srgrimes return; 1095194880Sdfr case MOUNTPROC_UMNTALL: 10969336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 109731656Sguido syslog(LOG_NOTICE, 109831656Sguido "umountall request from %s from unprivileged port", 109974462Salfred numerichost); 11001558Srgrimes svcerr_weakauth(transp); 11011558Srgrimes return; 11021558Srgrimes } 1103121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 110437663Scharnier syslog(LOG_ERR, "can't send reply"); 110574462Salfred if (!lookup_failed) 110675635Siedowse del_mlist(host, NULL); 110775635Siedowse del_mlist(numerichost, NULL); 1108121767Speter if (dolog) 110931656Sguido syslog(LOG_NOTICE, 111031656Sguido "umountall request succeeded from %s", 111174462Salfred numerichost); 11121558Srgrimes return; 1113194880Sdfr case MOUNTPROC_EXPORT: 1114121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 1115121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 1116121556Speter (caddr_t)NULL)) 1117100117Salfred syslog(LOG_ERR, "can't send reply"); 1118121767Speter if (dolog) 111931656Sguido syslog(LOG_NOTICE, 112031656Sguido "export request succeeded from %s", 112174462Salfred numerichost); 11221558Srgrimes return; 11231558Srgrimes default: 11241558Srgrimes svcerr_noproc(transp); 11251558Srgrimes return; 11261558Srgrimes } 11271558Srgrimes} 11281558Srgrimes 11291558Srgrimes/* 11301558Srgrimes * Xdr conversion for a dirpath string 11311558Srgrimes */ 11321558Srgrimesint 1133216587Scharnierxdr_dir(XDR *xdrsp, char *dirp) 11341558Srgrimes{ 1135194880Sdfr return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 11361558Srgrimes} 11371558Srgrimes 11381558Srgrimes/* 11399336Sdfr * Xdr routine to generate file handle reply 11401558Srgrimes */ 11411558Srgrimesint 1142216587Scharnierxdr_fhs(XDR *xdrsp, caddr_t cp) 11431558Srgrimes{ 114492806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 11459336Sdfr u_long ok = 0, len, auth; 1146184588Sdfr int i; 11471558Srgrimes 11481558Srgrimes if (!xdr_long(xdrsp, &ok)) 11491558Srgrimes return (0); 11509336Sdfr switch (fhrp->fhr_vers) { 11519336Sdfr case 1: 11529336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 11539336Sdfr case 3: 11549336Sdfr len = NFSX_V3FH; 11559336Sdfr if (!xdr_long(xdrsp, &len)) 11569336Sdfr return (0); 11579336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 11589336Sdfr return (0); 1159184588Sdfr if (fhrp->fhr_numsecflavors) { 1160184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 1161184588Sdfr return (0); 1162184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 1163184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 1164184588Sdfr return (0); 1165184588Sdfr return (1); 1166184588Sdfr } else { 1167184588Sdfr auth = AUTH_SYS; 1168184588Sdfr len = 1; 1169184588Sdfr if (!xdr_long(xdrsp, &len)) 1170184588Sdfr return (0); 1171184588Sdfr return (xdr_long(xdrsp, &auth)); 1172184588Sdfr } 11739336Sdfr }; 11749336Sdfr return (0); 11751558Srgrimes} 11761558Srgrimes 11771558Srgrimesint 1178216587Scharnierxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 11791558Srgrimes{ 11801558Srgrimes struct mountlist *mlp; 11811558Srgrimes int true = 1; 11821558Srgrimes int false = 0; 11831558Srgrimes char *strp; 11841558Srgrimes 11851558Srgrimes mlp = mlhead; 11861558Srgrimes while (mlp) { 11871558Srgrimes if (!xdr_bool(xdrsp, &true)) 11881558Srgrimes return (0); 11891558Srgrimes strp = &mlp->ml_host[0]; 1190194880Sdfr if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 11911558Srgrimes return (0); 11921558Srgrimes strp = &mlp->ml_dirp[0]; 1193194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 11941558Srgrimes return (0); 11951558Srgrimes mlp = mlp->ml_next; 11961558Srgrimes } 11971558Srgrimes if (!xdr_bool(xdrsp, &false)) 11981558Srgrimes return (0); 11991558Srgrimes return (1); 12001558Srgrimes} 12011558Srgrimes 12021558Srgrimes/* 12031558Srgrimes * Xdr conversion for export list 12041558Srgrimes */ 12051558Srgrimesint 1206216587Scharnierxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 12071558Srgrimes{ 12081558Srgrimes struct exportlist *ep; 12091558Srgrimes int false = 0; 12109336Sdfr int putdef; 12119336Sdfr sigset_t sighup_mask; 12121558Srgrimes 12139336Sdfr sigemptyset(&sighup_mask); 12149336Sdfr sigaddset(&sighup_mask, SIGHUP); 12159336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 12161558Srgrimes ep = exphead; 12171558Srgrimes while (ep) { 12181558Srgrimes putdef = 0; 1219100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1220100117Salfred &putdef, brief)) 12211558Srgrimes goto errout; 12221558Srgrimes if (ep->ex_defdir && putdef == 0 && 12231558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1224100117Salfred &putdef, brief)) 12251558Srgrimes goto errout; 12261558Srgrimes ep = ep->ex_next; 12271558Srgrimes } 12289336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12291558Srgrimes if (!xdr_bool(xdrsp, &false)) 12301558Srgrimes return (0); 12311558Srgrimes return (1); 12321558Srgrimeserrout: 12339336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 12341558Srgrimes return (0); 12351558Srgrimes} 12361558Srgrimes 12371558Srgrimes/* 12381558Srgrimes * Called from xdr_explist() to traverse the tree and export the 12391558Srgrimes * directory paths. 12401558Srgrimes */ 12411558Srgrimesint 1242216587Scharnierput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1243216587Scharnier int brief) 12441558Srgrimes{ 12451558Srgrimes struct grouplist *grp; 12461558Srgrimes struct hostlist *hp; 12471558Srgrimes int true = 1; 12481558Srgrimes int false = 0; 12491558Srgrimes int gotalldir = 0; 12501558Srgrimes char *strp; 12511558Srgrimes 12521558Srgrimes if (dp) { 1253100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 12541558Srgrimes return (1); 12551558Srgrimes if (!xdr_bool(xdrsp, &true)) 12561558Srgrimes return (1); 12571558Srgrimes strp = dp->dp_dirp; 1258194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 12591558Srgrimes return (1); 12601558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 12611558Srgrimes gotalldir = 1; 12621558Srgrimes *putdefp = 1; 12631558Srgrimes } 1264100117Salfred if (brief) { 1265100117Salfred if (!xdr_bool(xdrsp, &true)) 1266100117Salfred return (1); 1267100117Salfred strp = "(...)"; 1268194880Sdfr if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1269100117Salfred return (1); 1270100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 12711558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 12721558Srgrimes hp = dp->dp_hosts; 12731558Srgrimes while (hp) { 12741558Srgrimes grp = hp->ht_grp; 12751558Srgrimes if (grp->gr_type == GT_HOST) { 12761558Srgrimes if (!xdr_bool(xdrsp, &true)) 12771558Srgrimes return (1); 127874462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 12798871Srgrimes if (!xdr_string(xdrsp, &strp, 1280194880Sdfr MNTNAMLEN)) 12811558Srgrimes return (1); 12821558Srgrimes } else if (grp->gr_type == GT_NET) { 12831558Srgrimes if (!xdr_bool(xdrsp, &true)) 12841558Srgrimes return (1); 12851558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 12868871Srgrimes if (!xdr_string(xdrsp, &strp, 1287194880Sdfr MNTNAMLEN)) 12881558Srgrimes return (1); 12891558Srgrimes } 12901558Srgrimes hp = hp->ht_next; 12911558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 12921558Srgrimes hp = adp->dp_hosts; 12931558Srgrimes gotalldir = 0; 12941558Srgrimes } 12951558Srgrimes } 12961558Srgrimes } 12971558Srgrimes if (!xdr_bool(xdrsp, &false)) 12981558Srgrimes return (1); 1299100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 13001558Srgrimes return (1); 13011558Srgrimes } 13021558Srgrimes return (0); 13031558Srgrimes} 13041558Srgrimes 1305100117Salfredint 1306216587Scharnierxdr_explist(XDR *xdrsp, caddr_t cp) 1307100117Salfred{ 1308100117Salfred 1309100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1310100117Salfred} 1311100117Salfred 1312100117Salfredint 1313216587Scharnierxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1314100117Salfred{ 1315100117Salfred 1316100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1317100117Salfred} 1318100117Salfred 131996622Siedowsechar *line; 132096622Siedowseint linesize; 13211558SrgrimesFILE *exp_file; 13221558Srgrimes 13231558Srgrimes/* 1324166440Spjd * Get the export list from one, currently open file 13251558Srgrimes */ 1326166440Spjdstatic void 1327216587Scharnierget_exportlist_one(void) 13281558Srgrimes{ 13291558Srgrimes struct exportlist *ep, *ep2; 13301558Srgrimes struct grouplist *grp, *tgrp; 13311558Srgrimes struct exportlist **epp; 13321558Srgrimes struct dirlist *dirhead; 1333166440Spjd struct statfs fsb; 133472650Sgreen struct xucred anon; 13351558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1336166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 13371558Srgrimes 1338192934Srmacklem v4root_phase = 0; 13391558Srgrimes dirhead = (struct dirlist *)NULL; 13401558Srgrimes while (get_line()) { 13411558Srgrimes if (debug) 134237663Scharnier warnx("got line %s", line); 13431558Srgrimes cp = line; 13441558Srgrimes nextfield(&cp, &endcp); 13451558Srgrimes if (*cp == '#') 13461558Srgrimes goto nextline; 13471558Srgrimes 13481558Srgrimes /* 13491558Srgrimes * Set defaults. 13501558Srgrimes */ 13511558Srgrimes has_host = FALSE; 13521558Srgrimes anon = def_anon; 13531558Srgrimes exflags = MNT_EXPORTED; 13541558Srgrimes got_nondir = 0; 13551558Srgrimes opt_flags = 0; 13561558Srgrimes ep = (struct exportlist *)NULL; 1357192934Srmacklem dirp = NULL; 13581558Srgrimes 13591558Srgrimes /* 1360192934Srmacklem * Handle the V4 root dir. 1361192934Srmacklem */ 1362192934Srmacklem if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1363192934Srmacklem /* 1364192934Srmacklem * V4: just indicates that it is the v4 root point, 1365192934Srmacklem * so skip over that and set v4root_phase. 1366192934Srmacklem */ 1367192934Srmacklem if (v4root_phase > 0) { 1368192934Srmacklem syslog(LOG_ERR, "V4:duplicate line, ignored"); 1369192934Srmacklem goto nextline; 1370192934Srmacklem } 1371192934Srmacklem v4root_phase = 1; 1372192934Srmacklem cp += 3; 1373192934Srmacklem nextfield(&cp, &endcp); 1374192934Srmacklem } 1375192934Srmacklem 1376192934Srmacklem /* 13771558Srgrimes * Create new exports list entry 13781558Srgrimes */ 13791558Srgrimes len = endcp-cp; 13801558Srgrimes tgrp = grp = get_grp(); 13811558Srgrimes while (len > 0) { 1382194880Sdfr if (len > MNTNAMLEN) { 13831558Srgrimes getexp_err(ep, tgrp); 13841558Srgrimes goto nextline; 13851558Srgrimes } 13861558Srgrimes if (*cp == '-') { 13871558Srgrimes if (ep == (struct exportlist *)NULL) { 13881558Srgrimes getexp_err(ep, tgrp); 13891558Srgrimes goto nextline; 13901558Srgrimes } 13911558Srgrimes if (debug) 139237663Scharnier warnx("doing opt %s", cp); 13931558Srgrimes got_nondir = 1; 13941558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 13951558Srgrimes &exflags, &anon)) { 13961558Srgrimes getexp_err(ep, tgrp); 13971558Srgrimes goto nextline; 13981558Srgrimes } 13991558Srgrimes } else if (*cp == '/') { 14001558Srgrimes savedc = *endcp; 14011558Srgrimes *endcp = '\0'; 1402192934Srmacklem if (v4root_phase > 1) { 1403192934Srmacklem if (dirp != NULL) { 1404192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 1405192934Srmacklem getexp_err(ep, tgrp); 1406192934Srmacklem goto nextline; 1407192934Srmacklem } 1408192934Srmacklem } 14091558Srgrimes if (check_dirpath(cp) && 14101558Srgrimes statfs(cp, &fsb) >= 0) { 14111558Srgrimes if (got_nondir) { 141237663Scharnier syslog(LOG_ERR, "dirs must be first"); 14131558Srgrimes getexp_err(ep, tgrp); 14141558Srgrimes goto nextline; 14151558Srgrimes } 1416192934Srmacklem if (v4root_phase == 1) { 1417192934Srmacklem if (dirp != NULL) { 1418192934Srmacklem syslog(LOG_ERR, "Multiple V4 dirs"); 14191558Srgrimes getexp_err(ep, tgrp); 14201558Srgrimes goto nextline; 14211558Srgrimes } 1422192934Srmacklem if (strlen(v4root_dirpath) == 0) { 1423192934Srmacklem strlcpy(v4root_dirpath, cp, 1424192934Srmacklem sizeof (v4root_dirpath)); 1425192934Srmacklem } else if (strcmp(v4root_dirpath, cp) 1426192934Srmacklem != 0) { 1427192934Srmacklem syslog(LOG_ERR, 1428192934Srmacklem "different V4 dirpath %s", cp); 1429192934Srmacklem getexp_err(ep, tgrp); 1430192934Srmacklem goto nextline; 1431192934Srmacklem } 1432192934Srmacklem dirp = cp; 1433192934Srmacklem v4root_phase = 2; 1434192934Srmacklem got_nondir = 1; 1435192934Srmacklem ep = get_exp(); 14361558Srgrimes } else { 1437192934Srmacklem if (ep) { 1438192934Srmacklem if (ep->ex_fs.val[0] != 1439192934Srmacklem fsb.f_fsid.val[0] || 1440192934Srmacklem ep->ex_fs.val[1] != 1441192934Srmacklem fsb.f_fsid.val[1]) { 1442192934Srmacklem getexp_err(ep, tgrp); 1443192934Srmacklem goto nextline; 1444192934Srmacklem } 1445192934Srmacklem } else { 1446192934Srmacklem /* 1447192934Srmacklem * See if this directory is already 1448192934Srmacklem * in the list. 1449192934Srmacklem */ 1450192934Srmacklem ep = ex_search(&fsb.f_fsid); 1451192934Srmacklem if (ep == (struct exportlist *)NULL) { 1452192934Srmacklem ep = get_exp(); 1453192934Srmacklem ep->ex_fs = fsb.f_fsid; 1454192934Srmacklem ep->ex_fsdir = (char *)malloc 1455192934Srmacklem (strlen(fsb.f_mntonname) + 1); 1456192934Srmacklem if (ep->ex_fsdir) 1457192934Srmacklem strcpy(ep->ex_fsdir, 1458192934Srmacklem fsb.f_mntonname); 1459192934Srmacklem else 1460192934Srmacklem out_of_mem(); 1461192934Srmacklem if (debug) 1462192934Srmacklem warnx( 1463192934Srmacklem "making new ep fs=0x%x,0x%x", 1464192934Srmacklem fsb.f_fsid.val[0], 1465192934Srmacklem fsb.f_fsid.val[1]); 1466192934Srmacklem } else if (debug) 1467192934Srmacklem warnx("found ep fs=0x%x,0x%x", 1468192934Srmacklem fsb.f_fsid.val[0], 1469192934Srmacklem fsb.f_fsid.val[1]); 1470192934Srmacklem } 1471192934Srmacklem 14721558Srgrimes /* 1473192934Srmacklem * Add dirpath to export mount point. 14741558Srgrimes */ 1475192934Srmacklem dirp = add_expdir(&dirhead, cp, len); 1476192934Srmacklem dirplen = len; 14771558Srgrimes } 14781558Srgrimes } else { 14791558Srgrimes getexp_err(ep, tgrp); 14801558Srgrimes goto nextline; 14811558Srgrimes } 14821558Srgrimes *endcp = savedc; 14831558Srgrimes } else { 14841558Srgrimes savedc = *endcp; 14851558Srgrimes *endcp = '\0'; 14861558Srgrimes got_nondir = 1; 14871558Srgrimes if (ep == (struct exportlist *)NULL) { 14881558Srgrimes getexp_err(ep, tgrp); 14891558Srgrimes goto nextline; 14901558Srgrimes } 14911558Srgrimes 14921558Srgrimes /* 14931558Srgrimes * Get the host or netgroup. 14941558Srgrimes */ 14951558Srgrimes setnetgrent(cp); 14961558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 14971558Srgrimes do { 14981558Srgrimes if (has_host) { 14991558Srgrimes grp->gr_next = get_grp(); 15001558Srgrimes grp = grp->gr_next; 15011558Srgrimes } 15021558Srgrimes if (netgrp) { 150337003Sjoerg if (hst == 0) { 150437663Scharnier syslog(LOG_ERR, 150537663Scharnier "null hostname in netgroup %s, skipping", cp); 150637004Sjoerg grp->gr_type = GT_IGNORE; 150737003Sjoerg } else if (get_host(hst, grp, tgrp)) { 150837663Scharnier syslog(LOG_ERR, 150937663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 151029317Sjlemon grp->gr_type = GT_IGNORE; 15111558Srgrimes } 15127401Swpaul } else if (get_host(cp, grp, tgrp)) { 151337663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 151429317Sjlemon grp->gr_type = GT_IGNORE; 15151558Srgrimes } 15161558Srgrimes has_host = TRUE; 15171558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 15181558Srgrimes endnetgrent(); 15191558Srgrimes *endcp = savedc; 15201558Srgrimes } 15211558Srgrimes cp = endcp; 15221558Srgrimes nextfield(&cp, &endcp); 15231558Srgrimes len = endcp - cp; 15241558Srgrimes } 15251558Srgrimes if (check_options(dirhead)) { 15261558Srgrimes getexp_err(ep, tgrp); 15271558Srgrimes goto nextline; 15281558Srgrimes } 15291558Srgrimes if (!has_host) { 153075641Siedowse grp->gr_type = GT_DEFAULT; 15311558Srgrimes if (debug) 153237663Scharnier warnx("adding a default entry"); 15331558Srgrimes 15341558Srgrimes /* 15351558Srgrimes * Don't allow a network export coincide with a list of 15361558Srgrimes * host(s) on the same line. 15371558Srgrimes */ 15381558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 153975801Siedowse syslog(LOG_ERR, "network/host conflict"); 15401558Srgrimes getexp_err(ep, tgrp); 15411558Srgrimes goto nextline; 154229317Sjlemon 154374462Salfred /* 154474462Salfred * If an export list was specified on this line, make sure 154529317Sjlemon * that we have at least one valid entry, otherwise skip it. 154629317Sjlemon */ 154729317Sjlemon } else { 154829317Sjlemon grp = tgrp; 154974462Salfred while (grp && grp->gr_type == GT_IGNORE) 155029317Sjlemon grp = grp->gr_next; 155129317Sjlemon if (! grp) { 155229317Sjlemon getexp_err(ep, tgrp); 155329317Sjlemon goto nextline; 155429317Sjlemon } 15551558Srgrimes } 15561558Srgrimes 1557192934Srmacklem if (v4root_phase == 1) { 1558192934Srmacklem syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1559192934Srmacklem getexp_err(ep, tgrp); 1560192934Srmacklem goto nextline; 1561192934Srmacklem } 1562192934Srmacklem 15631558Srgrimes /* 15641558Srgrimes * Loop through hosts, pushing the exports into the kernel. 15651558Srgrimes * After loop, tgrp points to the start of the list and 15661558Srgrimes * grp points to the last entry in the list. 15671558Srgrimes */ 15681558Srgrimes grp = tgrp; 15691558Srgrimes do { 157075635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 157175635Siedowse &fsb)) { 157275635Siedowse getexp_err(ep, tgrp); 157375635Siedowse goto nextline; 157475635Siedowse } 15751558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 15761558Srgrimes 15771558Srgrimes /* 1578192934Srmacklem * For V4: don't enter in mount lists. 1579192934Srmacklem */ 1580194773Srmacklem if (v4root_phase > 0 && v4root_phase <= 2) { 1581194773Srmacklem /* 1582194773Srmacklem * Since these structures aren't used by mountd, 1583194773Srmacklem * free them up now. 1584194773Srmacklem */ 1585194773Srmacklem if (ep != NULL) 1586194773Srmacklem free_exp(ep); 1587194773Srmacklem while (tgrp != NULL) { 1588194773Srmacklem grp = tgrp; 1589194773Srmacklem tgrp = tgrp->gr_next; 1590194773Srmacklem free_grp(grp); 1591194773Srmacklem } 1592192934Srmacklem goto nextline; 1593194773Srmacklem } 1594192934Srmacklem 1595192934Srmacklem /* 15961558Srgrimes * Success. Update the data structures. 15971558Srgrimes */ 15981558Srgrimes if (has_host) { 15999336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 16001558Srgrimes grp->gr_next = grphead; 16011558Srgrimes grphead = tgrp; 16021558Srgrimes } else { 16031558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 16049336Sdfr opt_flags); 16051558Srgrimes free_grp(grp); 16061558Srgrimes } 16071558Srgrimes dirhead = (struct dirlist *)NULL; 16081558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 16091558Srgrimes ep2 = exphead; 16101558Srgrimes epp = &exphead; 16111558Srgrimes 16121558Srgrimes /* 16131558Srgrimes * Insert in the list in alphabetical order. 16141558Srgrimes */ 16151558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 16161558Srgrimes epp = &ep2->ex_next; 16171558Srgrimes ep2 = ep2->ex_next; 16181558Srgrimes } 16191558Srgrimes if (ep2) 16201558Srgrimes ep->ex_next = ep2; 16211558Srgrimes *epp = ep; 16221558Srgrimes ep->ex_flag |= EX_LINKED; 16231558Srgrimes } 16241558Srgrimesnextline: 1625192934Srmacklem v4root_phase = 0; 16261558Srgrimes if (dirhead) { 16271558Srgrimes free_dir(dirhead); 16281558Srgrimes dirhead = (struct dirlist *)NULL; 16291558Srgrimes } 16301558Srgrimes } 16311558Srgrimes} 16321558Srgrimes 16331558Srgrimes/* 1634166440Spjd * Get the export list from all specified files 1635166440Spjd */ 1636166440Spjdvoid 1637216587Scharnierget_exportlist(void) 1638166440Spjd{ 1639166440Spjd struct exportlist *ep, *ep2; 1640166440Spjd struct grouplist *grp, *tgrp; 1641166440Spjd struct export_args export; 1642166440Spjd struct iovec *iov; 1643166440Spjd struct statfs *fsp, *mntbufp; 1644166440Spjd struct xvfsconf vfc; 1645166440Spjd char *dirp; 1646166440Spjd char errmsg[255]; 1647166440Spjd int dirplen, num, i; 1648166440Spjd int iovlen; 1649168684Spjd int done; 1650192934Srmacklem struct nfsex_args eargs; 1651166440Spjd 1652192934Srmacklem v4root_dirpath[0] = '\0'; 1653166440Spjd bzero(&export, sizeof(export)); 1654166440Spjd export.ex_flags = MNT_DELEXPORT; 1655166440Spjd dirp = NULL; 1656166440Spjd dirplen = 0; 1657166440Spjd iov = NULL; 1658166440Spjd iovlen = 0; 1659166440Spjd bzero(errmsg, sizeof(errmsg)); 1660166440Spjd 1661166440Spjd /* 1662166440Spjd * First, get rid of the old list 1663166440Spjd */ 1664166440Spjd ep = exphead; 1665166440Spjd while (ep) { 1666166440Spjd ep2 = ep; 1667166440Spjd ep = ep->ex_next; 1668166440Spjd free_exp(ep2); 1669166440Spjd } 1670166440Spjd exphead = (struct exportlist *)NULL; 1671166440Spjd 1672166440Spjd grp = grphead; 1673166440Spjd while (grp) { 1674166440Spjd tgrp = grp; 1675166440Spjd grp = grp->gr_next; 1676166440Spjd free_grp(tgrp); 1677166440Spjd } 1678166440Spjd grphead = (struct grouplist *)NULL; 1679166440Spjd 1680166440Spjd /* 1681192934Srmacklem * and the old V4 root dir. 1682192934Srmacklem */ 1683192934Srmacklem bzero(&eargs, sizeof (eargs)); 1684192934Srmacklem eargs.export.ex_flags = MNT_DELEXPORT; 1685192934Srmacklem if (run_v4server > 0 && 1686192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1687192934Srmacklem errno != ENOENT) 1688192934Srmacklem syslog(LOG_ERR, "Can't delete exports for V4:"); 1689192934Srmacklem 1690192934Srmacklem /* 1691192934Srmacklem * and clear flag that notes if a public fh has been exported. 1692192934Srmacklem */ 1693192934Srmacklem has_publicfh = 0; 1694192934Srmacklem 1695192934Srmacklem /* 1696166440Spjd * And delete exports that are in the kernel for all local 1697166440Spjd * filesystems. 1698166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1699166440Spjd */ 1700166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1701166440Spjd 1702166440Spjd if (num > 0) { 1703166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1704166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1705166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1706166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1707166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1708166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1709166440Spjd } 1710166440Spjd 1711166440Spjd for (i = 0; i < num; i++) { 1712166440Spjd fsp = &mntbufp[i]; 1713166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1714166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1715166440Spjd fsp->f_fstypename); 1716166440Spjd continue; 1717166440Spjd } 1718166440Spjd 1719166440Spjd /* 1720166440Spjd * Do not delete export for network filesystem by 1721166440Spjd * passing "export" arg to nmount(). 1722166440Spjd * It only makes sense to do this for local filesystems. 1723166440Spjd */ 1724166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1725166440Spjd continue; 1726166440Spjd 1727166440Spjd iov[1].iov_base = fsp->f_fstypename; 1728166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1729166440Spjd iov[3].iov_base = fsp->f_mntonname; 1730166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1731166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1732166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1733166440Spjd 1734166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1735166440Spjd errno != ENOENT && errno != ENOTSUP) { 1736166440Spjd syslog(LOG_ERR, 1737166440Spjd "can't delete exports for %s: %m %s", 1738166440Spjd fsp->f_mntonname, errmsg); 1739166440Spjd } 1740166440Spjd } 1741166440Spjd 1742166440Spjd if (iov != NULL) { 1743166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1744166440Spjd free(iov[0].iov_base); /* fstype */ 1745166440Spjd free(iov[2].iov_base); /* fspath */ 1746166440Spjd free(iov[4].iov_base); /* from */ 1747166440Spjd free(iov[6].iov_base); /* update */ 1748166440Spjd free(iov[8].iov_base); /* export */ 1749166440Spjd free(iov[10].iov_base); /* errmsg */ 1750166440Spjd 1751166440Spjd /* free iov, allocated by realloc() */ 1752166440Spjd free(iov); 1753166440Spjd iovlen = 0; 1754166440Spjd } 1755166440Spjd 1756166440Spjd /* 1757166440Spjd * Read in the exports file and build the list, calling 1758166440Spjd * nmount() as we go along to push the export rules into the kernel. 1759166440Spjd */ 1760168684Spjd done = 0; 1761166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1762166440Spjd if (debug) 1763166440Spjd warnx("reading exports from %s", exnames[i]); 1764166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1765168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1766168684Spjd continue; 1767166440Spjd } 1768166440Spjd get_exportlist_one(); 1769166440Spjd fclose(exp_file); 1770168684Spjd done++; 1771166440Spjd } 1772168684Spjd if (done == 0) { 1773168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1774168684Spjd exit(2); 1775168684Spjd } 1776192934Srmacklem 1777192934Srmacklem /* 1778192934Srmacklem * If there was no public fh, clear any previous one set. 1779192934Srmacklem */ 1780192934Srmacklem if (run_v4server > 0 && has_publicfh == 0) 1781192934Srmacklem (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1782166440Spjd} 1783166440Spjd 1784166440Spjd/* 17851558Srgrimes * Allocate an export list element 17861558Srgrimes */ 17871558Srgrimesstruct exportlist * 1788216587Scharnierget_exp(void) 17891558Srgrimes{ 17901558Srgrimes struct exportlist *ep; 17911558Srgrimes 1792224003Sdelphij ep = (struct exportlist *)calloc(1, sizeof (struct exportlist)); 17931558Srgrimes if (ep == (struct exportlist *)NULL) 17941558Srgrimes out_of_mem(); 17951558Srgrimes return (ep); 17961558Srgrimes} 17971558Srgrimes 17981558Srgrimes/* 17991558Srgrimes * Allocate a group list element 18001558Srgrimes */ 18011558Srgrimesstruct grouplist * 1802216587Scharnierget_grp(void) 18031558Srgrimes{ 18041558Srgrimes struct grouplist *gp; 18051558Srgrimes 1806224003Sdelphij gp = (struct grouplist *)calloc(1, sizeof (struct grouplist)); 18071558Srgrimes if (gp == (struct grouplist *)NULL) 18081558Srgrimes out_of_mem(); 18091558Srgrimes return (gp); 18101558Srgrimes} 18111558Srgrimes 18121558Srgrimes/* 18131558Srgrimes * Clean up upon an error in get_exportlist(). 18141558Srgrimes */ 18151558Srgrimesvoid 1816216587Scharniergetexp_err(struct exportlist *ep, struct grouplist *grp) 18171558Srgrimes{ 18181558Srgrimes struct grouplist *tgrp; 18191558Srgrimes 1820100336Sjoerg if (!(opt_flags & OP_QUIET)) 1821100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 18221558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 18231558Srgrimes free_exp(ep); 18241558Srgrimes while (grp) { 18251558Srgrimes tgrp = grp; 18261558Srgrimes grp = grp->gr_next; 18271558Srgrimes free_grp(tgrp); 18281558Srgrimes } 18291558Srgrimes} 18301558Srgrimes 18311558Srgrimes/* 18321558Srgrimes * Search the export list for a matching fs. 18331558Srgrimes */ 18341558Srgrimesstruct exportlist * 1835216587Scharnierex_search(fsid_t *fsid) 18361558Srgrimes{ 18371558Srgrimes struct exportlist *ep; 18381558Srgrimes 18391558Srgrimes ep = exphead; 18401558Srgrimes while (ep) { 18411558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 18421558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 18431558Srgrimes return (ep); 18441558Srgrimes ep = ep->ex_next; 18451558Srgrimes } 18461558Srgrimes return (ep); 18471558Srgrimes} 18481558Srgrimes 18491558Srgrimes/* 18501558Srgrimes * Add a directory path to the list. 18511558Srgrimes */ 18521558Srgrimeschar * 1853216587Scharnieradd_expdir(struct dirlist **dpp, char *cp, int len) 18541558Srgrimes{ 18551558Srgrimes struct dirlist *dp; 18561558Srgrimes 18571558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 185837663Scharnier if (dp == (struct dirlist *)NULL) 185937663Scharnier out_of_mem(); 18601558Srgrimes dp->dp_left = *dpp; 18611558Srgrimes dp->dp_right = (struct dirlist *)NULL; 18621558Srgrimes dp->dp_flag = 0; 18631558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 18641558Srgrimes strcpy(dp->dp_dirp, cp); 18651558Srgrimes *dpp = dp; 18661558Srgrimes return (dp->dp_dirp); 18671558Srgrimes} 18681558Srgrimes 18691558Srgrimes/* 18701558Srgrimes * Hang the dir list element off the dirpath binary tree as required 18711558Srgrimes * and update the entry for host. 18721558Srgrimes */ 18731558Srgrimesvoid 1874216587Scharnierhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1875216587Scharnier int flags) 18761558Srgrimes{ 18771558Srgrimes struct hostlist *hp; 18781558Srgrimes struct dirlist *dp2; 18791558Srgrimes 18809336Sdfr if (flags & OP_ALLDIRS) { 18811558Srgrimes if (ep->ex_defdir) 18821558Srgrimes free((caddr_t)dp); 18831558Srgrimes else 18841558Srgrimes ep->ex_defdir = dp; 18859336Sdfr if (grp == (struct grouplist *)NULL) { 18861558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 18879336Sdfr } else while (grp) { 18881558Srgrimes hp = get_ht(); 18891558Srgrimes hp->ht_grp = grp; 18901558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 18911558Srgrimes ep->ex_defdir->dp_hosts = hp; 18921558Srgrimes grp = grp->gr_next; 18931558Srgrimes } 18941558Srgrimes } else { 18951558Srgrimes 18961558Srgrimes /* 189737663Scharnier * Loop through the directories adding them to the tree. 18981558Srgrimes */ 18991558Srgrimes while (dp) { 19001558Srgrimes dp2 = dp->dp_left; 19019336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 19021558Srgrimes dp = dp2; 19031558Srgrimes } 19041558Srgrimes } 19051558Srgrimes} 19061558Srgrimes 19071558Srgrimes/* 19081558Srgrimes * Traverse the binary tree either updating a node that is already there 19091558Srgrimes * for the new directory or adding the new node. 19101558Srgrimes */ 19111558Srgrimesvoid 1912216587Scharnieradd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1913216587Scharnier int flags) 19141558Srgrimes{ 19151558Srgrimes struct dirlist *dp; 19161558Srgrimes struct hostlist *hp; 19171558Srgrimes int cmp; 19181558Srgrimes 19191558Srgrimes dp = *dpp; 19201558Srgrimes if (dp) { 19211558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 19221558Srgrimes if (cmp > 0) { 19239336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 19241558Srgrimes return; 19251558Srgrimes } else if (cmp < 0) { 19269336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 19271558Srgrimes return; 19281558Srgrimes } else 19291558Srgrimes free((caddr_t)newdp); 19301558Srgrimes } else { 19311558Srgrimes dp = newdp; 19321558Srgrimes dp->dp_left = (struct dirlist *)NULL; 19331558Srgrimes *dpp = dp; 19341558Srgrimes } 19351558Srgrimes if (grp) { 19361558Srgrimes 19371558Srgrimes /* 19381558Srgrimes * Hang all of the host(s) off of the directory point. 19391558Srgrimes */ 19401558Srgrimes do { 19411558Srgrimes hp = get_ht(); 19421558Srgrimes hp->ht_grp = grp; 19431558Srgrimes hp->ht_next = dp->dp_hosts; 19441558Srgrimes dp->dp_hosts = hp; 19451558Srgrimes grp = grp->gr_next; 19461558Srgrimes } while (grp); 19479336Sdfr } else { 19481558Srgrimes dp->dp_flag |= DP_DEFSET; 19499336Sdfr } 19501558Srgrimes} 19511558Srgrimes 19521558Srgrimes/* 19531558Srgrimes * Search for a dirpath on the export point. 19541558Srgrimes */ 19551558Srgrimesstruct dirlist * 1956216587Scharnierdirp_search(struct dirlist *dp, char *dirp) 19571558Srgrimes{ 19581558Srgrimes int cmp; 19591558Srgrimes 19601558Srgrimes if (dp) { 196174462Salfred cmp = strcmp(dp->dp_dirp, dirp); 19621558Srgrimes if (cmp > 0) 196374462Salfred return (dirp_search(dp->dp_left, dirp)); 19641558Srgrimes else if (cmp < 0) 196574462Salfred return (dirp_search(dp->dp_right, dirp)); 19661558Srgrimes else 19671558Srgrimes return (dp); 19681558Srgrimes } 19691558Srgrimes return (dp); 19701558Srgrimes} 19711558Srgrimes 19721558Srgrimes/* 19731558Srgrimes * Scan for a host match in a directory tree. 19741558Srgrimes */ 19751558Srgrimesint 1976216587Scharnierchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 1977216587Scharnier int *hostsetp) 19781558Srgrimes{ 19791558Srgrimes struct hostlist *hp; 19801558Srgrimes struct grouplist *grp; 198174462Salfred struct addrinfo *ai; 19821558Srgrimes 19831558Srgrimes if (dp) { 19841558Srgrimes if (dp->dp_flag & DP_DEFSET) 19859336Sdfr *defsetp = dp->dp_flag; 19861558Srgrimes hp = dp->dp_hosts; 19871558Srgrimes while (hp) { 19881558Srgrimes grp = hp->ht_grp; 19891558Srgrimes switch (grp->gr_type) { 19901558Srgrimes case GT_HOST: 199174462Salfred ai = grp->gr_ptr.gt_addrinfo; 199274462Salfred for (; ai; ai = ai->ai_next) { 199375801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 199474462Salfred *hostsetp = 199574462Salfred (hp->ht_flag | DP_HOSTSET); 199674462Salfred return (1); 199774462Salfred } 19989336Sdfr } 199975801Siedowse break; 20001558Srgrimes case GT_NET: 200175801Siedowse if (!sacmp(saddr, (struct sockaddr *) 200275801Siedowse &grp->gr_ptr.gt_net.nt_net, 200375801Siedowse (struct sockaddr *) 200475801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 200574462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 200674462Salfred return (1); 200774462Salfred } 200875801Siedowse break; 200975801Siedowse } 20101558Srgrimes hp = hp->ht_next; 20111558Srgrimes } 20121558Srgrimes } 20131558Srgrimes return (0); 20141558Srgrimes} 20151558Srgrimes 20161558Srgrimes/* 20171558Srgrimes * Scan tree for a host that matches the address. 20181558Srgrimes */ 20191558Srgrimesint 2020216587Scharnierscan_tree(struct dirlist *dp, struct sockaddr *saddr) 20211558Srgrimes{ 20229336Sdfr int defset, hostset; 20231558Srgrimes 20241558Srgrimes if (dp) { 20251558Srgrimes if (scan_tree(dp->dp_left, saddr)) 20261558Srgrimes return (1); 20279336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 20281558Srgrimes return (1); 20291558Srgrimes if (scan_tree(dp->dp_right, saddr)) 20301558Srgrimes return (1); 20311558Srgrimes } 20321558Srgrimes return (0); 20331558Srgrimes} 20341558Srgrimes 20351558Srgrimes/* 20361558Srgrimes * Traverse the dirlist tree and free it up. 20371558Srgrimes */ 20381558Srgrimesvoid 2039216587Scharnierfree_dir(struct dirlist *dp) 20401558Srgrimes{ 20411558Srgrimes 20421558Srgrimes if (dp) { 20431558Srgrimes free_dir(dp->dp_left); 20441558Srgrimes free_dir(dp->dp_right); 20451558Srgrimes free_host(dp->dp_hosts); 20461558Srgrimes free((caddr_t)dp); 20471558Srgrimes } 20481558Srgrimes} 20491558Srgrimes 20501558Srgrimes/* 2051184588Sdfr * Parse a colon separated list of security flavors 2052184588Sdfr */ 2053184588Sdfrint 2054216587Scharnierparsesec(char *seclist, struct exportlist *ep) 2055184588Sdfr{ 2056184588Sdfr char *cp, savedc; 2057184588Sdfr int flavor; 2058184588Sdfr 2059184588Sdfr ep->ex_numsecflavors = 0; 2060184588Sdfr for (;;) { 2061184588Sdfr cp = strchr(seclist, ':'); 2062184588Sdfr if (cp) { 2063184588Sdfr savedc = *cp; 2064184588Sdfr *cp = '\0'; 2065184588Sdfr } 2066184588Sdfr 2067184588Sdfr if (!strcmp(seclist, "sys")) 2068184588Sdfr flavor = AUTH_SYS; 2069184588Sdfr else if (!strcmp(seclist, "krb5")) 2070184588Sdfr flavor = RPCSEC_GSS_KRB5; 2071184588Sdfr else if (!strcmp(seclist, "krb5i")) 2072184588Sdfr flavor = RPCSEC_GSS_KRB5I; 2073184588Sdfr else if (!strcmp(seclist, "krb5p")) 2074184588Sdfr flavor = RPCSEC_GSS_KRB5P; 2075184588Sdfr else { 2076184588Sdfr if (cp) 2077184588Sdfr *cp = savedc; 2078184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 2079184588Sdfr return (1); 2080184588Sdfr } 2081184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 2082184588Sdfr if (cp) 2083184588Sdfr *cp = savedc; 2084184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 2085184588Sdfr return (1); 2086184588Sdfr } 2087184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 2088184588Sdfr ep->ex_numsecflavors++; 2089184588Sdfr if (cp) { 2090184588Sdfr *cp = savedc; 2091184588Sdfr seclist = cp + 1; 2092184588Sdfr } else { 2093184588Sdfr break; 2094184588Sdfr } 2095184588Sdfr } 2096184588Sdfr return (0); 2097184588Sdfr} 2098184588Sdfr 2099184588Sdfr/* 21001558Srgrimes * Parse the option string and update fields. 21011558Srgrimes * Option arguments may either be -<option>=<value> or 21021558Srgrimes * -<option> <value> 21031558Srgrimes */ 21041558Srgrimesint 2105216587Scharnierdo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 2106216587Scharnier int *has_hostp, int *exflagsp, struct xucred *cr) 21071558Srgrimes{ 21081558Srgrimes char *cpoptarg, *cpoptend; 21091558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 21101558Srgrimes int allflag, usedarg; 21111558Srgrimes 211251968Salfred savedc2 = '\0'; 21131558Srgrimes cpopt = *cpp; 21141558Srgrimes cpopt++; 21151558Srgrimes cp = *endcpp; 21161558Srgrimes savedc = *cp; 21171558Srgrimes *cp = '\0'; 21181558Srgrimes while (cpopt && *cpopt) { 21191558Srgrimes allflag = 1; 21201558Srgrimes usedarg = -2; 212137663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 21221558Srgrimes *cpoptend++ = '\0'; 212337663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 21241558Srgrimes *cpoptarg++ = '\0'; 21251558Srgrimes } else { 212637663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 21271558Srgrimes *cpoptarg++ = '\0'; 21281558Srgrimes else { 21291558Srgrimes *cp = savedc; 21301558Srgrimes nextfield(&cp, &endcp); 21311558Srgrimes **endcpp = '\0'; 21321558Srgrimes if (endcp > cp && *cp != '-') { 21331558Srgrimes cpoptarg = cp; 21341558Srgrimes savedc2 = *endcp; 21351558Srgrimes *endcp = '\0'; 21361558Srgrimes usedarg = 0; 21371558Srgrimes } 21381558Srgrimes } 21391558Srgrimes } 21401558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 21411558Srgrimes *exflagsp |= MNT_EXRDONLY; 21421558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 21431558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 21441558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 21451558Srgrimes usedarg++; 21461558Srgrimes parsecred(cpoptarg, cr); 21471558Srgrimes if (allflag == 0) { 21481558Srgrimes *exflagsp |= MNT_EXPORTANON; 21491558Srgrimes opt_flags |= OP_MAPALL; 21501558Srgrimes } else 21511558Srgrimes opt_flags |= OP_MAPROOT; 21521558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 215375801Siedowse !strcmp(cpopt, "m"))) { 21541558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 215537663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 21561558Srgrimes return (1); 21571558Srgrimes } 21581558Srgrimes usedarg++; 21591558Srgrimes opt_flags |= OP_MASK; 21601558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 21611558Srgrimes !strcmp(cpopt, "n"))) { 216274462Salfred if (strchr(cpoptarg, '/') != NULL) { 216374462Salfred if (debug) 216474462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 216574462Salfred opt_flags |= OP_MASKLEN; 216674462Salfred } 21671558Srgrimes if (grp->gr_type != GT_NULL) { 216837663Scharnier syslog(LOG_ERR, "network/host conflict"); 21691558Srgrimes return (1); 21701558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 217137663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 21721558Srgrimes return (1); 21731558Srgrimes } 21741558Srgrimes grp->gr_type = GT_NET; 21751558Srgrimes *has_hostp = 1; 21761558Srgrimes usedarg++; 21771558Srgrimes opt_flags |= OP_NET; 21781558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 21791558Srgrimes opt_flags |= OP_ALLDIRS; 218027447Sdfr } else if (!strcmp(cpopt, "public")) { 218127447Sdfr *exflagsp |= MNT_EXPUBLIC; 218227447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 218327447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 218427447Sdfr opt_flags |= OP_MAPALL; 218527447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 218627447Sdfr ep->ex_indexfile = strdup(cpoptarg); 2187100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 2188100336Sjoerg opt_flags |= OP_QUIET; 2189184588Sdfr } else if (!strcmp(cpopt, "sec")) { 2190184588Sdfr if (parsesec(cpoptarg, ep)) 2191184588Sdfr return (1); 2192184588Sdfr opt_flags |= OP_SEC; 2193184588Sdfr usedarg++; 21941558Srgrimes } else { 219537663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 21961558Srgrimes return (1); 21971558Srgrimes } 21981558Srgrimes if (usedarg >= 0) { 21991558Srgrimes *endcp = savedc2; 22001558Srgrimes **endcpp = savedc; 22011558Srgrimes if (usedarg > 0) { 22021558Srgrimes *cpp = cp; 22031558Srgrimes *endcpp = endcp; 22041558Srgrimes } 22051558Srgrimes return (0); 22061558Srgrimes } 22071558Srgrimes cpopt = cpoptend; 22081558Srgrimes } 22091558Srgrimes **endcpp = savedc; 22101558Srgrimes return (0); 22111558Srgrimes} 22121558Srgrimes 22131558Srgrimes/* 22141558Srgrimes * Translate a character string to the corresponding list of network 22151558Srgrimes * addresses for a hostname. 22161558Srgrimes */ 22171558Srgrimesint 2218216587Scharnierget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 22191558Srgrimes{ 22207401Swpaul struct grouplist *checkgrp; 222175635Siedowse struct addrinfo *ai, *tai, hints; 222274462Salfred int ecode; 222374462Salfred char host[NI_MAXHOST]; 22241558Srgrimes 222574462Salfred if (grp->gr_type != GT_NULL) { 222674462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 22271558Srgrimes return (1); 22281558Srgrimes } 222974462Salfred memset(&hints, 0, sizeof hints); 223074462Salfred hints.ai_flags = AI_CANONNAME; 223174462Salfred hints.ai_protocol = IPPROTO_UDP; 223274462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 223374462Salfred if (ecode != 0) { 223475635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 223574462Salfred return 1; 223674462Salfred } 223774462Salfred grp->gr_ptr.gt_addrinfo = ai; 223874462Salfred while (ai != NULL) { 223974462Salfred if (ai->ai_canonname == NULL) { 224074462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2241146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 224274462Salfred strlcpy(host, "?", sizeof(host)); 224374462Salfred ai->ai_canonname = strdup(host); 224474462Salfred ai->ai_flags |= AI_CANONNAME; 224575641Siedowse } 224674462Salfred if (debug) 224775635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 224875635Siedowse /* 224975635Siedowse * Sanity check: make sure we don't already have an entry 225075635Siedowse * for this host in the grouplist. 225175635Siedowse */ 225275635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 225375635Siedowse checkgrp = checkgrp->gr_next) { 225475635Siedowse if (checkgrp->gr_type != GT_HOST) 225575635Siedowse continue; 225675635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 225775635Siedowse tai = tai->ai_next) { 225875801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 225975635Siedowse continue; 226075635Siedowse if (debug) 226175635Siedowse fprintf(stderr, 226275635Siedowse "ignoring duplicate host %s\n", 226375635Siedowse ai->ai_canonname); 226475635Siedowse grp->gr_type = GT_IGNORE; 226575635Siedowse return (0); 226675635Siedowse } 226775635Siedowse } 226874462Salfred ai = ai->ai_next; 22691558Srgrimes } 227075635Siedowse grp->gr_type = GT_HOST; 22711558Srgrimes return (0); 22721558Srgrimes} 22731558Srgrimes 22741558Srgrimes/* 22751558Srgrimes * Free up an exports list component 22761558Srgrimes */ 22771558Srgrimesvoid 2278216587Scharnierfree_exp(struct exportlist *ep) 22791558Srgrimes{ 22801558Srgrimes 22811558Srgrimes if (ep->ex_defdir) { 22821558Srgrimes free_host(ep->ex_defdir->dp_hosts); 22831558Srgrimes free((caddr_t)ep->ex_defdir); 22841558Srgrimes } 22851558Srgrimes if (ep->ex_fsdir) 22861558Srgrimes free(ep->ex_fsdir); 228727447Sdfr if (ep->ex_indexfile) 228827447Sdfr free(ep->ex_indexfile); 22891558Srgrimes free_dir(ep->ex_dirl); 22901558Srgrimes free((caddr_t)ep); 22911558Srgrimes} 22921558Srgrimes 22931558Srgrimes/* 22941558Srgrimes * Free hosts. 22951558Srgrimes */ 22961558Srgrimesvoid 2297216587Scharnierfree_host(struct hostlist *hp) 22981558Srgrimes{ 22991558Srgrimes struct hostlist *hp2; 23001558Srgrimes 23011558Srgrimes while (hp) { 23021558Srgrimes hp2 = hp; 23031558Srgrimes hp = hp->ht_next; 23041558Srgrimes free((caddr_t)hp2); 23051558Srgrimes } 23061558Srgrimes} 23071558Srgrimes 23081558Srgrimesstruct hostlist * 2309216587Scharnierget_ht(void) 23101558Srgrimes{ 23111558Srgrimes struct hostlist *hp; 23121558Srgrimes 23131558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 23141558Srgrimes if (hp == (struct hostlist *)NULL) 23151558Srgrimes out_of_mem(); 23161558Srgrimes hp->ht_next = (struct hostlist *)NULL; 23179336Sdfr hp->ht_flag = 0; 23181558Srgrimes return (hp); 23191558Srgrimes} 23201558Srgrimes 23211558Srgrimes/* 23221558Srgrimes * Out of memory, fatal 23231558Srgrimes */ 23241558Srgrimesvoid 2325216587Scharnierout_of_mem(void) 23261558Srgrimes{ 23271558Srgrimes 232837663Scharnier syslog(LOG_ERR, "out of memory"); 23291558Srgrimes exit(2); 23301558Srgrimes} 23311558Srgrimes 23321558Srgrimes/* 2333158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 23341558Srgrimes * the kernel. 23351558Srgrimes */ 23361558Srgrimesint 2337158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2338158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 23391558Srgrimes{ 234075841Siedowse struct statfs fsb1; 234174462Salfred struct addrinfo *ai; 2342192934Srmacklem struct export_args ea, *eap; 2343158857Srodrigc char errmsg[255]; 2344158857Srodrigc char *cp; 23451558Srgrimes int done; 2346158857Srodrigc char savedc; 2347158857Srodrigc struct iovec *iov; 2348184588Sdfr int i, iovlen; 2349158857Srodrigc int ret; 2350192934Srmacklem struct nfsex_args nfsea; 23511558Srgrimes 2352192934Srmacklem if (run_v4server > 0) 2353192934Srmacklem eap = &nfsea.export; 2354192934Srmacklem else 2355192934Srmacklem eap = &ea; 2356192934Srmacklem 2357158857Srodrigc cp = NULL; 2358158857Srodrigc savedc = '\0'; 2359158857Srodrigc iov = NULL; 2360158857Srodrigc iovlen = 0; 2361158857Srodrigc ret = 0; 236275801Siedowse 2363192934Srmacklem bzero(eap, sizeof (struct export_args)); 2364158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2365192934Srmacklem eap->ex_flags = exflags; 2366192934Srmacklem eap->ex_anon = *anoncrp; 2367192934Srmacklem eap->ex_indexfile = ep->ex_indexfile; 236875641Siedowse if (grp->gr_type == GT_HOST) 236974462Salfred ai = grp->gr_ptr.gt_addrinfo; 237075641Siedowse else 237175641Siedowse ai = NULL; 2372192934Srmacklem eap->ex_numsecflavors = ep->ex_numsecflavors; 2373192934Srmacklem for (i = 0; i < eap->ex_numsecflavors; i++) 2374192934Srmacklem eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2375192934Srmacklem if (eap->ex_numsecflavors == 0) { 2376192934Srmacklem eap->ex_numsecflavors = 1; 2377192934Srmacklem eap->ex_secflavors[0] = AUTH_SYS; 2378184588Sdfr } 23791558Srgrimes done = FALSE; 2380158857Srodrigc 2381192934Srmacklem if (v4root_phase == 0) { 2382192934Srmacklem build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2383192934Srmacklem build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2384192934Srmacklem build_iovec(&iov, &iovlen, "from", NULL, 0); 2385192934Srmacklem build_iovec(&iov, &iovlen, "update", NULL, 0); 2386192934Srmacklem build_iovec(&iov, &iovlen, "export", eap, 2387192934Srmacklem sizeof (struct export_args)); 2388192934Srmacklem build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2389192934Srmacklem } 2390158857Srodrigc 23911558Srgrimes while (!done) { 23921558Srgrimes switch (grp->gr_type) { 23931558Srgrimes case GT_HOST: 239475641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 239574462Salfred goto skip; 2396192934Srmacklem eap->ex_addr = ai->ai_addr; 2397192934Srmacklem eap->ex_addrlen = ai->ai_addrlen; 2398192934Srmacklem eap->ex_masklen = 0; 23991558Srgrimes break; 24001558Srgrimes case GT_NET: 240175801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 240274462Salfred have_v6 == 0) 240374462Salfred goto skip; 2404192934Srmacklem eap->ex_addr = 240575801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2406192934Srmacklem eap->ex_addrlen = 2407158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2408192934Srmacklem eap->ex_mask = 240975801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2410192934Srmacklem eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 24111558Srgrimes break; 241275641Siedowse case GT_DEFAULT: 2413192934Srmacklem eap->ex_addr = NULL; 2414192934Srmacklem eap->ex_addrlen = 0; 2415192934Srmacklem eap->ex_mask = NULL; 2416192934Srmacklem eap->ex_masklen = 0; 241775641Siedowse break; 24187401Swpaul case GT_IGNORE: 2419158857Srodrigc ret = 0; 2420158857Srodrigc goto error_exit; 24217401Swpaul break; 24221558Srgrimes default: 242337663Scharnier syslog(LOG_ERR, "bad grouptype"); 24241558Srgrimes if (cp) 24251558Srgrimes *cp = savedc; 2426158857Srodrigc ret = 1; 2427158857Srodrigc goto error_exit; 24281558Srgrimes }; 24291558Srgrimes 24301558Srgrimes /* 2431192934Srmacklem * For V4:, use the nfssvc() syscall, instead of mount(). 24321558Srgrimes */ 2433192934Srmacklem if (v4root_phase == 2) { 2434192934Srmacklem nfsea.fspec = v4root_dirpath; 2435192934Srmacklem if (run_v4server > 0 && 2436192934Srmacklem nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2437192934Srmacklem syslog(LOG_ERR, "Exporting V4: failed"); 2438192934Srmacklem return (2); 2439158857Srodrigc } 2440192934Srmacklem } else { 2441192934Srmacklem /* 2442192934Srmacklem * XXX: 2443192934Srmacklem * Maybe I should just use the fsb->f_mntonname path 2444192934Srmacklem * instead of looping back up the dirp to the mount 2445192934Srmacklem * point?? 2446192934Srmacklem * Also, needs to know how to export all types of local 2447192934Srmacklem * exportable filesystems and not just "ufs". 2448192934Srmacklem */ 2449192934Srmacklem iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2450192934Srmacklem iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2451192934Srmacklem iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2452192934Srmacklem iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2453192934Srmacklem iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2454192934Srmacklem iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2455192934Srmacklem 2456192934Srmacklem while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2457192934Srmacklem if (cp) 2458192934Srmacklem *cp-- = savedc; 2459192934Srmacklem else 2460192934Srmacklem cp = dirp + dirplen - 1; 2461192934Srmacklem if (opt_flags & OP_QUIET) { 2462192934Srmacklem ret = 1; 2463192934Srmacklem goto error_exit; 2464192934Srmacklem } 2465192934Srmacklem if (errno == EPERM) { 2466192934Srmacklem if (debug) 2467192934Srmacklem warnx("can't change attributes for %s", 2468192934Srmacklem dirp); 2469192934Srmacklem syslog(LOG_ERR, 2470192934Srmacklem "can't change attributes for %s", 247175635Siedowse dirp); 2472192934Srmacklem ret = 1; 2473192934Srmacklem goto error_exit; 2474192934Srmacklem } 2475192934Srmacklem if (opt_flags & OP_ALLDIRS) { 2476192934Srmacklem if (errno == EINVAL) 2477192934Srmacklem syslog(LOG_ERR, 2478100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2479192934Srmacklem dirp); 2480192934Srmacklem else 2481192934Srmacklem syslog(LOG_ERR, 2482192934Srmacklem "could not remount %s: %m", 2483192934Srmacklem dirp); 2484192934Srmacklem ret = 1; 2485192934Srmacklem goto error_exit; 2486192934Srmacklem } 2487192934Srmacklem /* back up over the last component */ 2488192934Srmacklem while (*cp == '/' && cp > dirp) 2489192934Srmacklem cp--; 2490192934Srmacklem while (*(cp - 1) != '/' && cp > dirp) 2491192934Srmacklem cp--; 2492192934Srmacklem if (cp == dirp) { 2493192934Srmacklem if (debug) 2494192934Srmacklem warnx("mnt unsucc"); 2495192934Srmacklem syslog(LOG_ERR, "can't export %s %s", 2496192934Srmacklem dirp, errmsg); 2497192934Srmacklem ret = 1; 2498192934Srmacklem goto error_exit; 2499192934Srmacklem } 2500192934Srmacklem savedc = *cp; 2501192934Srmacklem *cp = '\0'; 2502192934Srmacklem /* 2503192934Srmacklem * Check that we're still on the same 2504192934Srmacklem * filesystem. 2505192934Srmacklem */ 2506192934Srmacklem if (statfs(dirp, &fsb1) != 0 || 2507192934Srmacklem bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2508192934Srmacklem sizeof (fsb1.f_fsid)) != 0) { 2509192934Srmacklem *cp = savedc; 2510100336Sjoerg syslog(LOG_ERR, 2511192934Srmacklem "can't export %s %s", dirp, 2512192934Srmacklem errmsg); 2513192934Srmacklem ret = 1; 2514192934Srmacklem goto error_exit; 2515192934Srmacklem } 25161558Srgrimes } 25171558Srgrimes } 2518192934Srmacklem 2519192934Srmacklem /* 2520192934Srmacklem * For the experimental server: 2521192934Srmacklem * If this is the public directory, get the file handle 2522192934Srmacklem * and load it into the kernel via the nfssvc() syscall. 2523192934Srmacklem */ 2524192934Srmacklem if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2525192934Srmacklem fhandle_t fh; 2526192934Srmacklem char *public_name; 2527192934Srmacklem 2528192934Srmacklem if (eap->ex_indexfile != NULL) 2529192934Srmacklem public_name = eap->ex_indexfile; 2530192934Srmacklem else 2531192934Srmacklem public_name = dirp; 2532192934Srmacklem if (getfh(public_name, &fh) < 0) 2533192934Srmacklem syslog(LOG_ERR, 2534192934Srmacklem "Can't get public fh for %s", public_name); 2535192934Srmacklem else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2536192934Srmacklem syslog(LOG_ERR, 2537192934Srmacklem "Can't set public fh for %s", public_name); 2538192934Srmacklem else 2539192934Srmacklem has_publicfh = 1; 2540192934Srmacklem } 254174462Salfredskip: 254275641Siedowse if (ai != NULL) 254374462Salfred ai = ai->ai_next; 254475641Siedowse if (ai == NULL) 25451558Srgrimes done = TRUE; 25461558Srgrimes } 25471558Srgrimes if (cp) 25481558Srgrimes *cp = savedc; 2549158857Srodrigcerror_exit: 2550158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2551158857Srodrigc if (iov != NULL) { 2552158857Srodrigc free(iov[0].iov_base); /* fstype */ 2553158857Srodrigc free(iov[2].iov_base); /* fspath */ 2554158857Srodrigc free(iov[4].iov_base); /* from */ 2555158857Srodrigc free(iov[6].iov_base); /* update */ 2556158857Srodrigc free(iov[8].iov_base); /* export */ 2557158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2558158857Srodrigc 2559158857Srodrigc /* free iov, allocated by realloc() */ 2560158857Srodrigc free(iov); 2561158857Srodrigc } 2562158857Srodrigc return (ret); 25631558Srgrimes} 25641558Srgrimes 25651558Srgrimes/* 25661558Srgrimes * Translate a net address. 256775801Siedowse * 256875801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 25691558Srgrimes */ 25701558Srgrimesint 2571216587Scharnierget_net(char *cp, struct netmsk *net, int maskflg) 25721558Srgrimes{ 257375861Siedowse struct netent *np = NULL; 257474462Salfred char *name, *p, *prefp; 257575801Siedowse struct sockaddr_in sin; 257675861Siedowse struct sockaddr *sa = NULL; 257774462Salfred struct addrinfo hints, *ai = NULL; 257874462Salfred char netname[NI_MAXHOST]; 257974462Salfred long preflen; 25801558Srgrimes 258175635Siedowse p = prefp = NULL; 258274462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 258374462Salfred p = strchr(cp, '/'); 258474462Salfred *p = '\0'; 258574462Salfred prefp = p + 1; 258674462Salfred } 258774462Salfred 258875861Siedowse /* 258975861Siedowse * Check for a numeric address first. We wish to avoid 259075861Siedowse * possible DNS lookups in getnetbyname(). 259175861Siedowse */ 259275861Siedowse if (isxdigit(*cp) || *cp == ':') { 259374462Salfred memset(&hints, 0, sizeof hints); 259475801Siedowse /* Ensure the mask and the network have the same family. */ 259575801Siedowse if (maskflg && (opt_flags & OP_NET)) 259675801Siedowse hints.ai_family = net->nt_net.ss_family; 259775801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 259875801Siedowse hints.ai_family = net->nt_mask.ss_family; 259975801Siedowse else 260075801Siedowse hints.ai_family = AF_UNSPEC; 260174462Salfred hints.ai_flags = AI_NUMERICHOST; 260275861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 260375861Siedowse sa = ai->ai_addr; 260475861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 260574462Salfred /* 260675801Siedowse * The address in `cp' is really a network address, so 260775801Siedowse * use inet_network() to re-interpret this correctly. 260875801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 260974462Salfred */ 261075801Siedowse bzero(&sin, sizeof sin); 261174462Salfred sin.sin_family = AF_INET; 261274462Salfred sin.sin_len = sizeof sin; 261375801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 261474462Salfred if (debug) 261575801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 261675801Siedowse inet_ntoa(sin.sin_addr)); 261774462Salfred sa = (struct sockaddr *)&sin; 261875861Siedowse } 261975861Siedowse } 262075861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 262175861Siedowse bzero(&sin, sizeof sin); 262275861Siedowse sin.sin_family = AF_INET; 262375861Siedowse sin.sin_len = sizeof sin; 262475861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 262575861Siedowse sa = (struct sockaddr *)&sin; 262675861Siedowse } 262775861Siedowse if (sa == NULL) 262874462Salfred goto fail; 262925318Spst 263075801Siedowse if (maskflg) { 263175801Siedowse /* The specified sockaddr is a mask. */ 263275801Siedowse if (checkmask(sa) != 0) 263375801Siedowse goto fail; 263475801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 263575801Siedowse opt_flags |= OP_HAVEMASK; 263675801Siedowse } else { 263775801Siedowse /* The specified sockaddr is a network address. */ 263875801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 263974462Salfred 264075801Siedowse /* Get a network name for the export list. */ 264175801Siedowse if (np) { 264275801Siedowse name = np->n_name; 264375801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2644146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 264575801Siedowse name = netname; 264675801Siedowse } else { 264775801Siedowse goto fail; 264875801Siedowse } 264975801Siedowse if ((net->nt_name = strdup(name)) == NULL) 265075801Siedowse out_of_mem(); 265175801Siedowse 265275801Siedowse /* 265375801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 265475801Siedowse * from the class of an IPv4 address. 265575801Siedowse */ 265674462Salfred if (opt_flags & OP_MASKLEN) { 265774462Salfred preflen = strtol(prefp, NULL, 10); 265875801Siedowse if (preflen < 0L || preflen == LONG_MAX) 265974462Salfred goto fail; 266075801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 266175801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 266275801Siedowse goto fail; 266375801Siedowse opt_flags |= OP_HAVEMASK; 266474462Salfred *p = '/'; 266575801Siedowse } else if (sa->sa_family == AF_INET && 266675801Siedowse (opt_flags & OP_MASK) == 0) { 266775801Siedowse in_addr_t addr; 266874462Salfred 266975801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 267075801Siedowse if (IN_CLASSA(addr)) 267175801Siedowse preflen = 8; 267275801Siedowse else if (IN_CLASSB(addr)) 267375801Siedowse preflen = 16; 267475801Siedowse else if (IN_CLASSC(addr)) 267575801Siedowse preflen = 24; 267675801Siedowse else if (IN_CLASSD(addr)) 267775801Siedowse preflen = 28; 267875801Siedowse else 267975801Siedowse preflen = 32; /* XXX */ 268075801Siedowse 268175801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 268275801Siedowse makemask(&net->nt_mask, (int)preflen); 268375801Siedowse opt_flags |= OP_HAVEMASK; 268474462Salfred } 268574462Salfred } 268674462Salfred 268774462Salfred if (ai) 268874462Salfred freeaddrinfo(ai); 268974462Salfred return 0; 269074462Salfred 269174462Salfredfail: 269274462Salfred if (ai) 269374462Salfred freeaddrinfo(ai); 269474462Salfred return 1; 26951558Srgrimes} 26961558Srgrimes 26971558Srgrimes/* 26981558Srgrimes * Parse out the next white space separated field 26991558Srgrimes */ 27001558Srgrimesvoid 2701216587Scharniernextfield(char **cp, char **endcp) 27021558Srgrimes{ 27031558Srgrimes char *p; 27041558Srgrimes 27051558Srgrimes p = *cp; 27061558Srgrimes while (*p == ' ' || *p == '\t') 27071558Srgrimes p++; 27081558Srgrimes if (*p == '\n' || *p == '\0') 27091558Srgrimes *cp = *endcp = p; 27101558Srgrimes else { 27111558Srgrimes *cp = p++; 27121558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 27131558Srgrimes p++; 27141558Srgrimes *endcp = p; 27151558Srgrimes } 27161558Srgrimes} 27171558Srgrimes 27181558Srgrimes/* 27191558Srgrimes * Get an exports file line. Skip over blank lines and handle line 27201558Srgrimes * continuations. 27211558Srgrimes */ 27221558Srgrimesint 2723216587Scharnierget_line(void) 27241558Srgrimes{ 27251558Srgrimes char *p, *cp; 272696622Siedowse size_t len; 27271558Srgrimes int totlen, cont_line; 27281558Srgrimes 27291558Srgrimes /* 27301558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 27311558Srgrimes */ 27321558Srgrimes p = line; 27331558Srgrimes totlen = 0; 27341558Srgrimes do { 273596622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 27361558Srgrimes return (0); 27371558Srgrimes cp = p + len - 1; 27381558Srgrimes cont_line = 0; 27391558Srgrimes while (cp >= p && 27401558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 27411558Srgrimes if (*cp == '\\') 27421558Srgrimes cont_line = 1; 27431558Srgrimes cp--; 27441558Srgrimes len--; 27451558Srgrimes } 274679117Sdd if (cont_line) { 274779117Sdd *++cp = ' '; 274879117Sdd len++; 274979117Sdd } 275096622Siedowse if (linesize < len + totlen + 1) { 275196622Siedowse linesize = len + totlen + 1; 275296622Siedowse line = realloc(line, linesize); 275396622Siedowse if (line == NULL) 275496622Siedowse out_of_mem(); 27551558Srgrimes } 275696622Siedowse memcpy(line + totlen, p, len); 275796622Siedowse totlen += len; 275896622Siedowse line[totlen] = '\0'; 27591558Srgrimes } while (totlen == 0 || cont_line); 27601558Srgrimes return (1); 27611558Srgrimes} 27621558Srgrimes 27631558Srgrimes/* 27641558Srgrimes * Parse a description of a credential. 27651558Srgrimes */ 27661558Srgrimesvoid 2767216587Scharnierparsecred(char *namelist, struct xucred *cr) 27681558Srgrimes{ 27691558Srgrimes char *name; 27701558Srgrimes int cnt; 27711558Srgrimes char *names; 27721558Srgrimes struct passwd *pw; 27731558Srgrimes struct group *gr; 2774194498Sbrooks gid_t groups[XU_NGROUPS + 1]; 2775136051Sstefanf int ngroups; 27761558Srgrimes 277791354Sdd cr->cr_version = XUCRED_VERSION; 27781558Srgrimes /* 277937663Scharnier * Set up the unprivileged user. 27801558Srgrimes */ 27811558Srgrimes cr->cr_uid = -2; 27821558Srgrimes cr->cr_groups[0] = -2; 27831558Srgrimes cr->cr_ngroups = 1; 27841558Srgrimes /* 27851558Srgrimes * Get the user's password table entry. 27861558Srgrimes */ 27871558Srgrimes names = strsep(&namelist, " \t\n"); 27881558Srgrimes name = strsep(&names, ":"); 27891558Srgrimes if (isdigit(*name) || *name == '-') 27901558Srgrimes pw = getpwuid(atoi(name)); 27911558Srgrimes else 27921558Srgrimes pw = getpwnam(name); 27931558Srgrimes /* 27941558Srgrimes * Credentials specified as those of a user. 27951558Srgrimes */ 27961558Srgrimes if (names == NULL) { 27971558Srgrimes if (pw == NULL) { 279837663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 27991558Srgrimes return; 28001558Srgrimes } 28011558Srgrimes cr->cr_uid = pw->pw_uid; 2802194498Sbrooks ngroups = XU_NGROUPS + 1; 28031558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 280437663Scharnier syslog(LOG_ERR, "too many groups"); 28051558Srgrimes /* 2806136051Sstefanf * Compress out duplicate. 28071558Srgrimes */ 28081558Srgrimes cr->cr_ngroups = ngroups - 1; 28091558Srgrimes cr->cr_groups[0] = groups[0]; 28101558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 28111558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 28121558Srgrimes return; 28131558Srgrimes } 28141558Srgrimes /* 28151558Srgrimes * Explicit credential specified as a colon separated list: 28161558Srgrimes * uid:gid:gid:... 28171558Srgrimes */ 28181558Srgrimes if (pw != NULL) 28191558Srgrimes cr->cr_uid = pw->pw_uid; 28201558Srgrimes else if (isdigit(*name) || *name == '-') 28211558Srgrimes cr->cr_uid = atoi(name); 28221558Srgrimes else { 282337663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 28241558Srgrimes return; 28251558Srgrimes } 28261558Srgrimes cr->cr_ngroups = 0; 2827194498Sbrooks while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 28281558Srgrimes name = strsep(&names, ":"); 28291558Srgrimes if (isdigit(*name) || *name == '-') { 28301558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 28311558Srgrimes } else { 28321558Srgrimes if ((gr = getgrnam(name)) == NULL) { 283337663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 28341558Srgrimes continue; 28351558Srgrimes } 28361558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 28371558Srgrimes } 28381558Srgrimes } 2839194498Sbrooks if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 284037663Scharnier syslog(LOG_ERR, "too many groups"); 28411558Srgrimes} 28421558Srgrimes 2843194880Sdfr#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 28441558Srgrimes/* 28451558Srgrimes * Routines that maintain the remote mounttab 28461558Srgrimes */ 28471558Srgrimesvoid 2848216587Scharnierget_mountlist(void) 28491558Srgrimes{ 28501558Srgrimes struct mountlist *mlp, **mlpp; 285123681Speter char *host, *dirp, *cp; 28521558Srgrimes char str[STRSIZ]; 28531558Srgrimes FILE *mlfile; 28541558Srgrimes 28551558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 285653117Sbillf if (errno == ENOENT) 285753117Sbillf return; 285853117Sbillf else { 285953117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 286053117Sbillf return; 286153117Sbillf } 28621558Srgrimes } 28631558Srgrimes mlpp = &mlhead; 28641558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 286523681Speter cp = str; 286623681Speter host = strsep(&cp, " \t\n"); 286723681Speter dirp = strsep(&cp, " \t\n"); 286823681Speter if (host == NULL || dirp == NULL) 28691558Srgrimes continue; 28701558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 287137663Scharnier if (mlp == (struct mountlist *)NULL) 287237663Scharnier out_of_mem(); 2873194880Sdfr strncpy(mlp->ml_host, host, MNTNAMLEN); 2874194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2875194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2876194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 28771558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 28781558Srgrimes *mlpp = mlp; 28791558Srgrimes mlpp = &mlp->ml_next; 28801558Srgrimes } 28811558Srgrimes fclose(mlfile); 28821558Srgrimes} 28831558Srgrimes 288475635Siedowsevoid 288575635Siedowsedel_mlist(char *hostp, char *dirp) 28861558Srgrimes{ 28871558Srgrimes struct mountlist *mlp, **mlpp; 28881558Srgrimes struct mountlist *mlp2; 28891558Srgrimes FILE *mlfile; 28901558Srgrimes int fnd = 0; 28911558Srgrimes 28921558Srgrimes mlpp = &mlhead; 28931558Srgrimes mlp = mlhead; 28941558Srgrimes while (mlp) { 28951558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 28961558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 28971558Srgrimes fnd = 1; 28981558Srgrimes mlp2 = mlp; 28991558Srgrimes *mlpp = mlp = mlp->ml_next; 29001558Srgrimes free((caddr_t)mlp2); 29011558Srgrimes } else { 29021558Srgrimes mlpp = &mlp->ml_next; 29031558Srgrimes mlp = mlp->ml_next; 29041558Srgrimes } 29051558Srgrimes } 29061558Srgrimes if (fnd) { 29071558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 290837663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 29091558Srgrimes return; 29101558Srgrimes } 29111558Srgrimes mlp = mlhead; 29121558Srgrimes while (mlp) { 29131558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 29141558Srgrimes mlp = mlp->ml_next; 29151558Srgrimes } 29161558Srgrimes fclose(mlfile); 29171558Srgrimes } 29181558Srgrimes} 29191558Srgrimes 29201558Srgrimesvoid 2921216587Scharnieradd_mlist(char *hostp, char *dirp) 29221558Srgrimes{ 29231558Srgrimes struct mountlist *mlp, **mlpp; 29241558Srgrimes FILE *mlfile; 29251558Srgrimes 29261558Srgrimes mlpp = &mlhead; 29271558Srgrimes mlp = mlhead; 29281558Srgrimes while (mlp) { 29291558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 29301558Srgrimes return; 29311558Srgrimes mlpp = &mlp->ml_next; 29321558Srgrimes mlp = mlp->ml_next; 29331558Srgrimes } 29341558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 293537663Scharnier if (mlp == (struct mountlist *)NULL) 293637663Scharnier out_of_mem(); 2937194880Sdfr strncpy(mlp->ml_host, hostp, MNTNAMLEN); 2938194880Sdfr mlp->ml_host[MNTNAMLEN] = '\0'; 2939194880Sdfr strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2940194880Sdfr mlp->ml_dirp[MNTPATHLEN] = '\0'; 29411558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 29421558Srgrimes *mlpp = mlp; 29431558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 294437663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 29451558Srgrimes return; 29461558Srgrimes } 29471558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 29481558Srgrimes fclose(mlfile); 29491558Srgrimes} 29501558Srgrimes 29511558Srgrimes/* 29521558Srgrimes * Free up a group list. 29531558Srgrimes */ 29541558Srgrimesvoid 2955216587Scharnierfree_grp(struct grouplist *grp) 29561558Srgrimes{ 29571558Srgrimes if (grp->gr_type == GT_HOST) { 295874462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 295974462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 29601558Srgrimes } else if (grp->gr_type == GT_NET) { 29611558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 29621558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 29631558Srgrimes } 29641558Srgrimes free((caddr_t)grp); 29651558Srgrimes} 29661558Srgrimes 29671558Srgrimes#ifdef DEBUG 29681558Srgrimesvoid 29691558SrgrimesSYSLOG(int pri, const char *fmt, ...) 29701558Srgrimes{ 29711558Srgrimes va_list ap; 29721558Srgrimes 29731558Srgrimes va_start(ap, fmt); 29741558Srgrimes vfprintf(stderr, fmt, ap); 29751558Srgrimes va_end(ap); 29761558Srgrimes} 29771558Srgrimes#endif /* DEBUG */ 29781558Srgrimes 29791558Srgrimes/* 29801558Srgrimes * Check options for consistency. 29811558Srgrimes */ 29821558Srgrimesint 2983216587Scharniercheck_options(struct dirlist *dp) 29841558Srgrimes{ 29851558Srgrimes 2986192934Srmacklem if (v4root_phase == 0 && dp == NULL) 29871558Srgrimes return (1); 298883653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 298983653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 29901558Srgrimes return (1); 29911558Srgrimes } 29921558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 299375801Siedowse syslog(LOG_ERR, "-mask requires -network"); 299475801Siedowse return (1); 29951558Srgrimes } 299675801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 299775801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 299875801Siedowse return (1); 299975801Siedowse } 300075801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 300175801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 300275801Siedowse return (1); 300375801Siedowse } 3004192934Srmacklem if (v4root_phase > 0 && 3005192934Srmacklem (opt_flags & 3006192934Srmacklem ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 3007192934Srmacklem syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 3008192934Srmacklem return (1); 3009192934Srmacklem } 3010207689Srmacklem if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 3011207689Srmacklem syslog(LOG_ERR, "-alldirs has multiple directories"); 3012207689Srmacklem return (1); 3013207689Srmacklem } 30141558Srgrimes return (0); 30151558Srgrimes} 30161558Srgrimes 30171558Srgrimes/* 30181558Srgrimes * Check an absolute directory path for any symbolic links. Return true 30191558Srgrimes */ 30201558Srgrimesint 3021216587Scharniercheck_dirpath(char *dirp) 30221558Srgrimes{ 30231558Srgrimes char *cp; 30241558Srgrimes int ret = 1; 30251558Srgrimes struct stat sb; 30261558Srgrimes 30271558Srgrimes cp = dirp + 1; 30281558Srgrimes while (*cp && ret) { 30291558Srgrimes if (*cp == '/') { 30301558Srgrimes *cp = '\0'; 30319336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 30321558Srgrimes ret = 0; 30331558Srgrimes *cp = '/'; 30341558Srgrimes } 30351558Srgrimes cp++; 30361558Srgrimes } 30379336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 30381558Srgrimes ret = 0; 30391558Srgrimes return (ret); 30401558Srgrimes} 30419336Sdfr 304275801Siedowse/* 304375801Siedowse * Make a netmask according to the specified prefix length. The ss_family 304475801Siedowse * and other non-address fields must be initialised before calling this. 304575801Siedowse */ 304675801Siedowseint 304775801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 304874462Salfred{ 304975801Siedowse u_char *p; 305075801Siedowse int bits, i, len; 305174462Salfred 305275801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 305375801Siedowse return (-1); 3054103949Smike if (bitlen > len * CHAR_BIT) 305575801Siedowse return (-1); 305674462Salfred 305775801Siedowse for (i = 0; i < len; i++) { 3058103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 3059219125Sru *p++ = (u_char)~0 << (CHAR_BIT - bits); 306075801Siedowse bitlen -= bits; 306174462Salfred } 306275801Siedowse return 0; 306374462Salfred} 306474462Salfred 306575801Siedowse/* 306675801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 306775801Siedowse * is acceptable (i.e. of the form 1...10....0). 306875801Siedowse */ 306975801Siedowseint 307075801Siedowsecheckmask(struct sockaddr *sa) 307174462Salfred{ 307275801Siedowse u_char *mask; 307375801Siedowse int i, len; 307474462Salfred 307575801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 307675801Siedowse return (-1); 307775801Siedowse 307875801Siedowse for (i = 0; i < len; i++) 307975801Siedowse if (mask[i] != 0xff) 308075801Siedowse break; 308175801Siedowse if (i < len) { 308275801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 308375801Siedowse return (-1); 308475801Siedowse i++; 308574462Salfred } 308675801Siedowse for (; i < len; i++) 308775801Siedowse if (mask[i] != 0) 308875801Siedowse return (-1); 308975801Siedowse return (0); 309074462Salfred} 309174462Salfred 309275801Siedowse/* 309375801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 309475801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 309575801Siedowse * If samask is NULL, perform a full comparision. 309675801Siedowse */ 309775801Siedowseint 309875801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 309974462Salfred{ 310075801Siedowse unsigned char *p1, *p2, *mask; 310175801Siedowse int len, i; 310274462Salfred 310375801Siedowse if (sa1->sa_family != sa2->sa_family || 310475801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 310575801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 310675801Siedowse return (1); 310775801Siedowse 310875801Siedowse switch (sa1->sa_family) { 310974462Salfred case AF_INET6: 311075801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 311175801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 311275801Siedowse return (1); 311374462Salfred break; 311474462Salfred } 311574462Salfred 311675801Siedowse /* Simple binary comparison if no mask specified. */ 311775801Siedowse if (samask == NULL) 311875801Siedowse return (memcmp(p1, p2, len)); 311974462Salfred 312075801Siedowse /* Set up the mask, and do a mask-based comparison. */ 312175801Siedowse if (sa1->sa_family != samask->sa_family || 312275801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 312375801Siedowse return (1); 312474462Salfred 312575801Siedowse for (i = 0; i < len; i++) 312675801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 312775801Siedowse return (1); 312875801Siedowse return (0); 312974462Salfred} 313074462Salfred 313175801Siedowse/* 313275801Siedowse * Return a pointer to the part of the sockaddr that contains the 313375801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 313475801Siedowse * NULL if the address family is unknown. 313575801Siedowse */ 313675801Siedowsevoid * 313775801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 313875801Siedowse void *p; 313974462Salfred int len; 314074462Salfred 314175801Siedowse switch (sa->sa_family) { 314274462Salfred case AF_INET: 314375801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 314475801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 314574462Salfred break; 314674462Salfred case AF_INET6: 314775801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 314875801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 314974462Salfred break; 315074462Salfred default: 315175801Siedowse p = NULL; 315275801Siedowse len = 0; 315374462Salfred } 315474462Salfred 315575801Siedowse if (nbytes != NULL) 315675801Siedowse *nbytes = len; 315775801Siedowse return (p); 315874462Salfred} 315974462Salfred 316075754Siedowsevoid 3161216587Scharnierhuphandler(int sig __unused) 316275754Siedowse{ 316375754Siedowse got_sighup = 1; 316475754Siedowse} 316575754Siedowse 3166216587Scharniervoid terminate(int sig __unused) 316774462Salfred{ 3168149433Spjd pidfile_remove(pfh); 3169194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 3170194880Sdfr rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 317174462Salfred exit (0); 317274462Salfred} 3173192934Srmacklem 3174