mountd.c revision 173056
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 173056 2007-10-27 12:24:47Z simon $"); 47105267Scharnier 481558Srgrimes#include <sys/param.h> 491558Srgrimes#include <sys/mount.h> 5074462Salfred#include <sys/fcntl.h> 511558Srgrimes#include <sys/stat.h> 521558Srgrimes#include <sys/syslog.h> 5324330Sguido#include <sys/sysctl.h> 5496622Siedowse#include <sys/linker.h> 5596622Siedowse#include <sys/module.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> 621558Srgrimes#include <nfs/rpcv2.h> 639336Sdfr#include <nfs/nfsproto.h> 6483653Speter#include <nfsserver/nfs.h> 651558Srgrimes 661558Srgrimes#include <arpa/inet.h> 671558Srgrimes 681558Srgrimes#include <ctype.h> 6937663Scharnier#include <err.h> 701558Srgrimes#include <errno.h> 711558Srgrimes#include <grp.h> 72149433Spjd#include <libutil.h> 73103949Smike#include <limits.h> 741558Srgrimes#include <netdb.h> 751558Srgrimes#include <pwd.h> 761558Srgrimes#include <signal.h> 771558Srgrimes#include <stdio.h> 781558Srgrimes#include <stdlib.h> 791558Srgrimes#include <string.h> 801558Srgrimes#include <unistd.h> 811558Srgrimes#include "pathnames.h" 82158857Srodrigc#include "mntopts.h" 831558Srgrimes 841558Srgrimes#ifdef DEBUG 851558Srgrimes#include <stdarg.h> 861558Srgrimes#endif 871558Srgrimes 881558Srgrimes/* 891558Srgrimes * Structures for keeping the mount list and export list 901558Srgrimes */ 911558Srgrimesstruct mountlist { 921558Srgrimes struct mountlist *ml_next; 931558Srgrimes char ml_host[RPCMNT_NAMELEN+1]; 941558Srgrimes char ml_dirp[RPCMNT_PATHLEN+1]; 951558Srgrimes}; 961558Srgrimes 971558Srgrimesstruct dirlist { 981558Srgrimes struct dirlist *dp_left; 991558Srgrimes struct dirlist *dp_right; 1001558Srgrimes int dp_flag; 1011558Srgrimes struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 1021558Srgrimes char dp_dirp[1]; /* Actually malloc'd to size of dir */ 1031558Srgrimes}; 1041558Srgrimes/* dp_flag bits */ 1051558Srgrimes#define DP_DEFSET 0x1 1069336Sdfr#define DP_HOSTSET 0x2 1071558Srgrimes 1081558Srgrimesstruct exportlist { 1091558Srgrimes struct exportlist *ex_next; 1101558Srgrimes struct dirlist *ex_dirl; 1111558Srgrimes struct dirlist *ex_defdir; 1121558Srgrimes int ex_flag; 1131558Srgrimes fsid_t ex_fs; 1141558Srgrimes char *ex_fsdir; 11527447Sdfr char *ex_indexfile; 1161558Srgrimes}; 1171558Srgrimes/* ex_flag bits */ 1181558Srgrimes#define EX_LINKED 0x1 1191558Srgrimes 1201558Srgrimesstruct netmsk { 12174462Salfred struct sockaddr_storage nt_net; 12275801Siedowse struct sockaddr_storage nt_mask; 12342144Sdfr char *nt_name; 1241558Srgrimes}; 1251558Srgrimes 1261558Srgrimesunion grouptypes { 12774462Salfred struct addrinfo *gt_addrinfo; 1281558Srgrimes struct netmsk gt_net; 1291558Srgrimes}; 1301558Srgrimes 1311558Srgrimesstruct grouplist { 1321558Srgrimes int gr_type; 1331558Srgrimes union grouptypes gr_ptr; 1341558Srgrimes struct grouplist *gr_next; 1351558Srgrimes}; 1361558Srgrimes/* Group types */ 1371558Srgrimes#define GT_NULL 0x0 1381558Srgrimes#define GT_HOST 0x1 1391558Srgrimes#define GT_NET 0x2 14075641Siedowse#define GT_DEFAULT 0x3 1417401Swpaul#define GT_IGNORE 0x5 1421558Srgrimes 1431558Srgrimesstruct hostlist { 1449336Sdfr int ht_flag; /* Uses DP_xx bits */ 1451558Srgrimes struct grouplist *ht_grp; 1461558Srgrimes struct hostlist *ht_next; 1471558Srgrimes}; 1481558Srgrimes 1499336Sdfrstruct fhreturn { 1509336Sdfr int fhr_flag; 1519336Sdfr int fhr_vers; 1529336Sdfr nfsfh_t fhr_fh; 1539336Sdfr}; 1549336Sdfr 1551558Srgrimes/* Global defs */ 15692882Simpchar *add_expdir(struct dirlist **, char *, int); 15792882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 15892882Simp struct grouplist *, int); 15992882Simpvoid add_mlist(char *, char *); 16092882Simpint check_dirpath(char *); 16192882Simpint check_options(struct dirlist *); 16275801Siedowseint checkmask(struct sockaddr *sa); 16392882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 164172827Smatteovoid create_service(struct netconfig *nconf); 16575635Siedowsevoid del_mlist(char *hostp, char *dirp); 16692882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 16792882Simpint do_mount(struct exportlist *, struct grouplist *, int, 16892882Simp struct xucred *, char *, int, struct statfs *); 16992882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17092882Simp int *, int *, struct xucred *); 17192882Simpstruct exportlist *ex_search(fsid_t *); 17292882Simpstruct exportlist *get_exp(void); 17392882Simpvoid free_dir(struct dirlist *); 17492882Simpvoid free_exp(struct exportlist *); 17592882Simpvoid free_grp(struct grouplist *); 17692882Simpvoid free_host(struct hostlist *); 17792882Simpvoid get_exportlist(void); 17892882Simpint get_host(char *, struct grouplist *, struct grouplist *); 17992882Simpstruct hostlist *get_ht(void); 18092882Simpint get_line(void); 18192882Simpvoid get_mountlist(void); 18292882Simpint get_net(char *, struct netmsk *, int); 18392882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 18492882Simpstruct grouplist *get_grp(void); 18592882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 18692882Simp struct exportlist *, int); 18775754Siedowsevoid huphandler(int sig); 18875801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 18992882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19092882Simpvoid nextfield(char **, char **); 19192882Simpvoid out_of_mem(void); 19292882Simpvoid parsecred(char *, struct xucred *); 193100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 19475801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 19575801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 19675801Siedowse struct sockaddr *samask); 19792882Simpint scan_tree(struct dirlist *, struct sockaddr *); 19892882Simpstatic void usage(void); 19992882Simpint xdr_dir(XDR *, char *); 20092882Simpint xdr_explist(XDR *, caddr_t); 201100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20292882Simpint xdr_fhs(XDR *, caddr_t); 20392882Simpint xdr_mlist(XDR *, caddr_t); 20492882Simpvoid terminate(int); 2051558Srgrimes 2061558Srgrimesstruct exportlist *exphead; 2071558Srgrimesstruct mountlist *mlhead; 2081558Srgrimesstruct grouplist *grphead; 209166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 210166440Spjdchar **exnames; 211172827Smatteochar **hosts = NULL; 21272650Sgreenstruct xucred def_anon = { 21391354Sdd XUCRED_VERSION, 21472650Sgreen (uid_t)-2, 2151558Srgrimes 1, 21672650Sgreen { (gid_t)-2 }, 21772650Sgreen NULL 2181558Srgrimes}; 21925087Sdfrint force_v2 = 0; 2209336Sdfrint resvport_only = 1; 221172827Smatteoint nhosts = 0; 2229336Sdfrint dir_only = 1; 223121767Speterint dolog = 0; 22475754Siedowseint got_sighup = 0; 225172827Smatteoint xcreated = 0; 22674462Salfred 227172827Smatteochar *svcport_str = NULL; 228172827Smatteo 2291558Srgrimesint opt_flags; 23074462Salfredstatic int have_v6 = 1; 23174462Salfred 232149433Spjdstruct pidfh *pfh = NULL; 23375801Siedowse/* Bits for opt_flags above */ 2341558Srgrimes#define OP_MAPROOT 0x01 2351558Srgrimes#define OP_MAPALL 0x02 23683653Speter/* 0x4 free */ 2371558Srgrimes#define OP_MASK 0x08 2381558Srgrimes#define OP_NET 0x10 2391558Srgrimes#define OP_ALLDIRS 0x40 24075801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 241100336Sjoerg#define OP_QUIET 0x100 24274462Salfred#define OP_MASKLEN 0x200 2431558Srgrimes 2441558Srgrimes#ifdef DEBUG 2451558Srgrimesint debug = 1; 24692882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2471558Srgrimes#define syslog SYSLOG 2481558Srgrimes#else 2491558Srgrimesint debug = 0; 2501558Srgrimes#endif 2511558Srgrimes 2521558Srgrimes/* 2531558Srgrimes * Mountd server for NFS mount protocol as described in: 2541558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2551558Srgrimes * The optional arguments are the exports file name 2561558Srgrimes * default: _PATH_EXPORTS 2571558Srgrimes * and "-n" to allow nonroot mount. 2581558Srgrimes */ 2591558Srgrimesint 2601558Srgrimesmain(argc, argv) 2611558Srgrimes int argc; 2621558Srgrimes char **argv; 2631558Srgrimes{ 26475754Siedowse fd_set readfds; 265172827Smatteo struct netconfig *nconf; 266172827Smatteo char *endptr, **hosts_bak; 267172827Smatteo void *nc_handle; 268149433Spjd pid_t otherpid; 269172827Smatteo in_port_t svcport; 270172827Smatteo int c, k, s; 271109363Smbr int maxrec = RPC_MAXDATASIZE; 2721558Srgrimes 27374462Salfred /* Check that another mountd isn't already running. */ 274150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 275149433Spjd if (pfh == NULL) { 276149433Spjd if (errno == EEXIST) 277149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 278149433Spjd warn("cannot open or create pidfile"); 279149433Spjd } 28074462Salfred 28174462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 28274462Salfred if (s < 0) 28374462Salfred have_v6 = 0; 28474462Salfred else 28574462Salfred close(s); 28683687Speter if (modfind("nfsserver") < 0) { 28783687Speter /* Not present in kernel, try loading it */ 28883687Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 28983687Speter errx(1, "NFS server is not available or loadable"); 2902999Swollman } 2912999Swollman 292172827Smatteo while ((c = getopt(argc, argv, "2dh:lnp:r")) != -1) 2931558Srgrimes switch (c) { 29425087Sdfr case '2': 29525087Sdfr force_v2 = 1; 29625087Sdfr break; 2979336Sdfr case 'n': 2989336Sdfr resvport_only = 0; 2999336Sdfr break; 3009336Sdfr case 'r': 3019336Sdfr dir_only = 0; 3029336Sdfr break; 3038688Sphk case 'd': 3048688Sphk debug = debug ? 0 : 1; 3058688Sphk break; 30631656Sguido case 'l': 307121767Speter dolog = 1; 30831656Sguido break; 309126572Sbms case 'p': 310126572Sbms endptr = NULL; 311126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 312126572Sbms if (endptr == NULL || *endptr != '\0' || 313126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 314126572Sbms usage(); 315172827Smatteo svcport_str = strdup(optarg); 316126572Sbms break; 317172827Smatteo case 'h': 318172827Smatteo ++nhosts; 319172827Smatteo hosts_bak = hosts; 320172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 321172827Smatteo if (hosts_bak == NULL) { 322172827Smatteo if (hosts != NULL) { 323172827Smatteo for (k = 0; k < nhosts; k++) 324172827Smatteo free(hosts[k]); 325172827Smatteo free(hosts); 326172827Smatteo out_of_mem(); 327172827Smatteo } 328172827Smatteo } 329172827Smatteo hosts = hosts_bak; 330172827Smatteo hosts[nhosts - 1] = strdup(optarg); 331172827Smatteo if (hosts[nhosts - 1] == NULL) { 332172827Smatteo for (k = 0; k < (nhosts - 1); k++) 333172827Smatteo free(hosts[k]); 334172827Smatteo free(hosts); 335172827Smatteo out_of_mem(); 336172827Smatteo } 337172827Smatteo break; 3381558Srgrimes default: 33937663Scharnier usage(); 3401558Srgrimes }; 3411558Srgrimes argc -= optind; 3421558Srgrimes argv += optind; 3431558Srgrimes grphead = (struct grouplist *)NULL; 3441558Srgrimes exphead = (struct exportlist *)NULL; 3451558Srgrimes mlhead = (struct mountlist *)NULL; 346166440Spjd if (argc > 0) 347166440Spjd exnames = argv; 348166440Spjd else 349166440Spjd exnames = exnames_default; 3501558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3511558Srgrimes if (debug) 35237663Scharnier warnx("getting export list"); 3531558Srgrimes get_exportlist(); 3541558Srgrimes if (debug) 35537663Scharnier warnx("getting mount list"); 3561558Srgrimes get_mountlist(); 3571558Srgrimes if (debug) 35837663Scharnier warnx("here we go"); 3591558Srgrimes if (debug == 0) { 3601558Srgrimes daemon(0, 0); 3611558Srgrimes signal(SIGINT, SIG_IGN); 3621558Srgrimes signal(SIGQUIT, SIG_IGN); 3631558Srgrimes } 36475754Siedowse signal(SIGHUP, huphandler); 36574462Salfred signal(SIGTERM, terminate); 366164394Srodrigc signal(SIGPIPE, SIG_IGN); 367149433Spjd 368149433Spjd pidfile_write(pfh); 369149433Spjd 37074462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 37174462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 372109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 373109363Smbr 37424759Sguido if (!resvport_only) { 37583687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 37683687Speter &resvport_only, sizeof(resvport_only)) != 0 && 37783687Speter errno != ENOENT) { 37824759Sguido syslog(LOG_ERR, "sysctl: %m"); 37924759Sguido exit(1); 38024759Sguido } 38124330Sguido } 382126572Sbms 383172827Smatteo /* 384172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 385172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 386172827Smatteo * list. 387172827Smatteo */ 388172827Smatteo if (nhosts == 0) { 389172827Smatteo hosts = malloc(sizeof(char**)); 390172827Smatteo if (hosts == NULL) 391172827Smatteo out_of_mem(); 392172827Smatteo hosts[0] = "*"; 393172827Smatteo nhosts = 1; 394172827Smatteo } else { 395172827Smatteo hosts_bak = hosts; 396172827Smatteo if (have_v6) { 397172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 398172827Smatteo sizeof(char *)); 399172827Smatteo if (hosts_bak == NULL) { 400172827Smatteo for (k = 0; k < nhosts; k++) 401172827Smatteo free(hosts[k]); 402172827Smatteo free(hosts); 403172827Smatteo out_of_mem(); 404172827Smatteo } else 405172827Smatteo hosts = hosts_bak; 406172827Smatteo nhosts += 2; 407172827Smatteo hosts[nhosts - 2] = "::1"; 408172827Smatteo } else { 409172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 410172827Smatteo if (hosts_bak == NULL) { 411172827Smatteo for (k = 0; k < nhosts; k++) 412172827Smatteo free(hosts[k]); 413172827Smatteo free(hosts); 414172827Smatteo out_of_mem(); 415172827Smatteo } else { 416172827Smatteo nhosts += 1; 417172827Smatteo hosts = hosts_bak; 418126572Sbms } 419172827Smatteo } 42074462Salfred 421172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 42274462Salfred } 42374462Salfred 424172827Smatteo nc_handle = setnetconfig(); 425172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 426172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 427172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 428172827Smatteo "inet6") == 0) { 429172827Smatteo /* DO NOTHING */ 430172827Smatteo } else 431172827Smatteo create_service(nconf); 432172827Smatteo } 43374462Salfred } 434172827Smatteo endnetconfig(nc_handle); 43574462Salfred 43674462Salfred if (xcreated == 0) { 43774462Salfred syslog(LOG_ERR, "could not create any services"); 4381558Srgrimes exit(1); 4391558Srgrimes } 44075754Siedowse 44175754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 44275754Siedowse for (;;) { 44375754Siedowse if (got_sighup) { 44475754Siedowse get_exportlist(); 44575754Siedowse got_sighup = 0; 44675754Siedowse } 44775754Siedowse readfds = svc_fdset; 44875754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 44975754Siedowse case -1: 45075754Siedowse if (errno == EINTR) 45175754Siedowse continue; 45275754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 45375754Siedowse exit(1); 45475754Siedowse case 0: 45575754Siedowse continue; 45675754Siedowse default: 45775754Siedowse svc_getreqset(&readfds); 45875754Siedowse } 45975754Siedowse } 460172827Smatteo} 461172827Smatteo 462172827Smatteo/* 463172827Smatteo * This routine creates and binds sockets on the appropriate 464172827Smatteo * addresses. It gets called one time for each transport and 465172827Smatteo * registrates the service with rpcbind on that trasport. 466172827Smatteo */ 467172827Smatteovoid 468172827Smatteocreate_service(struct netconfig *nconf) 469172827Smatteo{ 470172827Smatteo struct addrinfo hints, *res = NULL; 471172827Smatteo struct sockaddr_in *sin; 472172827Smatteo struct sockaddr_in6 *sin6; 473172827Smatteo struct __rpc_sockinfo si; 474172827Smatteo struct netbuf servaddr; 475172827Smatteo SVCXPRT *transp = NULL; 476172827Smatteo int aicode; 477172827Smatteo int fd; 478172827Smatteo int nhostsbak; 479172827Smatteo int one = 1; 480172827Smatteo int r; 481172827Smatteo int registered = 0; 482172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 483172827Smatteo 484172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 485172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 486172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 487172827Smatteo return; /* not my type */ 488172827Smatteo 489172827Smatteo /* 490172827Smatteo * XXX - using RPC library internal functions. 491172827Smatteo */ 492172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 493172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 494172827Smatteo nconf->nc_netid); 495172827Smatteo return; 496172827Smatteo } 497172827Smatteo 498172827Smatteo /* Get mountd's address on this transport */ 499172827Smatteo memset(&hints, 0, sizeof hints); 500172827Smatteo hints.ai_flags = AI_PASSIVE; 501172827Smatteo hints.ai_family = si.si_af; 502172827Smatteo hints.ai_socktype = si.si_socktype; 503172827Smatteo hints.ai_protocol = si.si_proto; 504172827Smatteo 505172827Smatteo /* 506172827Smatteo * Bind to specific IPs if asked to 507172827Smatteo */ 508172827Smatteo nhostsbak = nhosts; 509172827Smatteo while (nhostsbak > 0) { 510172827Smatteo --nhostsbak; 511172827Smatteo /* 512172827Smatteo * XXX - using RPC library internal functions. 513172827Smatteo */ 514172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 515172827Smatteo int non_fatal = 0; 516172827Smatteo if (errno == EPROTONOSUPPORT && 517172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 518172827Smatteo non_fatal = 1; 519172827Smatteo 520172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 521172827Smatteo "cannot create socket for %s", nconf->nc_netid); 522172827Smatteo return; 523172827Smatteo } 524172827Smatteo 525172827Smatteo switch (hints.ai_family) { 526172827Smatteo case AF_INET: 527172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 528172827Smatteo host_addr) == 1) { 529172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 530172827Smatteo } else { 531172827Smatteo /* 532172827Smatteo * Skip if we have an AF_INET6 address. 533172827Smatteo */ 534172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 535172827Smatteo host_addr) == 1) { 536172827Smatteo close(fd); 537172827Smatteo continue; 538172827Smatteo } 539172827Smatteo } 540172827Smatteo break; 541172827Smatteo case AF_INET6: 542172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 543172827Smatteo host_addr) == 1) { 544172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 545172827Smatteo } else { 546172827Smatteo /* 547172827Smatteo * Skip if we have an AF_INET address. 548172827Smatteo */ 549172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 550172827Smatteo host_addr) == 1) { 551172827Smatteo close(fd); 552172827Smatteo continue; 553172827Smatteo } 554172827Smatteo } 555172827Smatteo 556172827Smatteo /* 557172827Smatteo * We're doing host-based access checks here, so don't 558172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 559172827Smatteo * disable it by default on NFS sockets too. 560172827Smatteo */ 561172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 562172827Smatteo sizeof one) < 0) { 563172827Smatteo syslog(LOG_ERR, 564172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 565172827Smatteo exit(1); 566172827Smatteo } 567172827Smatteo break; 568172827Smatteo default: 569172827Smatteo break; 570172827Smatteo } 571172827Smatteo 572172827Smatteo /* 573172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 574172827Smatteo */ 575172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 576172827Smatteo if (svcport_str == NULL) { 577172827Smatteo res = malloc(sizeof(struct addrinfo)); 578172827Smatteo if (res == NULL) 579172827Smatteo out_of_mem(); 580172827Smatteo res->ai_flags = hints.ai_flags; 581172827Smatteo res->ai_family = hints.ai_family; 582172827Smatteo res->ai_protocol = hints.ai_protocol; 583172827Smatteo switch (res->ai_family) { 584172827Smatteo case AF_INET: 585172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 586172827Smatteo if (sin == NULL) 587172827Smatteo out_of_mem(); 588172827Smatteo sin->sin_family = AF_INET; 589172827Smatteo sin->sin_port = htons(0); 590172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 591172827Smatteo res->ai_addr = (struct sockaddr*) sin; 592172827Smatteo res->ai_addrlen = (socklen_t) 593172827Smatteo sizeof(res->ai_addr); 594172827Smatteo break; 595172827Smatteo case AF_INET6: 596172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 597173056Ssimon if (sin6 == NULL) 598172827Smatteo out_of_mem(); 599172827Smatteo sin6->sin6_family = AF_INET6; 600172827Smatteo sin6->sin6_port = htons(0); 601172827Smatteo sin6->sin6_addr = in6addr_any; 602172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 603172827Smatteo res->ai_addrlen = (socklen_t) 604172827Smatteo sizeof(res->ai_addr); 605172827Smatteo break; 606172827Smatteo default: 607172827Smatteo break; 608172827Smatteo } 609172827Smatteo } else { 610172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 611172827Smatteo &hints, &res)) != 0) { 612172827Smatteo syslog(LOG_ERR, 613172827Smatteo "cannot get local address for %s: %s", 614172827Smatteo nconf->nc_netid, 615172827Smatteo gai_strerror(aicode)); 616172827Smatteo continue; 617172827Smatteo } 618172827Smatteo } 619172827Smatteo } else { 620172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 621172827Smatteo &hints, &res)) != 0) { 622172827Smatteo syslog(LOG_ERR, 623172827Smatteo "cannot get local address for %s: %s", 624172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 625172827Smatteo continue; 626172827Smatteo } 627172827Smatteo } 628172827Smatteo 629172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 630172827Smatteo if (r != 0) { 631172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 632172827Smatteo exit(1); 633172827Smatteo } 634172827Smatteo 635172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 636172827Smatteo listen(fd, SOMAXCONN); 637172827Smatteo 638172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 639172827Smatteo transp = svc_dg_create(fd, 0, 0); 640172827Smatteo else 641172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 642172827Smatteo RPC_MAXDATASIZE); 643172827Smatteo 644172827Smatteo if (transp != (SVCXPRT *) NULL) { 645172827Smatteo if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 646172827Smatteo NULL)) 647172827Smatteo syslog(LOG_ERR, 648172827Smatteo "can't register %s RPCMNT_VER1 service", 649172827Smatteo nconf->nc_netid); 650172827Smatteo if (!force_v2) { 651172827Smatteo if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER3, 652172827Smatteo mntsrv, NULL)) 653172827Smatteo syslog(LOG_ERR, 654172827Smatteo "can't register %s RPCMNT_VER3 service", 655172827Smatteo nconf->nc_netid); 656172827Smatteo } 657172827Smatteo } else 658172827Smatteo syslog(LOG_WARNING, "can't create %s services", 659172827Smatteo nconf->nc_netid); 660172827Smatteo 661172827Smatteo if (registered == 0) { 662172827Smatteo registered = 1; 663172827Smatteo memset(&hints, 0, sizeof hints); 664172827Smatteo hints.ai_flags = AI_PASSIVE; 665172827Smatteo hints.ai_family = si.si_af; 666172827Smatteo hints.ai_socktype = si.si_socktype; 667172827Smatteo hints.ai_protocol = si.si_proto; 668172827Smatteo 669172827Smatteo if (svcport_str == NULL) { 670172827Smatteo svcport_str = malloc(NI_MAXSERV * sizeof(char)); 671172827Smatteo if (svcport_str == NULL) 672172827Smatteo out_of_mem(); 673172827Smatteo 674172827Smatteo if (getnameinfo(res->ai_addr, 675172827Smatteo res->ai_addr->sa_len, NULL, NI_MAXHOST, 676172827Smatteo svcport_str, NI_MAXSERV * sizeof(char), 677172827Smatteo NI_NUMERICHOST | NI_NUMERICSERV)) 678172827Smatteo errx(1, "Cannot get port number"); 679172827Smatteo } 680172827Smatteo 681172827Smatteo if((aicode = getaddrinfo(NULL, svcport_str, &hints, 682172827Smatteo &res)) != 0) { 683172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 684172827Smatteo gai_strerror(aicode)); 685172827Smatteo exit(1); 686172827Smatteo } 687172827Smatteo 688172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 689172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 690172827Smatteo servaddr.len = res->ai_addrlen; 691172827Smatteo 692172827Smatteo rpcb_set(RPCPROG_MNT, RPCMNT_VER1, nconf, &servaddr); 693172827Smatteo rpcb_set(RPCPROG_MNT, RPCMNT_VER3, nconf, &servaddr); 694172827Smatteo 695172827Smatteo xcreated++; 696172827Smatteo freeaddrinfo(res); 697172827Smatteo } 698172827Smatteo } /* end while */ 6991558Srgrimes} 7001558Srgrimes 70137663Scharnierstatic void 70237663Scharnierusage() 70337663Scharnier{ 70437663Scharnier fprintf(stderr, 705126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 706172827Smatteo "[-h <bindip>] [export_file ...]\n"); 70737663Scharnier exit(1); 70837663Scharnier} 70937663Scharnier 7101558Srgrimes/* 7111558Srgrimes * The mount rpc service 7121558Srgrimes */ 7131558Srgrimesvoid 7141558Srgrimesmntsrv(rqstp, transp) 7151558Srgrimes struct svc_req *rqstp; 7161558Srgrimes SVCXPRT *transp; 7171558Srgrimes{ 7181558Srgrimes struct exportlist *ep; 7191558Srgrimes struct dirlist *dp; 7209336Sdfr struct fhreturn fhr; 7211558Srgrimes struct stat stb; 7221558Srgrimes struct statfs fsb; 72374462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 72474462Salfred int lookup_failed = 1; 72574462Salfred struct sockaddr *saddr; 7269336Sdfr u_short sport; 72723681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 72828911Sguido int bad = 0, defset, hostset; 7299336Sdfr sigset_t sighup_mask; 7301558Srgrimes 7319336Sdfr sigemptyset(&sighup_mask); 7329336Sdfr sigaddset(&sighup_mask, SIGHUP); 73374462Salfred saddr = svc_getrpccaller(transp)->buf; 73474462Salfred switch (saddr->sa_family) { 73574462Salfred case AF_INET6: 73675635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 73774462Salfred break; 73874462Salfred case AF_INET: 73975635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 74074462Salfred break; 74174462Salfred default: 74274462Salfred syslog(LOG_ERR, "request from unknown address family"); 74374462Salfred return; 74474462Salfred } 74574462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 74674462Salfred NULL, 0, 0); 74774462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 74874462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 7491558Srgrimes switch (rqstp->rq_proc) { 7501558Srgrimes case NULLPROC: 751121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 75237663Scharnier syslog(LOG_ERR, "can't send reply"); 7531558Srgrimes return; 7541558Srgrimes case RPCMNT_MOUNT: 7559336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 75631656Sguido syslog(LOG_NOTICE, 75731656Sguido "mount request from %s from unprivileged port", 75874462Salfred numerichost); 7591558Srgrimes svcerr_weakauth(transp); 7601558Srgrimes return; 7611558Srgrimes } 762121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 76331656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 76474462Salfred numerichost); 7651558Srgrimes svcerr_decode(transp); 7661558Srgrimes return; 7671558Srgrimes } 7681558Srgrimes 7691558Srgrimes /* 7701558Srgrimes * Get the real pathname and make sure it is a directory 7719336Sdfr * or a regular file if the -r option was specified 7729336Sdfr * and it exists. 7731558Srgrimes */ 77451968Salfred if (realpath(rpcpath, dirpath) == NULL || 7751558Srgrimes stat(dirpath, &stb) < 0 || 7769336Sdfr (!S_ISDIR(stb.st_mode) && 77774462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 7781558Srgrimes statfs(dirpath, &fsb) < 0) { 7791558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 78031656Sguido syslog(LOG_NOTICE, 78137663Scharnier "mount request from %s for non existent path %s", 78274462Salfred numerichost, dirpath); 7831558Srgrimes if (debug) 78437663Scharnier warnx("stat failed on %s", dirpath); 78528911Sguido bad = ENOENT; /* We will send error reply later */ 7861558Srgrimes } 7871558Srgrimes 7881558Srgrimes /* Check in the exports list */ 7899336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 7901558Srgrimes ep = ex_search(&fsb.f_fsid); 7919336Sdfr hostset = defset = 0; 7929336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 7931558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 79474462Salfred chk_host(dp, saddr, &defset, &hostset)) || 79574462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 79674462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 79728911Sguido if (bad) { 798121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 79928911Sguido (caddr_t)&bad)) 80037663Scharnier syslog(LOG_ERR, "can't send reply"); 80128911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 80228911Sguido return; 80328911Sguido } 8049336Sdfr if (hostset & DP_HOSTSET) 8059336Sdfr fhr.fhr_flag = hostset; 8069336Sdfr else 8079336Sdfr fhr.fhr_flag = defset; 8089336Sdfr fhr.fhr_vers = rqstp->rq_vers; 8091558Srgrimes /* Get the file handle */ 81023681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 8119336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 8121558Srgrimes bad = errno; 81337663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 814121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 8151558Srgrimes (caddr_t)&bad)) 81637663Scharnier syslog(LOG_ERR, "can't send reply"); 8179336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8181558Srgrimes return; 8191558Srgrimes } 820121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 821121556Speter (caddr_t)&fhr)) 82237663Scharnier syslog(LOG_ERR, "can't send reply"); 82374462Salfred if (!lookup_failed) 82474462Salfred add_mlist(host, dirpath); 8251558Srgrimes else 82674462Salfred add_mlist(numerichost, dirpath); 8271558Srgrimes if (debug) 82837663Scharnier warnx("mount successful"); 829121767Speter if (dolog) 83031656Sguido syslog(LOG_NOTICE, 83131656Sguido "mount request succeeded from %s for %s", 83274462Salfred numerichost, dirpath); 83331656Sguido } else { 8341558Srgrimes bad = EACCES; 83531656Sguido syslog(LOG_NOTICE, 83631656Sguido "mount request denied from %s for %s", 83774462Salfred numerichost, dirpath); 83831656Sguido } 83928911Sguido 840121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 841121556Speter (caddr_t)&bad)) 84237663Scharnier syslog(LOG_ERR, "can't send reply"); 8439336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8441558Srgrimes return; 8451558Srgrimes case RPCMNT_DUMP: 846121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 84737663Scharnier syslog(LOG_ERR, "can't send reply"); 848121767Speter else if (dolog) 84931656Sguido syslog(LOG_NOTICE, 85031656Sguido "dump request succeeded from %s", 85174462Salfred numerichost); 8521558Srgrimes return; 8531558Srgrimes case RPCMNT_UMOUNT: 8549336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 85531656Sguido syslog(LOG_NOTICE, 85631656Sguido "umount request from %s from unprivileged port", 85774462Salfred numerichost); 8581558Srgrimes svcerr_weakauth(transp); 8591558Srgrimes return; 8601558Srgrimes } 861121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 86231656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 86374462Salfred numerichost); 8641558Srgrimes svcerr_decode(transp); 8651558Srgrimes return; 8661558Srgrimes } 86751968Salfred if (realpath(rpcpath, dirpath) == NULL) { 86851968Salfred syslog(LOG_NOTICE, "umount request from %s " 86951968Salfred "for non existent path %s", 87074462Salfred numerichost, dirpath); 87151968Salfred } 872121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 87337663Scharnier syslog(LOG_ERR, "can't send reply"); 87474462Salfred if (!lookup_failed) 87575635Siedowse del_mlist(host, dirpath); 87675635Siedowse del_mlist(numerichost, dirpath); 877121767Speter if (dolog) 87831656Sguido syslog(LOG_NOTICE, 87931656Sguido "umount request succeeded from %s for %s", 88074462Salfred numerichost, dirpath); 8811558Srgrimes return; 8821558Srgrimes case RPCMNT_UMNTALL: 8839336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 88431656Sguido syslog(LOG_NOTICE, 88531656Sguido "umountall request from %s from unprivileged port", 88674462Salfred numerichost); 8871558Srgrimes svcerr_weakauth(transp); 8881558Srgrimes return; 8891558Srgrimes } 890121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 89137663Scharnier syslog(LOG_ERR, "can't send reply"); 89274462Salfred if (!lookup_failed) 89375635Siedowse del_mlist(host, NULL); 89475635Siedowse del_mlist(numerichost, NULL); 895121767Speter if (dolog) 89631656Sguido syslog(LOG_NOTICE, 89731656Sguido "umountall request succeeded from %s", 89874462Salfred numerichost); 8991558Srgrimes return; 9001558Srgrimes case RPCMNT_EXPORT: 901121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 902121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 903121556Speter (caddr_t)NULL)) 904100117Salfred syslog(LOG_ERR, "can't send reply"); 905121767Speter if (dolog) 90631656Sguido syslog(LOG_NOTICE, 90731656Sguido "export request succeeded from %s", 90874462Salfred numerichost); 9091558Srgrimes return; 9101558Srgrimes default: 9111558Srgrimes svcerr_noproc(transp); 9121558Srgrimes return; 9131558Srgrimes } 9141558Srgrimes} 9151558Srgrimes 9161558Srgrimes/* 9171558Srgrimes * Xdr conversion for a dirpath string 9181558Srgrimes */ 9191558Srgrimesint 9201558Srgrimesxdr_dir(xdrsp, dirp) 9211558Srgrimes XDR *xdrsp; 9221558Srgrimes char *dirp; 9231558Srgrimes{ 9241558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 9251558Srgrimes} 9261558Srgrimes 9271558Srgrimes/* 9289336Sdfr * Xdr routine to generate file handle reply 9291558Srgrimes */ 9301558Srgrimesint 9319336Sdfrxdr_fhs(xdrsp, cp) 9321558Srgrimes XDR *xdrsp; 9339336Sdfr caddr_t cp; 9341558Srgrimes{ 93592806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 9369336Sdfr u_long ok = 0, len, auth; 9371558Srgrimes 9381558Srgrimes if (!xdr_long(xdrsp, &ok)) 9391558Srgrimes return (0); 9409336Sdfr switch (fhrp->fhr_vers) { 9419336Sdfr case 1: 9429336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 9439336Sdfr case 3: 9449336Sdfr len = NFSX_V3FH; 9459336Sdfr if (!xdr_long(xdrsp, &len)) 9469336Sdfr return (0); 9479336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 9489336Sdfr return (0); 94983653Speter auth = RPCAUTH_UNIX; 9509336Sdfr len = 1; 9519336Sdfr if (!xdr_long(xdrsp, &len)) 9529336Sdfr return (0); 9539336Sdfr return (xdr_long(xdrsp, &auth)); 9549336Sdfr }; 9559336Sdfr return (0); 9561558Srgrimes} 9571558Srgrimes 9581558Srgrimesint 9591558Srgrimesxdr_mlist(xdrsp, cp) 9601558Srgrimes XDR *xdrsp; 9611558Srgrimes caddr_t cp; 9621558Srgrimes{ 9631558Srgrimes struct mountlist *mlp; 9641558Srgrimes int true = 1; 9651558Srgrimes int false = 0; 9661558Srgrimes char *strp; 9671558Srgrimes 9681558Srgrimes mlp = mlhead; 9691558Srgrimes while (mlp) { 9701558Srgrimes if (!xdr_bool(xdrsp, &true)) 9711558Srgrimes return (0); 9721558Srgrimes strp = &mlp->ml_host[0]; 9731558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 9741558Srgrimes return (0); 9751558Srgrimes strp = &mlp->ml_dirp[0]; 9761558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 9771558Srgrimes return (0); 9781558Srgrimes mlp = mlp->ml_next; 9791558Srgrimes } 9801558Srgrimes if (!xdr_bool(xdrsp, &false)) 9811558Srgrimes return (0); 9821558Srgrimes return (1); 9831558Srgrimes} 9841558Srgrimes 9851558Srgrimes/* 9861558Srgrimes * Xdr conversion for export list 9871558Srgrimes */ 9881558Srgrimesint 989100117Salfredxdr_explist_common(xdrsp, cp, brief) 9901558Srgrimes XDR *xdrsp; 9911558Srgrimes caddr_t cp; 992100117Salfred int brief; 9931558Srgrimes{ 9941558Srgrimes struct exportlist *ep; 9951558Srgrimes int false = 0; 9969336Sdfr int putdef; 9979336Sdfr sigset_t sighup_mask; 9981558Srgrimes 9999336Sdfr sigemptyset(&sighup_mask); 10009336Sdfr sigaddset(&sighup_mask, SIGHUP); 10019336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10021558Srgrimes ep = exphead; 10031558Srgrimes while (ep) { 10041558Srgrimes putdef = 0; 1005100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1006100117Salfred &putdef, brief)) 10071558Srgrimes goto errout; 10081558Srgrimes if (ep->ex_defdir && putdef == 0 && 10091558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1010100117Salfred &putdef, brief)) 10111558Srgrimes goto errout; 10121558Srgrimes ep = ep->ex_next; 10131558Srgrimes } 10149336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10151558Srgrimes if (!xdr_bool(xdrsp, &false)) 10161558Srgrimes return (0); 10171558Srgrimes return (1); 10181558Srgrimeserrout: 10199336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10201558Srgrimes return (0); 10211558Srgrimes} 10221558Srgrimes 10231558Srgrimes/* 10241558Srgrimes * Called from xdr_explist() to traverse the tree and export the 10251558Srgrimes * directory paths. 10261558Srgrimes */ 10271558Srgrimesint 1028100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 10291558Srgrimes struct dirlist *dp; 10301558Srgrimes XDR *xdrsp; 10311558Srgrimes struct dirlist *adp; 10321558Srgrimes int *putdefp; 1033100117Salfred int brief; 10341558Srgrimes{ 10351558Srgrimes struct grouplist *grp; 10361558Srgrimes struct hostlist *hp; 10371558Srgrimes int true = 1; 10381558Srgrimes int false = 0; 10391558Srgrimes int gotalldir = 0; 10401558Srgrimes char *strp; 10411558Srgrimes 10421558Srgrimes if (dp) { 1043100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 10441558Srgrimes return (1); 10451558Srgrimes if (!xdr_bool(xdrsp, &true)) 10461558Srgrimes return (1); 10471558Srgrimes strp = dp->dp_dirp; 10481558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 10491558Srgrimes return (1); 10501558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 10511558Srgrimes gotalldir = 1; 10521558Srgrimes *putdefp = 1; 10531558Srgrimes } 1054100117Salfred if (brief) { 1055100117Salfred if (!xdr_bool(xdrsp, &true)) 1056100117Salfred return (1); 1057100117Salfred strp = "(...)"; 1058100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1059100117Salfred return (1); 1060100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 10611558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 10621558Srgrimes hp = dp->dp_hosts; 10631558Srgrimes while (hp) { 10641558Srgrimes grp = hp->ht_grp; 10651558Srgrimes if (grp->gr_type == GT_HOST) { 10661558Srgrimes if (!xdr_bool(xdrsp, &true)) 10671558Srgrimes return (1); 106874462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 10698871Srgrimes if (!xdr_string(xdrsp, &strp, 10701558Srgrimes RPCMNT_NAMELEN)) 10711558Srgrimes return (1); 10721558Srgrimes } else if (grp->gr_type == GT_NET) { 10731558Srgrimes if (!xdr_bool(xdrsp, &true)) 10741558Srgrimes return (1); 10751558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 10768871Srgrimes if (!xdr_string(xdrsp, &strp, 10771558Srgrimes RPCMNT_NAMELEN)) 10781558Srgrimes return (1); 10791558Srgrimes } 10801558Srgrimes hp = hp->ht_next; 10811558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 10821558Srgrimes hp = adp->dp_hosts; 10831558Srgrimes gotalldir = 0; 10841558Srgrimes } 10851558Srgrimes } 10861558Srgrimes } 10871558Srgrimes if (!xdr_bool(xdrsp, &false)) 10881558Srgrimes return (1); 1089100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 10901558Srgrimes return (1); 10911558Srgrimes } 10921558Srgrimes return (0); 10931558Srgrimes} 10941558Srgrimes 1095100117Salfredint 1096100117Salfredxdr_explist(xdrsp, cp) 1097100117Salfred XDR *xdrsp; 1098100117Salfred caddr_t cp; 1099100117Salfred{ 1100100117Salfred 1101100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1102100117Salfred} 1103100117Salfred 1104100117Salfredint 1105100117Salfredxdr_explist_brief(xdrsp, cp) 1106100117Salfred XDR *xdrsp; 1107100117Salfred caddr_t cp; 1108100117Salfred{ 1109100117Salfred 1110100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1111100117Salfred} 1112100117Salfred 111396622Siedowsechar *line; 111496622Siedowseint linesize; 11151558SrgrimesFILE *exp_file; 11161558Srgrimes 11171558Srgrimes/* 1118166440Spjd * Get the export list from one, currently open file 11191558Srgrimes */ 1120166440Spjdstatic void 1121166440Spjdget_exportlist_one() 11221558Srgrimes{ 11231558Srgrimes struct exportlist *ep, *ep2; 11241558Srgrimes struct grouplist *grp, *tgrp; 11251558Srgrimes struct exportlist **epp; 11261558Srgrimes struct dirlist *dirhead; 1127166440Spjd struct statfs fsb; 112872650Sgreen struct xucred anon; 11291558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1130166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 11311558Srgrimes 11321558Srgrimes dirhead = (struct dirlist *)NULL; 11331558Srgrimes while (get_line()) { 11341558Srgrimes if (debug) 113537663Scharnier warnx("got line %s", line); 11361558Srgrimes cp = line; 11371558Srgrimes nextfield(&cp, &endcp); 11381558Srgrimes if (*cp == '#') 11391558Srgrimes goto nextline; 11401558Srgrimes 11411558Srgrimes /* 11421558Srgrimes * Set defaults. 11431558Srgrimes */ 11441558Srgrimes has_host = FALSE; 11451558Srgrimes anon = def_anon; 11461558Srgrimes exflags = MNT_EXPORTED; 11471558Srgrimes got_nondir = 0; 11481558Srgrimes opt_flags = 0; 11491558Srgrimes ep = (struct exportlist *)NULL; 11501558Srgrimes 11511558Srgrimes /* 11521558Srgrimes * Create new exports list entry 11531558Srgrimes */ 11541558Srgrimes len = endcp-cp; 11551558Srgrimes tgrp = grp = get_grp(); 11561558Srgrimes while (len > 0) { 11571558Srgrimes if (len > RPCMNT_NAMELEN) { 11581558Srgrimes getexp_err(ep, tgrp); 11591558Srgrimes goto nextline; 11601558Srgrimes } 11611558Srgrimes if (*cp == '-') { 11621558Srgrimes if (ep == (struct exportlist *)NULL) { 11631558Srgrimes getexp_err(ep, tgrp); 11641558Srgrimes goto nextline; 11651558Srgrimes } 11661558Srgrimes if (debug) 116737663Scharnier warnx("doing opt %s", cp); 11681558Srgrimes got_nondir = 1; 11691558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 11701558Srgrimes &exflags, &anon)) { 11711558Srgrimes getexp_err(ep, tgrp); 11721558Srgrimes goto nextline; 11731558Srgrimes } 11741558Srgrimes } else if (*cp == '/') { 11751558Srgrimes savedc = *endcp; 11761558Srgrimes *endcp = '\0'; 11771558Srgrimes if (check_dirpath(cp) && 11781558Srgrimes statfs(cp, &fsb) >= 0) { 11791558Srgrimes if (got_nondir) { 118037663Scharnier syslog(LOG_ERR, "dirs must be first"); 11811558Srgrimes getexp_err(ep, tgrp); 11821558Srgrimes goto nextline; 11831558Srgrimes } 11841558Srgrimes if (ep) { 11851558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 11861558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 11871558Srgrimes getexp_err(ep, tgrp); 11881558Srgrimes goto nextline; 11891558Srgrimes } 11901558Srgrimes } else { 11911558Srgrimes /* 11921558Srgrimes * See if this directory is already 11931558Srgrimes * in the list. 11941558Srgrimes */ 11951558Srgrimes ep = ex_search(&fsb.f_fsid); 11961558Srgrimes if (ep == (struct exportlist *)NULL) { 11971558Srgrimes ep = get_exp(); 11981558Srgrimes ep->ex_fs = fsb.f_fsid; 11991558Srgrimes ep->ex_fsdir = (char *) 12001558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 12011558Srgrimes if (ep->ex_fsdir) 12021558Srgrimes strcpy(ep->ex_fsdir, 12031558Srgrimes fsb.f_mntonname); 12041558Srgrimes else 12051558Srgrimes out_of_mem(); 12061558Srgrimes if (debug) 120774462Salfred warnx("making new ep fs=0x%x,0x%x", 120874462Salfred fsb.f_fsid.val[0], 120974462Salfred fsb.f_fsid.val[1]); 12101558Srgrimes } else if (debug) 121137663Scharnier warnx("found ep fs=0x%x,0x%x", 12121558Srgrimes fsb.f_fsid.val[0], 12131558Srgrimes fsb.f_fsid.val[1]); 12141558Srgrimes } 12151558Srgrimes 12161558Srgrimes /* 12171558Srgrimes * Add dirpath to export mount point. 12181558Srgrimes */ 12191558Srgrimes dirp = add_expdir(&dirhead, cp, len); 12201558Srgrimes dirplen = len; 12211558Srgrimes } else { 12221558Srgrimes getexp_err(ep, tgrp); 12231558Srgrimes goto nextline; 12241558Srgrimes } 12251558Srgrimes *endcp = savedc; 12261558Srgrimes } else { 12271558Srgrimes savedc = *endcp; 12281558Srgrimes *endcp = '\0'; 12291558Srgrimes got_nondir = 1; 12301558Srgrimes if (ep == (struct exportlist *)NULL) { 12311558Srgrimes getexp_err(ep, tgrp); 12321558Srgrimes goto nextline; 12331558Srgrimes } 12341558Srgrimes 12351558Srgrimes /* 12361558Srgrimes * Get the host or netgroup. 12371558Srgrimes */ 12381558Srgrimes setnetgrent(cp); 12391558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 12401558Srgrimes do { 12411558Srgrimes if (has_host) { 12421558Srgrimes grp->gr_next = get_grp(); 12431558Srgrimes grp = grp->gr_next; 12441558Srgrimes } 12451558Srgrimes if (netgrp) { 124637003Sjoerg if (hst == 0) { 124737663Scharnier syslog(LOG_ERR, 124837663Scharnier "null hostname in netgroup %s, skipping", cp); 124937004Sjoerg grp->gr_type = GT_IGNORE; 125037003Sjoerg } else if (get_host(hst, grp, tgrp)) { 125137663Scharnier syslog(LOG_ERR, 125237663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 125329317Sjlemon grp->gr_type = GT_IGNORE; 12541558Srgrimes } 12557401Swpaul } else if (get_host(cp, grp, tgrp)) { 125637663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 125729317Sjlemon grp->gr_type = GT_IGNORE; 12581558Srgrimes } 12591558Srgrimes has_host = TRUE; 12601558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 12611558Srgrimes endnetgrent(); 12621558Srgrimes *endcp = savedc; 12631558Srgrimes } 12641558Srgrimes cp = endcp; 12651558Srgrimes nextfield(&cp, &endcp); 12661558Srgrimes len = endcp - cp; 12671558Srgrimes } 12681558Srgrimes if (check_options(dirhead)) { 12691558Srgrimes getexp_err(ep, tgrp); 12701558Srgrimes goto nextline; 12711558Srgrimes } 12721558Srgrimes if (!has_host) { 127375641Siedowse grp->gr_type = GT_DEFAULT; 12741558Srgrimes if (debug) 127537663Scharnier warnx("adding a default entry"); 12761558Srgrimes 12771558Srgrimes /* 12781558Srgrimes * Don't allow a network export coincide with a list of 12791558Srgrimes * host(s) on the same line. 12801558Srgrimes */ 12811558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 128275801Siedowse syslog(LOG_ERR, "network/host conflict"); 12831558Srgrimes getexp_err(ep, tgrp); 12841558Srgrimes goto nextline; 128529317Sjlemon 128674462Salfred /* 128774462Salfred * If an export list was specified on this line, make sure 128829317Sjlemon * that we have at least one valid entry, otherwise skip it. 128929317Sjlemon */ 129029317Sjlemon } else { 129129317Sjlemon grp = tgrp; 129274462Salfred while (grp && grp->gr_type == GT_IGNORE) 129329317Sjlemon grp = grp->gr_next; 129429317Sjlemon if (! grp) { 129529317Sjlemon getexp_err(ep, tgrp); 129629317Sjlemon goto nextline; 129729317Sjlemon } 12981558Srgrimes } 12991558Srgrimes 13001558Srgrimes /* 13011558Srgrimes * Loop through hosts, pushing the exports into the kernel. 13021558Srgrimes * After loop, tgrp points to the start of the list and 13031558Srgrimes * grp points to the last entry in the list. 13041558Srgrimes */ 13051558Srgrimes grp = tgrp; 13061558Srgrimes do { 130775635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 130875635Siedowse &fsb)) { 130975635Siedowse getexp_err(ep, tgrp); 131075635Siedowse goto nextline; 131175635Siedowse } 13121558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 13131558Srgrimes 13141558Srgrimes /* 13151558Srgrimes * Success. Update the data structures. 13161558Srgrimes */ 13171558Srgrimes if (has_host) { 13189336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 13191558Srgrimes grp->gr_next = grphead; 13201558Srgrimes grphead = tgrp; 13211558Srgrimes } else { 13221558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 13239336Sdfr opt_flags); 13241558Srgrimes free_grp(grp); 13251558Srgrimes } 13261558Srgrimes dirhead = (struct dirlist *)NULL; 13271558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 13281558Srgrimes ep2 = exphead; 13291558Srgrimes epp = &exphead; 13301558Srgrimes 13311558Srgrimes /* 13321558Srgrimes * Insert in the list in alphabetical order. 13331558Srgrimes */ 13341558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 13351558Srgrimes epp = &ep2->ex_next; 13361558Srgrimes ep2 = ep2->ex_next; 13371558Srgrimes } 13381558Srgrimes if (ep2) 13391558Srgrimes ep->ex_next = ep2; 13401558Srgrimes *epp = ep; 13411558Srgrimes ep->ex_flag |= EX_LINKED; 13421558Srgrimes } 13431558Srgrimesnextline: 13441558Srgrimes if (dirhead) { 13451558Srgrimes free_dir(dirhead); 13461558Srgrimes dirhead = (struct dirlist *)NULL; 13471558Srgrimes } 13481558Srgrimes } 13491558Srgrimes} 13501558Srgrimes 13511558Srgrimes/* 1352166440Spjd * Get the export list from all specified files 1353166440Spjd */ 1354166440Spjdvoid 1355166440Spjdget_exportlist() 1356166440Spjd{ 1357166440Spjd struct exportlist *ep, *ep2; 1358166440Spjd struct grouplist *grp, *tgrp; 1359166440Spjd struct export_args export; 1360166440Spjd struct iovec *iov; 1361166440Spjd struct statfs *fsp, *mntbufp; 1362166440Spjd struct xvfsconf vfc; 1363166440Spjd char *dirp; 1364166440Spjd char errmsg[255]; 1365166440Spjd int dirplen, num, i; 1366166440Spjd int iovlen; 1367168684Spjd int done; 1368166440Spjd 1369166440Spjd bzero(&export, sizeof(export)); 1370166440Spjd export.ex_flags = MNT_DELEXPORT; 1371166440Spjd dirp = NULL; 1372166440Spjd dirplen = 0; 1373166440Spjd iov = NULL; 1374166440Spjd iovlen = 0; 1375166440Spjd bzero(errmsg, sizeof(errmsg)); 1376166440Spjd 1377166440Spjd /* 1378166440Spjd * First, get rid of the old list 1379166440Spjd */ 1380166440Spjd ep = exphead; 1381166440Spjd while (ep) { 1382166440Spjd ep2 = ep; 1383166440Spjd ep = ep->ex_next; 1384166440Spjd free_exp(ep2); 1385166440Spjd } 1386166440Spjd exphead = (struct exportlist *)NULL; 1387166440Spjd 1388166440Spjd grp = grphead; 1389166440Spjd while (grp) { 1390166440Spjd tgrp = grp; 1391166440Spjd grp = grp->gr_next; 1392166440Spjd free_grp(tgrp); 1393166440Spjd } 1394166440Spjd grphead = (struct grouplist *)NULL; 1395166440Spjd 1396166440Spjd /* 1397166440Spjd * And delete exports that are in the kernel for all local 1398166440Spjd * filesystems. 1399166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1400166440Spjd */ 1401166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1402166440Spjd 1403166440Spjd if (num > 0) { 1404166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1405166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1406166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1407166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1408166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1409166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1410166440Spjd } 1411166440Spjd 1412166440Spjd for (i = 0; i < num; i++) { 1413166440Spjd fsp = &mntbufp[i]; 1414166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1415166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1416166440Spjd fsp->f_fstypename); 1417166440Spjd continue; 1418166440Spjd } 1419166440Spjd 1420166440Spjd /* 1421166440Spjd * Do not delete export for network filesystem by 1422166440Spjd * passing "export" arg to nmount(). 1423166440Spjd * It only makes sense to do this for local filesystems. 1424166440Spjd */ 1425166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1426166440Spjd continue; 1427166440Spjd 1428166440Spjd iov[1].iov_base = fsp->f_fstypename; 1429166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1430166440Spjd iov[3].iov_base = fsp->f_mntonname; 1431166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1432166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1433166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1434166440Spjd 1435166440Spjd /* 1436166440Spjd * Kick out MNT_ROOTFS. It should not be passed from 1437166440Spjd * userland to kernel. It should only be used 1438166440Spjd * internally in the kernel. 1439166440Spjd */ 1440166440Spjd if (fsp->f_flags & MNT_ROOTFS) { 1441166440Spjd fsp->f_flags &= ~MNT_ROOTFS; 1442166440Spjd } 1443166440Spjd 1444166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1445166440Spjd errno != ENOENT && errno != ENOTSUP) { 1446166440Spjd syslog(LOG_ERR, 1447166440Spjd "can't delete exports for %s: %m %s", 1448166440Spjd fsp->f_mntonname, errmsg); 1449166440Spjd } 1450166440Spjd } 1451166440Spjd 1452166440Spjd if (iov != NULL) { 1453166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1454166440Spjd free(iov[0].iov_base); /* fstype */ 1455166440Spjd free(iov[2].iov_base); /* fspath */ 1456166440Spjd free(iov[4].iov_base); /* from */ 1457166440Spjd free(iov[6].iov_base); /* update */ 1458166440Spjd free(iov[8].iov_base); /* export */ 1459166440Spjd free(iov[10].iov_base); /* errmsg */ 1460166440Spjd 1461166440Spjd /* free iov, allocated by realloc() */ 1462166440Spjd free(iov); 1463166440Spjd iovlen = 0; 1464166440Spjd } 1465166440Spjd 1466166440Spjd /* 1467166440Spjd * Read in the exports file and build the list, calling 1468166440Spjd * nmount() as we go along to push the export rules into the kernel. 1469166440Spjd */ 1470168684Spjd done = 0; 1471166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1472166440Spjd if (debug) 1473166440Spjd warnx("reading exports from %s", exnames[i]); 1474166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1475168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1476168684Spjd continue; 1477166440Spjd } 1478166440Spjd get_exportlist_one(); 1479166440Spjd fclose(exp_file); 1480168684Spjd done++; 1481166440Spjd } 1482168684Spjd if (done == 0) { 1483168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1484168684Spjd exit(2); 1485168684Spjd } 1486166440Spjd} 1487166440Spjd 1488166440Spjd/* 14891558Srgrimes * Allocate an export list element 14901558Srgrimes */ 14911558Srgrimesstruct exportlist * 14921558Srgrimesget_exp() 14931558Srgrimes{ 14941558Srgrimes struct exportlist *ep; 14951558Srgrimes 14961558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 14971558Srgrimes if (ep == (struct exportlist *)NULL) 14981558Srgrimes out_of_mem(); 149923681Speter memset(ep, 0, sizeof(struct exportlist)); 15001558Srgrimes return (ep); 15011558Srgrimes} 15021558Srgrimes 15031558Srgrimes/* 15041558Srgrimes * Allocate a group list element 15051558Srgrimes */ 15061558Srgrimesstruct grouplist * 15071558Srgrimesget_grp() 15081558Srgrimes{ 15091558Srgrimes struct grouplist *gp; 15101558Srgrimes 15111558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 15121558Srgrimes if (gp == (struct grouplist *)NULL) 15131558Srgrimes out_of_mem(); 151423681Speter memset(gp, 0, sizeof(struct grouplist)); 15151558Srgrimes return (gp); 15161558Srgrimes} 15171558Srgrimes 15181558Srgrimes/* 15191558Srgrimes * Clean up upon an error in get_exportlist(). 15201558Srgrimes */ 15211558Srgrimesvoid 15221558Srgrimesgetexp_err(ep, grp) 15231558Srgrimes struct exportlist *ep; 15241558Srgrimes struct grouplist *grp; 15251558Srgrimes{ 15261558Srgrimes struct grouplist *tgrp; 15271558Srgrimes 1528100336Sjoerg if (!(opt_flags & OP_QUIET)) 1529100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 15301558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 15311558Srgrimes free_exp(ep); 15321558Srgrimes while (grp) { 15331558Srgrimes tgrp = grp; 15341558Srgrimes grp = grp->gr_next; 15351558Srgrimes free_grp(tgrp); 15361558Srgrimes } 15371558Srgrimes} 15381558Srgrimes 15391558Srgrimes/* 15401558Srgrimes * Search the export list for a matching fs. 15411558Srgrimes */ 15421558Srgrimesstruct exportlist * 15431558Srgrimesex_search(fsid) 15441558Srgrimes fsid_t *fsid; 15451558Srgrimes{ 15461558Srgrimes struct exportlist *ep; 15471558Srgrimes 15481558Srgrimes ep = exphead; 15491558Srgrimes while (ep) { 15501558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 15511558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 15521558Srgrimes return (ep); 15531558Srgrimes ep = ep->ex_next; 15541558Srgrimes } 15551558Srgrimes return (ep); 15561558Srgrimes} 15571558Srgrimes 15581558Srgrimes/* 15591558Srgrimes * Add a directory path to the list. 15601558Srgrimes */ 15611558Srgrimeschar * 15621558Srgrimesadd_expdir(dpp, cp, len) 15631558Srgrimes struct dirlist **dpp; 15641558Srgrimes char *cp; 15651558Srgrimes int len; 15661558Srgrimes{ 15671558Srgrimes struct dirlist *dp; 15681558Srgrimes 15691558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 157037663Scharnier if (dp == (struct dirlist *)NULL) 157137663Scharnier out_of_mem(); 15721558Srgrimes dp->dp_left = *dpp; 15731558Srgrimes dp->dp_right = (struct dirlist *)NULL; 15741558Srgrimes dp->dp_flag = 0; 15751558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 15761558Srgrimes strcpy(dp->dp_dirp, cp); 15771558Srgrimes *dpp = dp; 15781558Srgrimes return (dp->dp_dirp); 15791558Srgrimes} 15801558Srgrimes 15811558Srgrimes/* 15821558Srgrimes * Hang the dir list element off the dirpath binary tree as required 15831558Srgrimes * and update the entry for host. 15841558Srgrimes */ 15851558Srgrimesvoid 15869336Sdfrhang_dirp(dp, grp, ep, flags) 15871558Srgrimes struct dirlist *dp; 15881558Srgrimes struct grouplist *grp; 15891558Srgrimes struct exportlist *ep; 15909336Sdfr int flags; 15911558Srgrimes{ 15921558Srgrimes struct hostlist *hp; 15931558Srgrimes struct dirlist *dp2; 15941558Srgrimes 15959336Sdfr if (flags & OP_ALLDIRS) { 15961558Srgrimes if (ep->ex_defdir) 15971558Srgrimes free((caddr_t)dp); 15981558Srgrimes else 15991558Srgrimes ep->ex_defdir = dp; 16009336Sdfr if (grp == (struct grouplist *)NULL) { 16011558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 16029336Sdfr } else while (grp) { 16031558Srgrimes hp = get_ht(); 16041558Srgrimes hp->ht_grp = grp; 16051558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 16061558Srgrimes ep->ex_defdir->dp_hosts = hp; 16071558Srgrimes grp = grp->gr_next; 16081558Srgrimes } 16091558Srgrimes } else { 16101558Srgrimes 16111558Srgrimes /* 161237663Scharnier * Loop through the directories adding them to the tree. 16131558Srgrimes */ 16141558Srgrimes while (dp) { 16151558Srgrimes dp2 = dp->dp_left; 16169336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 16171558Srgrimes dp = dp2; 16181558Srgrimes } 16191558Srgrimes } 16201558Srgrimes} 16211558Srgrimes 16221558Srgrimes/* 16231558Srgrimes * Traverse the binary tree either updating a node that is already there 16241558Srgrimes * for the new directory or adding the new node. 16251558Srgrimes */ 16261558Srgrimesvoid 16279336Sdfradd_dlist(dpp, newdp, grp, flags) 16281558Srgrimes struct dirlist **dpp; 16291558Srgrimes struct dirlist *newdp; 16301558Srgrimes struct grouplist *grp; 16319336Sdfr int flags; 16321558Srgrimes{ 16331558Srgrimes struct dirlist *dp; 16341558Srgrimes struct hostlist *hp; 16351558Srgrimes int cmp; 16361558Srgrimes 16371558Srgrimes dp = *dpp; 16381558Srgrimes if (dp) { 16391558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 16401558Srgrimes if (cmp > 0) { 16419336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 16421558Srgrimes return; 16431558Srgrimes } else if (cmp < 0) { 16449336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 16451558Srgrimes return; 16461558Srgrimes } else 16471558Srgrimes free((caddr_t)newdp); 16481558Srgrimes } else { 16491558Srgrimes dp = newdp; 16501558Srgrimes dp->dp_left = (struct dirlist *)NULL; 16511558Srgrimes *dpp = dp; 16521558Srgrimes } 16531558Srgrimes if (grp) { 16541558Srgrimes 16551558Srgrimes /* 16561558Srgrimes * Hang all of the host(s) off of the directory point. 16571558Srgrimes */ 16581558Srgrimes do { 16591558Srgrimes hp = get_ht(); 16601558Srgrimes hp->ht_grp = grp; 16611558Srgrimes hp->ht_next = dp->dp_hosts; 16621558Srgrimes dp->dp_hosts = hp; 16631558Srgrimes grp = grp->gr_next; 16641558Srgrimes } while (grp); 16659336Sdfr } else { 16661558Srgrimes dp->dp_flag |= DP_DEFSET; 16679336Sdfr } 16681558Srgrimes} 16691558Srgrimes 16701558Srgrimes/* 16711558Srgrimes * Search for a dirpath on the export point. 16721558Srgrimes */ 16731558Srgrimesstruct dirlist * 167474462Salfreddirp_search(dp, dirp) 16751558Srgrimes struct dirlist *dp; 167674462Salfred char *dirp; 16771558Srgrimes{ 16781558Srgrimes int cmp; 16791558Srgrimes 16801558Srgrimes if (dp) { 168174462Salfred cmp = strcmp(dp->dp_dirp, dirp); 16821558Srgrimes if (cmp > 0) 168374462Salfred return (dirp_search(dp->dp_left, dirp)); 16841558Srgrimes else if (cmp < 0) 168574462Salfred return (dirp_search(dp->dp_right, dirp)); 16861558Srgrimes else 16871558Srgrimes return (dp); 16881558Srgrimes } 16891558Srgrimes return (dp); 16901558Srgrimes} 16911558Srgrimes 16921558Srgrimes/* 16931558Srgrimes * Scan for a host match in a directory tree. 16941558Srgrimes */ 16951558Srgrimesint 16969336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 16971558Srgrimes struct dirlist *dp; 169874462Salfred struct sockaddr *saddr; 16991558Srgrimes int *defsetp; 17009336Sdfr int *hostsetp; 17011558Srgrimes{ 17021558Srgrimes struct hostlist *hp; 17031558Srgrimes struct grouplist *grp; 170474462Salfred struct addrinfo *ai; 17051558Srgrimes 17061558Srgrimes if (dp) { 17071558Srgrimes if (dp->dp_flag & DP_DEFSET) 17089336Sdfr *defsetp = dp->dp_flag; 17091558Srgrimes hp = dp->dp_hosts; 17101558Srgrimes while (hp) { 17111558Srgrimes grp = hp->ht_grp; 17121558Srgrimes switch (grp->gr_type) { 17131558Srgrimes case GT_HOST: 171474462Salfred ai = grp->gr_ptr.gt_addrinfo; 171574462Salfred for (; ai; ai = ai->ai_next) { 171675801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 171774462Salfred *hostsetp = 171874462Salfred (hp->ht_flag | DP_HOSTSET); 171974462Salfred return (1); 172074462Salfred } 17219336Sdfr } 172275801Siedowse break; 17231558Srgrimes case GT_NET: 172475801Siedowse if (!sacmp(saddr, (struct sockaddr *) 172575801Siedowse &grp->gr_ptr.gt_net.nt_net, 172675801Siedowse (struct sockaddr *) 172775801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 172874462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 172974462Salfred return (1); 173074462Salfred } 173175801Siedowse break; 173275801Siedowse } 17331558Srgrimes hp = hp->ht_next; 17341558Srgrimes } 17351558Srgrimes } 17361558Srgrimes return (0); 17371558Srgrimes} 17381558Srgrimes 17391558Srgrimes/* 17401558Srgrimes * Scan tree for a host that matches the address. 17411558Srgrimes */ 17421558Srgrimesint 17431558Srgrimesscan_tree(dp, saddr) 17441558Srgrimes struct dirlist *dp; 174574462Salfred struct sockaddr *saddr; 17461558Srgrimes{ 17479336Sdfr int defset, hostset; 17481558Srgrimes 17491558Srgrimes if (dp) { 17501558Srgrimes if (scan_tree(dp->dp_left, saddr)) 17511558Srgrimes return (1); 17529336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 17531558Srgrimes return (1); 17541558Srgrimes if (scan_tree(dp->dp_right, saddr)) 17551558Srgrimes return (1); 17561558Srgrimes } 17571558Srgrimes return (0); 17581558Srgrimes} 17591558Srgrimes 17601558Srgrimes/* 17611558Srgrimes * Traverse the dirlist tree and free it up. 17621558Srgrimes */ 17631558Srgrimesvoid 17641558Srgrimesfree_dir(dp) 17651558Srgrimes struct dirlist *dp; 17661558Srgrimes{ 17671558Srgrimes 17681558Srgrimes if (dp) { 17691558Srgrimes free_dir(dp->dp_left); 17701558Srgrimes free_dir(dp->dp_right); 17711558Srgrimes free_host(dp->dp_hosts); 17721558Srgrimes free((caddr_t)dp); 17731558Srgrimes } 17741558Srgrimes} 17751558Srgrimes 17761558Srgrimes/* 17771558Srgrimes * Parse the option string and update fields. 17781558Srgrimes * Option arguments may either be -<option>=<value> or 17791558Srgrimes * -<option> <value> 17801558Srgrimes */ 17811558Srgrimesint 17821558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 17831558Srgrimes char **cpp, **endcpp; 17841558Srgrimes struct exportlist *ep; 17851558Srgrimes struct grouplist *grp; 17861558Srgrimes int *has_hostp; 17871558Srgrimes int *exflagsp; 178872650Sgreen struct xucred *cr; 17891558Srgrimes{ 17901558Srgrimes char *cpoptarg, *cpoptend; 17911558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 17921558Srgrimes int allflag, usedarg; 17931558Srgrimes 179451968Salfred savedc2 = '\0'; 17951558Srgrimes cpopt = *cpp; 17961558Srgrimes cpopt++; 17971558Srgrimes cp = *endcpp; 17981558Srgrimes savedc = *cp; 17991558Srgrimes *cp = '\0'; 18001558Srgrimes while (cpopt && *cpopt) { 18011558Srgrimes allflag = 1; 18021558Srgrimes usedarg = -2; 180337663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 18041558Srgrimes *cpoptend++ = '\0'; 180537663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 18061558Srgrimes *cpoptarg++ = '\0'; 18071558Srgrimes } else { 180837663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 18091558Srgrimes *cpoptarg++ = '\0'; 18101558Srgrimes else { 18111558Srgrimes *cp = savedc; 18121558Srgrimes nextfield(&cp, &endcp); 18131558Srgrimes **endcpp = '\0'; 18141558Srgrimes if (endcp > cp && *cp != '-') { 18151558Srgrimes cpoptarg = cp; 18161558Srgrimes savedc2 = *endcp; 18171558Srgrimes *endcp = '\0'; 18181558Srgrimes usedarg = 0; 18191558Srgrimes } 18201558Srgrimes } 18211558Srgrimes } 18221558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 18231558Srgrimes *exflagsp |= MNT_EXRDONLY; 18241558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 18251558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 18261558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 18271558Srgrimes usedarg++; 18281558Srgrimes parsecred(cpoptarg, cr); 18291558Srgrimes if (allflag == 0) { 18301558Srgrimes *exflagsp |= MNT_EXPORTANON; 18311558Srgrimes opt_flags |= OP_MAPALL; 18321558Srgrimes } else 18331558Srgrimes opt_flags |= OP_MAPROOT; 18341558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 183575801Siedowse !strcmp(cpopt, "m"))) { 18361558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 183737663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 18381558Srgrimes return (1); 18391558Srgrimes } 18401558Srgrimes usedarg++; 18411558Srgrimes opt_flags |= OP_MASK; 18421558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 18431558Srgrimes !strcmp(cpopt, "n"))) { 184474462Salfred if (strchr(cpoptarg, '/') != NULL) { 184574462Salfred if (debug) 184674462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 184774462Salfred opt_flags |= OP_MASKLEN; 184874462Salfred } 18491558Srgrimes if (grp->gr_type != GT_NULL) { 185037663Scharnier syslog(LOG_ERR, "network/host conflict"); 18511558Srgrimes return (1); 18521558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 185337663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 18541558Srgrimes return (1); 18551558Srgrimes } 18561558Srgrimes grp->gr_type = GT_NET; 18571558Srgrimes *has_hostp = 1; 18581558Srgrimes usedarg++; 18591558Srgrimes opt_flags |= OP_NET; 18601558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 18611558Srgrimes opt_flags |= OP_ALLDIRS; 186227447Sdfr } else if (!strcmp(cpopt, "public")) { 186327447Sdfr *exflagsp |= MNT_EXPUBLIC; 186427447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 186527447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 186627447Sdfr opt_flags |= OP_MAPALL; 186727447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 186827447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1869100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1870100336Sjoerg opt_flags |= OP_QUIET; 18711558Srgrimes } else { 187237663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 18731558Srgrimes return (1); 18741558Srgrimes } 18751558Srgrimes if (usedarg >= 0) { 18761558Srgrimes *endcp = savedc2; 18771558Srgrimes **endcpp = savedc; 18781558Srgrimes if (usedarg > 0) { 18791558Srgrimes *cpp = cp; 18801558Srgrimes *endcpp = endcp; 18811558Srgrimes } 18821558Srgrimes return (0); 18831558Srgrimes } 18841558Srgrimes cpopt = cpoptend; 18851558Srgrimes } 18861558Srgrimes **endcpp = savedc; 18871558Srgrimes return (0); 18881558Srgrimes} 18891558Srgrimes 18901558Srgrimes/* 18911558Srgrimes * Translate a character string to the corresponding list of network 18921558Srgrimes * addresses for a hostname. 18931558Srgrimes */ 18941558Srgrimesint 18957401Swpaulget_host(cp, grp, tgrp) 18961558Srgrimes char *cp; 18971558Srgrimes struct grouplist *grp; 18987401Swpaul struct grouplist *tgrp; 18991558Srgrimes{ 19007401Swpaul struct grouplist *checkgrp; 190175635Siedowse struct addrinfo *ai, *tai, hints; 190274462Salfred int ecode; 190374462Salfred char host[NI_MAXHOST]; 19041558Srgrimes 190574462Salfred if (grp->gr_type != GT_NULL) { 190674462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 19071558Srgrimes return (1); 19081558Srgrimes } 190974462Salfred memset(&hints, 0, sizeof hints); 191074462Salfred hints.ai_flags = AI_CANONNAME; 191174462Salfred hints.ai_protocol = IPPROTO_UDP; 191274462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 191374462Salfred if (ecode != 0) { 191475635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 191574462Salfred return 1; 191674462Salfred } 191774462Salfred grp->gr_ptr.gt_addrinfo = ai; 191874462Salfred while (ai != NULL) { 191974462Salfred if (ai->ai_canonname == NULL) { 192074462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1921146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 192274462Salfred strlcpy(host, "?", sizeof(host)); 192374462Salfred ai->ai_canonname = strdup(host); 192474462Salfred ai->ai_flags |= AI_CANONNAME; 192575641Siedowse } 192674462Salfred if (debug) 192775635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 192875635Siedowse /* 192975635Siedowse * Sanity check: make sure we don't already have an entry 193075635Siedowse * for this host in the grouplist. 193175635Siedowse */ 193275635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 193375635Siedowse checkgrp = checkgrp->gr_next) { 193475635Siedowse if (checkgrp->gr_type != GT_HOST) 193575635Siedowse continue; 193675635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 193775635Siedowse tai = tai->ai_next) { 193875801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 193975635Siedowse continue; 194075635Siedowse if (debug) 194175635Siedowse fprintf(stderr, 194275635Siedowse "ignoring duplicate host %s\n", 194375635Siedowse ai->ai_canonname); 194475635Siedowse grp->gr_type = GT_IGNORE; 194575635Siedowse return (0); 194675635Siedowse } 194775635Siedowse } 194874462Salfred ai = ai->ai_next; 19491558Srgrimes } 195075635Siedowse grp->gr_type = GT_HOST; 19511558Srgrimes return (0); 19521558Srgrimes} 19531558Srgrimes 19541558Srgrimes/* 19551558Srgrimes * Free up an exports list component 19561558Srgrimes */ 19571558Srgrimesvoid 19581558Srgrimesfree_exp(ep) 19591558Srgrimes struct exportlist *ep; 19601558Srgrimes{ 19611558Srgrimes 19621558Srgrimes if (ep->ex_defdir) { 19631558Srgrimes free_host(ep->ex_defdir->dp_hosts); 19641558Srgrimes free((caddr_t)ep->ex_defdir); 19651558Srgrimes } 19661558Srgrimes if (ep->ex_fsdir) 19671558Srgrimes free(ep->ex_fsdir); 196827447Sdfr if (ep->ex_indexfile) 196927447Sdfr free(ep->ex_indexfile); 19701558Srgrimes free_dir(ep->ex_dirl); 19711558Srgrimes free((caddr_t)ep); 19721558Srgrimes} 19731558Srgrimes 19741558Srgrimes/* 19751558Srgrimes * Free hosts. 19761558Srgrimes */ 19771558Srgrimesvoid 19781558Srgrimesfree_host(hp) 19791558Srgrimes struct hostlist *hp; 19801558Srgrimes{ 19811558Srgrimes struct hostlist *hp2; 19821558Srgrimes 19831558Srgrimes while (hp) { 19841558Srgrimes hp2 = hp; 19851558Srgrimes hp = hp->ht_next; 19861558Srgrimes free((caddr_t)hp2); 19871558Srgrimes } 19881558Srgrimes} 19891558Srgrimes 19901558Srgrimesstruct hostlist * 19911558Srgrimesget_ht() 19921558Srgrimes{ 19931558Srgrimes struct hostlist *hp; 19941558Srgrimes 19951558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 19961558Srgrimes if (hp == (struct hostlist *)NULL) 19971558Srgrimes out_of_mem(); 19981558Srgrimes hp->ht_next = (struct hostlist *)NULL; 19999336Sdfr hp->ht_flag = 0; 20001558Srgrimes return (hp); 20011558Srgrimes} 20021558Srgrimes 20031558Srgrimes/* 20041558Srgrimes * Out of memory, fatal 20051558Srgrimes */ 20061558Srgrimesvoid 20071558Srgrimesout_of_mem() 20081558Srgrimes{ 20091558Srgrimes 201037663Scharnier syslog(LOG_ERR, "out of memory"); 20111558Srgrimes exit(2); 20121558Srgrimes} 20131558Srgrimes 20141558Srgrimes/* 2015158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 20161558Srgrimes * the kernel. 20171558Srgrimes */ 20181558Srgrimesint 2019158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2020158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 20211558Srgrimes{ 202275841Siedowse struct statfs fsb1; 202374462Salfred struct addrinfo *ai; 2024158857Srodrigc struct export_args eap; 2025158857Srodrigc char errmsg[255]; 2026158857Srodrigc char *cp; 20271558Srgrimes int done; 2028158857Srodrigc char savedc; 2029158857Srodrigc struct iovec *iov; 2030158857Srodrigc int iovlen; 2031158857Srodrigc int ret; 20321558Srgrimes 2033158857Srodrigc cp = NULL; 2034158857Srodrigc savedc = '\0'; 2035158857Srodrigc iov = NULL; 2036158857Srodrigc iovlen = 0; 2037158857Srodrigc ret = 0; 203875801Siedowse 2039158857Srodrigc bzero(&eap, sizeof(eap)); 2040158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2041158857Srodrigc eap.ex_flags = exflags; 2042158857Srodrigc eap.ex_anon = *anoncrp; 2043158857Srodrigc eap.ex_indexfile = ep->ex_indexfile; 204475641Siedowse if (grp->gr_type == GT_HOST) 204574462Salfred ai = grp->gr_ptr.gt_addrinfo; 204675641Siedowse else 204775641Siedowse ai = NULL; 20481558Srgrimes done = FALSE; 2049158857Srodrigc 2050158857Srodrigc build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2051158857Srodrigc build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2052158857Srodrigc build_iovec(&iov, &iovlen, "from", NULL, 0); 2053158857Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 2054158857Srodrigc build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap)); 2055158857Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2056158857Srodrigc 20571558Srgrimes while (!done) { 20581558Srgrimes switch (grp->gr_type) { 20591558Srgrimes case GT_HOST: 206075641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 206174462Salfred goto skip; 2062158857Srodrigc eap.ex_addr = ai->ai_addr; 2063158857Srodrigc eap.ex_addrlen = ai->ai_addrlen; 2064158857Srodrigc eap.ex_masklen = 0; 20651558Srgrimes break; 20661558Srgrimes case GT_NET: 206775801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 206874462Salfred have_v6 == 0) 206974462Salfred goto skip; 2070158857Srodrigc eap.ex_addr = 207175801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2072158857Srodrigc eap.ex_addrlen = 2073158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2074158857Srodrigc eap.ex_mask = 207575801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2076158857Srodrigc eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 20771558Srgrimes break; 207875641Siedowse case GT_DEFAULT: 2079158857Srodrigc eap.ex_addr = NULL; 2080158857Srodrigc eap.ex_addrlen = 0; 2081158857Srodrigc eap.ex_mask = NULL; 2082158857Srodrigc eap.ex_masklen = 0; 208375641Siedowse break; 20847401Swpaul case GT_IGNORE: 2085158857Srodrigc ret = 0; 2086158857Srodrigc goto error_exit; 20877401Swpaul break; 20881558Srgrimes default: 208937663Scharnier syslog(LOG_ERR, "bad grouptype"); 20901558Srgrimes if (cp) 20911558Srgrimes *cp = savedc; 2092158857Srodrigc ret = 1; 2093158857Srodrigc goto error_exit; 20941558Srgrimes }; 20951558Srgrimes 20961558Srgrimes /* 20971558Srgrimes * XXX: 20981558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 20991558Srgrimes * of looping back up the dirp to the mount point?? 21001558Srgrimes * Also, needs to know how to export all types of local 210196707Strhodes * exportable filesystems and not just "ufs". 21021558Srgrimes */ 2103158857Srodrigc iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2104158857Srodrigc iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2105158857Srodrigc iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2106158857Srodrigc iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2107158857Srodrigc iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2108158857Srodrigc iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2109158857Srodrigc 2110163512Srink /* 2111163512Srink * Remount the filesystem, but chop off the MNT_ROOTFS flag 2112163512Srink * as it is used internally (and will result in an error if 2113163512Srink * specified) 2114163512Srink */ 2115163512Srink while (nmount(iov, iovlen, fsb->f_flags & ~MNT_ROOTFS) < 0) { 21161558Srgrimes if (cp) 21171558Srgrimes *cp-- = savedc; 21181558Srgrimes else 21191558Srgrimes cp = dirp + dirplen - 1; 2120158857Srodrigc if (opt_flags & OP_QUIET) { 2121158857Srodrigc ret = 1; 2122158857Srodrigc goto error_exit; 2123158857Srodrigc } 21241558Srgrimes if (errno == EPERM) { 212575635Siedowse if (debug) 212675635Siedowse warnx("can't change attributes for %s", 212775635Siedowse dirp); 21281558Srgrimes syslog(LOG_ERR, 212937663Scharnier "can't change attributes for %s", dirp); 2130158857Srodrigc ret = 1; 2131158857Srodrigc goto error_exit; 21321558Srgrimes } 21331558Srgrimes if (opt_flags & OP_ALLDIRS) { 2134100336Sjoerg if (errno == EINVAL) 2135100336Sjoerg syslog(LOG_ERR, 2136100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2137100336Sjoerg dirp); 2138100336Sjoerg else 2139100336Sjoerg syslog(LOG_ERR, 2140100336Sjoerg "could not remount %s: %m", 2141100336Sjoerg dirp); 2142158857Srodrigc ret = 1; 2143158857Srodrigc goto error_exit; 21441558Srgrimes } 21451558Srgrimes /* back up over the last component */ 21461558Srgrimes while (*cp == '/' && cp > dirp) 21471558Srgrimes cp--; 21481558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 21491558Srgrimes cp--; 21501558Srgrimes if (cp == dirp) { 21511558Srgrimes if (debug) 215237663Scharnier warnx("mnt unsucc"); 2153166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 2154166258Srodrigc errmsg); 2155158857Srodrigc ret = 1; 2156158857Srodrigc goto error_exit; 21571558Srgrimes } 21581558Srgrimes savedc = *cp; 21591558Srgrimes *cp = '\0'; 216075841Siedowse /* Check that we're still on the same filesystem. */ 216175841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 216275841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 216375841Siedowse *cp = savedc; 2164166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 2165166258Srodrigc errmsg); 2166158857Srodrigc ret = 1; 2167158857Srodrigc goto error_exit; 216875841Siedowse } 21691558Srgrimes } 217074462Salfredskip: 217175641Siedowse if (ai != NULL) 217274462Salfred ai = ai->ai_next; 217375641Siedowse if (ai == NULL) 21741558Srgrimes done = TRUE; 21751558Srgrimes } 21761558Srgrimes if (cp) 21771558Srgrimes *cp = savedc; 2178158857Srodrigcerror_exit: 2179158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2180158857Srodrigc if (iov != NULL) { 2181158857Srodrigc free(iov[0].iov_base); /* fstype */ 2182158857Srodrigc free(iov[2].iov_base); /* fspath */ 2183158857Srodrigc free(iov[4].iov_base); /* from */ 2184158857Srodrigc free(iov[6].iov_base); /* update */ 2185158857Srodrigc free(iov[8].iov_base); /* export */ 2186158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2187158857Srodrigc 2188158857Srodrigc /* free iov, allocated by realloc() */ 2189158857Srodrigc free(iov); 2190158857Srodrigc } 2191158857Srodrigc return (ret); 21921558Srgrimes} 21931558Srgrimes 21941558Srgrimes/* 21951558Srgrimes * Translate a net address. 219675801Siedowse * 219775801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 21981558Srgrimes */ 21991558Srgrimesint 22001558Srgrimesget_net(cp, net, maskflg) 22011558Srgrimes char *cp; 22021558Srgrimes struct netmsk *net; 22031558Srgrimes int maskflg; 22041558Srgrimes{ 220575861Siedowse struct netent *np = NULL; 220674462Salfred char *name, *p, *prefp; 220775801Siedowse struct sockaddr_in sin; 220875861Siedowse struct sockaddr *sa = NULL; 220974462Salfred struct addrinfo hints, *ai = NULL; 221074462Salfred char netname[NI_MAXHOST]; 221174462Salfred long preflen; 22121558Srgrimes 221375635Siedowse p = prefp = NULL; 221474462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 221574462Salfred p = strchr(cp, '/'); 221674462Salfred *p = '\0'; 221774462Salfred prefp = p + 1; 221874462Salfred } 221974462Salfred 222075861Siedowse /* 222175861Siedowse * Check for a numeric address first. We wish to avoid 222275861Siedowse * possible DNS lookups in getnetbyname(). 222375861Siedowse */ 222475861Siedowse if (isxdigit(*cp) || *cp == ':') { 222574462Salfred memset(&hints, 0, sizeof hints); 222675801Siedowse /* Ensure the mask and the network have the same family. */ 222775801Siedowse if (maskflg && (opt_flags & OP_NET)) 222875801Siedowse hints.ai_family = net->nt_net.ss_family; 222975801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 223075801Siedowse hints.ai_family = net->nt_mask.ss_family; 223175801Siedowse else 223275801Siedowse hints.ai_family = AF_UNSPEC; 223374462Salfred hints.ai_flags = AI_NUMERICHOST; 223475861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 223575861Siedowse sa = ai->ai_addr; 223675861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 223774462Salfred /* 223875801Siedowse * The address in `cp' is really a network address, so 223975801Siedowse * use inet_network() to re-interpret this correctly. 224075801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 224174462Salfred */ 224275801Siedowse bzero(&sin, sizeof sin); 224374462Salfred sin.sin_family = AF_INET; 224474462Salfred sin.sin_len = sizeof sin; 224575801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 224674462Salfred if (debug) 224775801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 224875801Siedowse inet_ntoa(sin.sin_addr)); 224974462Salfred sa = (struct sockaddr *)&sin; 225075861Siedowse } 225175861Siedowse } 225275861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 225375861Siedowse bzero(&sin, sizeof sin); 225475861Siedowse sin.sin_family = AF_INET; 225575861Siedowse sin.sin_len = sizeof sin; 225675861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 225775861Siedowse sa = (struct sockaddr *)&sin; 225875861Siedowse } 225975861Siedowse if (sa == NULL) 226074462Salfred goto fail; 226125318Spst 226275801Siedowse if (maskflg) { 226375801Siedowse /* The specified sockaddr is a mask. */ 226475801Siedowse if (checkmask(sa) != 0) 226575801Siedowse goto fail; 226675801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 226775801Siedowse opt_flags |= OP_HAVEMASK; 226875801Siedowse } else { 226975801Siedowse /* The specified sockaddr is a network address. */ 227075801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 227174462Salfred 227275801Siedowse /* Get a network name for the export list. */ 227375801Siedowse if (np) { 227475801Siedowse name = np->n_name; 227575801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2276146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 227775801Siedowse name = netname; 227875801Siedowse } else { 227975801Siedowse goto fail; 228075801Siedowse } 228175801Siedowse if ((net->nt_name = strdup(name)) == NULL) 228275801Siedowse out_of_mem(); 228375801Siedowse 228475801Siedowse /* 228575801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 228675801Siedowse * from the class of an IPv4 address. 228775801Siedowse */ 228874462Salfred if (opt_flags & OP_MASKLEN) { 228974462Salfred preflen = strtol(prefp, NULL, 10); 229075801Siedowse if (preflen < 0L || preflen == LONG_MAX) 229174462Salfred goto fail; 229275801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 229375801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 229475801Siedowse goto fail; 229575801Siedowse opt_flags |= OP_HAVEMASK; 229674462Salfred *p = '/'; 229775801Siedowse } else if (sa->sa_family == AF_INET && 229875801Siedowse (opt_flags & OP_MASK) == 0) { 229975801Siedowse in_addr_t addr; 230074462Salfred 230175801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 230275801Siedowse if (IN_CLASSA(addr)) 230375801Siedowse preflen = 8; 230475801Siedowse else if (IN_CLASSB(addr)) 230575801Siedowse preflen = 16; 230675801Siedowse else if (IN_CLASSC(addr)) 230775801Siedowse preflen = 24; 230875801Siedowse else if (IN_CLASSD(addr)) 230975801Siedowse preflen = 28; 231075801Siedowse else 231175801Siedowse preflen = 32; /* XXX */ 231275801Siedowse 231375801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 231475801Siedowse makemask(&net->nt_mask, (int)preflen); 231575801Siedowse opt_flags |= OP_HAVEMASK; 231674462Salfred } 231774462Salfred } 231874462Salfred 231974462Salfred if (ai) 232074462Salfred freeaddrinfo(ai); 232174462Salfred return 0; 232274462Salfred 232374462Salfredfail: 232474462Salfred if (ai) 232574462Salfred freeaddrinfo(ai); 232674462Salfred return 1; 23271558Srgrimes} 23281558Srgrimes 23291558Srgrimes/* 23301558Srgrimes * Parse out the next white space separated field 23311558Srgrimes */ 23321558Srgrimesvoid 23331558Srgrimesnextfield(cp, endcp) 23341558Srgrimes char **cp; 23351558Srgrimes char **endcp; 23361558Srgrimes{ 23371558Srgrimes char *p; 23381558Srgrimes 23391558Srgrimes p = *cp; 23401558Srgrimes while (*p == ' ' || *p == '\t') 23411558Srgrimes p++; 23421558Srgrimes if (*p == '\n' || *p == '\0') 23431558Srgrimes *cp = *endcp = p; 23441558Srgrimes else { 23451558Srgrimes *cp = p++; 23461558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 23471558Srgrimes p++; 23481558Srgrimes *endcp = p; 23491558Srgrimes } 23501558Srgrimes} 23511558Srgrimes 23521558Srgrimes/* 23531558Srgrimes * Get an exports file line. Skip over blank lines and handle line 23541558Srgrimes * continuations. 23551558Srgrimes */ 23561558Srgrimesint 23571558Srgrimesget_line() 23581558Srgrimes{ 23591558Srgrimes char *p, *cp; 236096622Siedowse size_t len; 23611558Srgrimes int totlen, cont_line; 23621558Srgrimes 23631558Srgrimes /* 23641558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 23651558Srgrimes */ 23661558Srgrimes p = line; 23671558Srgrimes totlen = 0; 23681558Srgrimes do { 236996622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 23701558Srgrimes return (0); 23711558Srgrimes cp = p + len - 1; 23721558Srgrimes cont_line = 0; 23731558Srgrimes while (cp >= p && 23741558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 23751558Srgrimes if (*cp == '\\') 23761558Srgrimes cont_line = 1; 23771558Srgrimes cp--; 23781558Srgrimes len--; 23791558Srgrimes } 238079117Sdd if (cont_line) { 238179117Sdd *++cp = ' '; 238279117Sdd len++; 238379117Sdd } 238496622Siedowse if (linesize < len + totlen + 1) { 238596622Siedowse linesize = len + totlen + 1; 238696622Siedowse line = realloc(line, linesize); 238796622Siedowse if (line == NULL) 238896622Siedowse out_of_mem(); 23891558Srgrimes } 239096622Siedowse memcpy(line + totlen, p, len); 239196622Siedowse totlen += len; 239296622Siedowse line[totlen] = '\0'; 23931558Srgrimes } while (totlen == 0 || cont_line); 23941558Srgrimes return (1); 23951558Srgrimes} 23961558Srgrimes 23971558Srgrimes/* 23981558Srgrimes * Parse a description of a credential. 23991558Srgrimes */ 24001558Srgrimesvoid 24011558Srgrimesparsecred(namelist, cr) 24021558Srgrimes char *namelist; 240372650Sgreen struct xucred *cr; 24041558Srgrimes{ 24051558Srgrimes char *name; 24061558Srgrimes int cnt; 24071558Srgrimes char *names; 24081558Srgrimes struct passwd *pw; 24091558Srgrimes struct group *gr; 2410136051Sstefanf gid_t groups[NGROUPS + 1]; 2411136051Sstefanf int ngroups; 24121558Srgrimes 241391354Sdd cr->cr_version = XUCRED_VERSION; 24141558Srgrimes /* 241537663Scharnier * Set up the unprivileged user. 24161558Srgrimes */ 24171558Srgrimes cr->cr_uid = -2; 24181558Srgrimes cr->cr_groups[0] = -2; 24191558Srgrimes cr->cr_ngroups = 1; 24201558Srgrimes /* 24211558Srgrimes * Get the user's password table entry. 24221558Srgrimes */ 24231558Srgrimes names = strsep(&namelist, " \t\n"); 24241558Srgrimes name = strsep(&names, ":"); 24251558Srgrimes if (isdigit(*name) || *name == '-') 24261558Srgrimes pw = getpwuid(atoi(name)); 24271558Srgrimes else 24281558Srgrimes pw = getpwnam(name); 24291558Srgrimes /* 24301558Srgrimes * Credentials specified as those of a user. 24311558Srgrimes */ 24321558Srgrimes if (names == NULL) { 24331558Srgrimes if (pw == NULL) { 243437663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 24351558Srgrimes return; 24361558Srgrimes } 24371558Srgrimes cr->cr_uid = pw->pw_uid; 24381558Srgrimes ngroups = NGROUPS + 1; 24391558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 244037663Scharnier syslog(LOG_ERR, "too many groups"); 24411558Srgrimes /* 2442136051Sstefanf * Compress out duplicate. 24431558Srgrimes */ 24441558Srgrimes cr->cr_ngroups = ngroups - 1; 24451558Srgrimes cr->cr_groups[0] = groups[0]; 24461558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 24471558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 24481558Srgrimes return; 24491558Srgrimes } 24501558Srgrimes /* 24511558Srgrimes * Explicit credential specified as a colon separated list: 24521558Srgrimes * uid:gid:gid:... 24531558Srgrimes */ 24541558Srgrimes if (pw != NULL) 24551558Srgrimes cr->cr_uid = pw->pw_uid; 24561558Srgrimes else if (isdigit(*name) || *name == '-') 24571558Srgrimes cr->cr_uid = atoi(name); 24581558Srgrimes else { 245937663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 24601558Srgrimes return; 24611558Srgrimes } 24621558Srgrimes cr->cr_ngroups = 0; 24631558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 24641558Srgrimes name = strsep(&names, ":"); 24651558Srgrimes if (isdigit(*name) || *name == '-') { 24661558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 24671558Srgrimes } else { 24681558Srgrimes if ((gr = getgrnam(name)) == NULL) { 246937663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 24701558Srgrimes continue; 24711558Srgrimes } 24721558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 24731558Srgrimes } 24741558Srgrimes } 24751558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 247637663Scharnier syslog(LOG_ERR, "too many groups"); 24771558Srgrimes} 24781558Srgrimes 24791558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 24801558Srgrimes/* 24811558Srgrimes * Routines that maintain the remote mounttab 24821558Srgrimes */ 24831558Srgrimesvoid 24841558Srgrimesget_mountlist() 24851558Srgrimes{ 24861558Srgrimes struct mountlist *mlp, **mlpp; 248723681Speter char *host, *dirp, *cp; 24881558Srgrimes char str[STRSIZ]; 24891558Srgrimes FILE *mlfile; 24901558Srgrimes 24911558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 249253117Sbillf if (errno == ENOENT) 249353117Sbillf return; 249453117Sbillf else { 249553117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 249653117Sbillf return; 249753117Sbillf } 24981558Srgrimes } 24991558Srgrimes mlpp = &mlhead; 25001558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 250123681Speter cp = str; 250223681Speter host = strsep(&cp, " \t\n"); 250323681Speter dirp = strsep(&cp, " \t\n"); 250423681Speter if (host == NULL || dirp == NULL) 25051558Srgrimes continue; 25061558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 250737663Scharnier if (mlp == (struct mountlist *)NULL) 250837663Scharnier out_of_mem(); 250923681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 251023681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 251123681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 251223681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 25131558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 25141558Srgrimes *mlpp = mlp; 25151558Srgrimes mlpp = &mlp->ml_next; 25161558Srgrimes } 25171558Srgrimes fclose(mlfile); 25181558Srgrimes} 25191558Srgrimes 252075635Siedowsevoid 252175635Siedowsedel_mlist(char *hostp, char *dirp) 25221558Srgrimes{ 25231558Srgrimes struct mountlist *mlp, **mlpp; 25241558Srgrimes struct mountlist *mlp2; 25251558Srgrimes FILE *mlfile; 25261558Srgrimes int fnd = 0; 25271558Srgrimes 25281558Srgrimes mlpp = &mlhead; 25291558Srgrimes mlp = mlhead; 25301558Srgrimes while (mlp) { 25311558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 25321558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 25331558Srgrimes fnd = 1; 25341558Srgrimes mlp2 = mlp; 25351558Srgrimes *mlpp = mlp = mlp->ml_next; 25361558Srgrimes free((caddr_t)mlp2); 25371558Srgrimes } else { 25381558Srgrimes mlpp = &mlp->ml_next; 25391558Srgrimes mlp = mlp->ml_next; 25401558Srgrimes } 25411558Srgrimes } 25421558Srgrimes if (fnd) { 25431558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 254437663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 25451558Srgrimes return; 25461558Srgrimes } 25471558Srgrimes mlp = mlhead; 25481558Srgrimes while (mlp) { 25491558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 25501558Srgrimes mlp = mlp->ml_next; 25511558Srgrimes } 25521558Srgrimes fclose(mlfile); 25531558Srgrimes } 25541558Srgrimes} 25551558Srgrimes 25561558Srgrimesvoid 25571558Srgrimesadd_mlist(hostp, dirp) 25581558Srgrimes char *hostp, *dirp; 25591558Srgrimes{ 25601558Srgrimes struct mountlist *mlp, **mlpp; 25611558Srgrimes FILE *mlfile; 25621558Srgrimes 25631558Srgrimes mlpp = &mlhead; 25641558Srgrimes mlp = mlhead; 25651558Srgrimes while (mlp) { 25661558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 25671558Srgrimes return; 25681558Srgrimes mlpp = &mlp->ml_next; 25691558Srgrimes mlp = mlp->ml_next; 25701558Srgrimes } 25711558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 257237663Scharnier if (mlp == (struct mountlist *)NULL) 257337663Scharnier out_of_mem(); 25741558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 25751558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 25761558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 25771558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 25781558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 25791558Srgrimes *mlpp = mlp; 25801558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 258137663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 25821558Srgrimes return; 25831558Srgrimes } 25841558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 25851558Srgrimes fclose(mlfile); 25861558Srgrimes} 25871558Srgrimes 25881558Srgrimes/* 25891558Srgrimes * Free up a group list. 25901558Srgrimes */ 25911558Srgrimesvoid 25921558Srgrimesfree_grp(grp) 25931558Srgrimes struct grouplist *grp; 25941558Srgrimes{ 25951558Srgrimes if (grp->gr_type == GT_HOST) { 259674462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 259774462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 25981558Srgrimes } else if (grp->gr_type == GT_NET) { 25991558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 26001558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 26011558Srgrimes } 26021558Srgrimes free((caddr_t)grp); 26031558Srgrimes} 26041558Srgrimes 26051558Srgrimes#ifdef DEBUG 26061558Srgrimesvoid 26071558SrgrimesSYSLOG(int pri, const char *fmt, ...) 26081558Srgrimes{ 26091558Srgrimes va_list ap; 26101558Srgrimes 26111558Srgrimes va_start(ap, fmt); 26121558Srgrimes vfprintf(stderr, fmt, ap); 26131558Srgrimes va_end(ap); 26141558Srgrimes} 26151558Srgrimes#endif /* DEBUG */ 26161558Srgrimes 26171558Srgrimes/* 26181558Srgrimes * Check options for consistency. 26191558Srgrimes */ 26201558Srgrimesint 26211558Srgrimescheck_options(dp) 26221558Srgrimes struct dirlist *dp; 26231558Srgrimes{ 26241558Srgrimes 26251558Srgrimes if (dp == (struct dirlist *)NULL) 26261558Srgrimes return (1); 262783653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 262883653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 26291558Srgrimes return (1); 26301558Srgrimes } 26311558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 263275801Siedowse syslog(LOG_ERR, "-mask requires -network"); 263375801Siedowse return (1); 26341558Srgrimes } 263575801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 263675801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 263775801Siedowse return (1); 263875801Siedowse } 263975801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 264075801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 264175801Siedowse return (1); 264275801Siedowse } 26431558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 264445927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 26451558Srgrimes return (1); 26461558Srgrimes } 26471558Srgrimes return (0); 26481558Srgrimes} 26491558Srgrimes 26501558Srgrimes/* 26511558Srgrimes * Check an absolute directory path for any symbolic links. Return true 26521558Srgrimes */ 26531558Srgrimesint 26541558Srgrimescheck_dirpath(dirp) 26551558Srgrimes char *dirp; 26561558Srgrimes{ 26571558Srgrimes char *cp; 26581558Srgrimes int ret = 1; 26591558Srgrimes struct stat sb; 26601558Srgrimes 26611558Srgrimes cp = dirp + 1; 26621558Srgrimes while (*cp && ret) { 26631558Srgrimes if (*cp == '/') { 26641558Srgrimes *cp = '\0'; 26659336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 26661558Srgrimes ret = 0; 26671558Srgrimes *cp = '/'; 26681558Srgrimes } 26691558Srgrimes cp++; 26701558Srgrimes } 26719336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 26721558Srgrimes ret = 0; 26731558Srgrimes return (ret); 26741558Srgrimes} 26759336Sdfr 267675801Siedowse/* 267775801Siedowse * Make a netmask according to the specified prefix length. The ss_family 267875801Siedowse * and other non-address fields must be initialised before calling this. 267975801Siedowse */ 268075801Siedowseint 268175801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 268274462Salfred{ 268375801Siedowse u_char *p; 268475801Siedowse int bits, i, len; 268574462Salfred 268675801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 268775801Siedowse return (-1); 2688103949Smike if (bitlen > len * CHAR_BIT) 268975801Siedowse return (-1); 269074462Salfred 269175801Siedowse for (i = 0; i < len; i++) { 2692103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 269375801Siedowse *p++ = (1 << bits) - 1; 269475801Siedowse bitlen -= bits; 269574462Salfred } 269675801Siedowse return 0; 269774462Salfred} 269874462Salfred 269975801Siedowse/* 270075801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 270175801Siedowse * is acceptable (i.e. of the form 1...10....0). 270275801Siedowse */ 270375801Siedowseint 270475801Siedowsecheckmask(struct sockaddr *sa) 270574462Salfred{ 270675801Siedowse u_char *mask; 270775801Siedowse int i, len; 270874462Salfred 270975801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 271075801Siedowse return (-1); 271175801Siedowse 271275801Siedowse for (i = 0; i < len; i++) 271375801Siedowse if (mask[i] != 0xff) 271475801Siedowse break; 271575801Siedowse if (i < len) { 271675801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 271775801Siedowse return (-1); 271875801Siedowse i++; 271974462Salfred } 272075801Siedowse for (; i < len; i++) 272175801Siedowse if (mask[i] != 0) 272275801Siedowse return (-1); 272375801Siedowse return (0); 272474462Salfred} 272574462Salfred 272675801Siedowse/* 272775801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 272875801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 272975801Siedowse * If samask is NULL, perform a full comparision. 273075801Siedowse */ 273175801Siedowseint 273275801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 273374462Salfred{ 273475801Siedowse unsigned char *p1, *p2, *mask; 273575801Siedowse int len, i; 273674462Salfred 273775801Siedowse if (sa1->sa_family != sa2->sa_family || 273875801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 273975801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 274075801Siedowse return (1); 274175801Siedowse 274275801Siedowse switch (sa1->sa_family) { 274374462Salfred case AF_INET6: 274475801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 274575801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 274675801Siedowse return (1); 274774462Salfred break; 274874462Salfred } 274974462Salfred 275075801Siedowse /* Simple binary comparison if no mask specified. */ 275175801Siedowse if (samask == NULL) 275275801Siedowse return (memcmp(p1, p2, len)); 275374462Salfred 275475801Siedowse /* Set up the mask, and do a mask-based comparison. */ 275575801Siedowse if (sa1->sa_family != samask->sa_family || 275675801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 275775801Siedowse return (1); 275874462Salfred 275975801Siedowse for (i = 0; i < len; i++) 276075801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 276175801Siedowse return (1); 276275801Siedowse return (0); 276374462Salfred} 276474462Salfred 276575801Siedowse/* 276675801Siedowse * Return a pointer to the part of the sockaddr that contains the 276775801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 276875801Siedowse * NULL if the address family is unknown. 276975801Siedowse */ 277075801Siedowsevoid * 277175801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 277275801Siedowse void *p; 277374462Salfred int len; 277474462Salfred 277575801Siedowse switch (sa->sa_family) { 277674462Salfred case AF_INET: 277775801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 277875801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 277974462Salfred break; 278074462Salfred case AF_INET6: 278175801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 278275801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 278374462Salfred break; 278474462Salfred default: 278575801Siedowse p = NULL; 278675801Siedowse len = 0; 278774462Salfred } 278874462Salfred 278975801Siedowse if (nbytes != NULL) 279075801Siedowse *nbytes = len; 279175801Siedowse return (p); 279274462Salfred} 279374462Salfred 279475754Siedowsevoid 279575754Siedowsehuphandler(int sig) 279675754Siedowse{ 279775754Siedowse got_sighup = 1; 279875754Siedowse} 279975754Siedowse 280074462Salfredvoid terminate(sig) 280174462Salfredint sig; 280274462Salfred{ 2803149433Spjd pidfile_remove(pfh); 280474792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 280574792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 280674462Salfred exit (0); 280774462Salfred} 2808