mountd.c revision 184588
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 184588 2008-11-03 10:38:00Z dfr $"); 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; 116184588Sdfr int ex_numsecflavors; 117184588Sdfr int ex_secflavors[MAXSECFLAVORS]; 1181558Srgrimes}; 1191558Srgrimes/* ex_flag bits */ 1201558Srgrimes#define EX_LINKED 0x1 1211558Srgrimes 1221558Srgrimesstruct netmsk { 12374462Salfred struct sockaddr_storage nt_net; 12475801Siedowse struct sockaddr_storage nt_mask; 12542144Sdfr char *nt_name; 1261558Srgrimes}; 1271558Srgrimes 1281558Srgrimesunion grouptypes { 12974462Salfred struct addrinfo *gt_addrinfo; 1301558Srgrimes struct netmsk gt_net; 1311558Srgrimes}; 1321558Srgrimes 1331558Srgrimesstruct grouplist { 1341558Srgrimes int gr_type; 1351558Srgrimes union grouptypes gr_ptr; 1361558Srgrimes struct grouplist *gr_next; 1371558Srgrimes}; 1381558Srgrimes/* Group types */ 1391558Srgrimes#define GT_NULL 0x0 1401558Srgrimes#define GT_HOST 0x1 1411558Srgrimes#define GT_NET 0x2 14275641Siedowse#define GT_DEFAULT 0x3 1437401Swpaul#define GT_IGNORE 0x5 1441558Srgrimes 1451558Srgrimesstruct hostlist { 1469336Sdfr int ht_flag; /* Uses DP_xx bits */ 1471558Srgrimes struct grouplist *ht_grp; 1481558Srgrimes struct hostlist *ht_next; 1491558Srgrimes}; 1501558Srgrimes 1519336Sdfrstruct fhreturn { 1529336Sdfr int fhr_flag; 1539336Sdfr int fhr_vers; 1549336Sdfr nfsfh_t fhr_fh; 155184588Sdfr int fhr_numsecflavors; 156184588Sdfr int *fhr_secflavors; 1579336Sdfr}; 1589336Sdfr 1591558Srgrimes/* Global defs */ 16092882Simpchar *add_expdir(struct dirlist **, char *, int); 16192882Simpvoid add_dlist(struct dirlist **, struct dirlist *, 16292882Simp struct grouplist *, int); 16392882Simpvoid add_mlist(char *, char *); 16492882Simpint check_dirpath(char *); 16592882Simpint check_options(struct dirlist *); 16675801Siedowseint checkmask(struct sockaddr *sa); 16792882Simpint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 168172827Smatteovoid create_service(struct netconfig *nconf); 16975635Siedowsevoid del_mlist(char *hostp, char *dirp); 17092882Simpstruct dirlist *dirp_search(struct dirlist *, char *); 17192882Simpint do_mount(struct exportlist *, struct grouplist *, int, 17292882Simp struct xucred *, char *, int, struct statfs *); 17392882Simpint do_opt(char **, char **, struct exportlist *, struct grouplist *, 17492882Simp int *, int *, struct xucred *); 17592882Simpstruct exportlist *ex_search(fsid_t *); 17692882Simpstruct exportlist *get_exp(void); 17792882Simpvoid free_dir(struct dirlist *); 17892882Simpvoid free_exp(struct exportlist *); 17992882Simpvoid free_grp(struct grouplist *); 18092882Simpvoid free_host(struct hostlist *); 18192882Simpvoid get_exportlist(void); 18292882Simpint get_host(char *, struct grouplist *, struct grouplist *); 18392882Simpstruct hostlist *get_ht(void); 18492882Simpint get_line(void); 18592882Simpvoid get_mountlist(void); 18692882Simpint get_net(char *, struct netmsk *, int); 18792882Simpvoid getexp_err(struct exportlist *, struct grouplist *); 18892882Simpstruct grouplist *get_grp(void); 18992882Simpvoid hang_dirp(struct dirlist *, struct grouplist *, 19092882Simp struct exportlist *, int); 19175754Siedowsevoid huphandler(int sig); 19275801Siedowseint makemask(struct sockaddr_storage *ssp, int bitlen); 19392882Simpvoid mntsrv(struct svc_req *, SVCXPRT *); 19492882Simpvoid nextfield(char **, char **); 19592882Simpvoid out_of_mem(void); 19692882Simpvoid parsecred(char *, struct xucred *); 197100117Salfredint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 19875801Siedowsevoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 19975801Siedowseint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 20075801Siedowse struct sockaddr *samask); 20192882Simpint scan_tree(struct dirlist *, struct sockaddr *); 20292882Simpstatic void usage(void); 20392882Simpint xdr_dir(XDR *, char *); 20492882Simpint xdr_explist(XDR *, caddr_t); 205100117Salfredint xdr_explist_brief(XDR *, caddr_t); 20692882Simpint xdr_fhs(XDR *, caddr_t); 20792882Simpint xdr_mlist(XDR *, caddr_t); 20892882Simpvoid terminate(int); 2091558Srgrimes 2101558Srgrimesstruct exportlist *exphead; 2111558Srgrimesstruct mountlist *mlhead; 2121558Srgrimesstruct grouplist *grphead; 213166440Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 214166440Spjdchar **exnames; 215172827Smatteochar **hosts = NULL; 21672650Sgreenstruct xucred def_anon = { 21791354Sdd XUCRED_VERSION, 21872650Sgreen (uid_t)-2, 2191558Srgrimes 1, 22072650Sgreen { (gid_t)-2 }, 22172650Sgreen NULL 2221558Srgrimes}; 22325087Sdfrint force_v2 = 0; 2249336Sdfrint resvport_only = 1; 225172827Smatteoint nhosts = 0; 2269336Sdfrint dir_only = 1; 227121767Speterint dolog = 0; 22875754Siedowseint got_sighup = 0; 229172827Smatteoint xcreated = 0; 23074462Salfred 231172827Smatteochar *svcport_str = NULL; 232172827Smatteo 2331558Srgrimesint opt_flags; 23474462Salfredstatic int have_v6 = 1; 23574462Salfred 236149433Spjdstruct pidfh *pfh = NULL; 23775801Siedowse/* Bits for opt_flags above */ 2381558Srgrimes#define OP_MAPROOT 0x01 2391558Srgrimes#define OP_MAPALL 0x02 24083653Speter/* 0x4 free */ 2411558Srgrimes#define OP_MASK 0x08 2421558Srgrimes#define OP_NET 0x10 2431558Srgrimes#define OP_ALLDIRS 0x40 24475801Siedowse#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 245100336Sjoerg#define OP_QUIET 0x100 24674462Salfred#define OP_MASKLEN 0x200 247184588Sdfr#define OP_SEC 0x400 2481558Srgrimes 2491558Srgrimes#ifdef DEBUG 2501558Srgrimesint debug = 1; 25192882Simpvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 2521558Srgrimes#define syslog SYSLOG 2531558Srgrimes#else 2541558Srgrimesint debug = 0; 2551558Srgrimes#endif 2561558Srgrimes 2571558Srgrimes/* 2581558Srgrimes * Mountd server for NFS mount protocol as described in: 2591558Srgrimes * NFS: Network File System Protocol Specification, RFC1094, Appendix A 2601558Srgrimes * The optional arguments are the exports file name 2611558Srgrimes * default: _PATH_EXPORTS 2621558Srgrimes * and "-n" to allow nonroot mount. 2631558Srgrimes */ 2641558Srgrimesint 2651558Srgrimesmain(argc, argv) 2661558Srgrimes int argc; 2671558Srgrimes char **argv; 2681558Srgrimes{ 26975754Siedowse fd_set readfds; 270172827Smatteo struct netconfig *nconf; 271172827Smatteo char *endptr, **hosts_bak; 272172827Smatteo void *nc_handle; 273149433Spjd pid_t otherpid; 274172827Smatteo in_port_t svcport; 275172827Smatteo int c, k, s; 276109363Smbr int maxrec = RPC_MAXDATASIZE; 2771558Srgrimes 27874462Salfred /* Check that another mountd isn't already running. */ 279150214Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 280149433Spjd if (pfh == NULL) { 281149433Spjd if (errno == EEXIST) 282149433Spjd errx(1, "mountd already running, pid: %d.", otherpid); 283149433Spjd warn("cannot open or create pidfile"); 284149433Spjd } 28574462Salfred 28674462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 28774462Salfred if (s < 0) 28874462Salfred have_v6 = 0; 28974462Salfred else 29074462Salfred close(s); 29183687Speter if (modfind("nfsserver") < 0) { 29283687Speter /* Not present in kernel, try loading it */ 29383687Speter if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 29483687Speter errx(1, "NFS server is not available or loadable"); 2952999Swollman } 2962999Swollman 297172827Smatteo while ((c = getopt(argc, argv, "2dh:lnp:r")) != -1) 2981558Srgrimes switch (c) { 29925087Sdfr case '2': 30025087Sdfr force_v2 = 1; 30125087Sdfr break; 3029336Sdfr case 'n': 3039336Sdfr resvport_only = 0; 3049336Sdfr break; 3059336Sdfr case 'r': 3069336Sdfr dir_only = 0; 3079336Sdfr break; 3088688Sphk case 'd': 3098688Sphk debug = debug ? 0 : 1; 3108688Sphk break; 31131656Sguido case 'l': 312121767Speter dolog = 1; 31331656Sguido break; 314126572Sbms case 'p': 315126572Sbms endptr = NULL; 316126572Sbms svcport = (in_port_t)strtoul(optarg, &endptr, 10); 317126572Sbms if (endptr == NULL || *endptr != '\0' || 318126572Sbms svcport == 0 || svcport >= IPPORT_MAX) 319126572Sbms usage(); 320172827Smatteo svcport_str = strdup(optarg); 321126572Sbms break; 322172827Smatteo case 'h': 323172827Smatteo ++nhosts; 324172827Smatteo hosts_bak = hosts; 325172827Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 326172827Smatteo if (hosts_bak == NULL) { 327172827Smatteo if (hosts != NULL) { 328172827Smatteo for (k = 0; k < nhosts; k++) 329172827Smatteo free(hosts[k]); 330172827Smatteo free(hosts); 331172827Smatteo out_of_mem(); 332172827Smatteo } 333172827Smatteo } 334172827Smatteo hosts = hosts_bak; 335172827Smatteo hosts[nhosts - 1] = strdup(optarg); 336172827Smatteo if (hosts[nhosts - 1] == NULL) { 337172827Smatteo for (k = 0; k < (nhosts - 1); k++) 338172827Smatteo free(hosts[k]); 339172827Smatteo free(hosts); 340172827Smatteo out_of_mem(); 341172827Smatteo } 342172827Smatteo break; 3431558Srgrimes default: 34437663Scharnier usage(); 3451558Srgrimes }; 3461558Srgrimes argc -= optind; 3471558Srgrimes argv += optind; 3481558Srgrimes grphead = (struct grouplist *)NULL; 3491558Srgrimes exphead = (struct exportlist *)NULL; 3501558Srgrimes mlhead = (struct mountlist *)NULL; 351166440Spjd if (argc > 0) 352166440Spjd exnames = argv; 353166440Spjd else 354166440Spjd exnames = exnames_default; 3551558Srgrimes openlog("mountd", LOG_PID, LOG_DAEMON); 3561558Srgrimes if (debug) 35737663Scharnier warnx("getting export list"); 3581558Srgrimes get_exportlist(); 3591558Srgrimes if (debug) 36037663Scharnier warnx("getting mount list"); 3611558Srgrimes get_mountlist(); 3621558Srgrimes if (debug) 36337663Scharnier warnx("here we go"); 3641558Srgrimes if (debug == 0) { 3651558Srgrimes daemon(0, 0); 3661558Srgrimes signal(SIGINT, SIG_IGN); 3671558Srgrimes signal(SIGQUIT, SIG_IGN); 3681558Srgrimes } 36975754Siedowse signal(SIGHUP, huphandler); 37074462Salfred signal(SIGTERM, terminate); 371164394Srodrigc signal(SIGPIPE, SIG_IGN); 372149433Spjd 373149433Spjd pidfile_write(pfh); 374149433Spjd 37574462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 37674462Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 377109363Smbr rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 378109363Smbr 37924759Sguido if (!resvport_only) { 38083687Speter if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 38183687Speter &resvport_only, sizeof(resvport_only)) != 0 && 38283687Speter errno != ENOENT) { 38324759Sguido syslog(LOG_ERR, "sysctl: %m"); 38424759Sguido exit(1); 38524759Sguido } 38624330Sguido } 387126572Sbms 388172827Smatteo /* 389172827Smatteo * If no hosts were specified, add a wildcard entry to bind to 390172827Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 391172827Smatteo * list. 392172827Smatteo */ 393172827Smatteo if (nhosts == 0) { 394172827Smatteo hosts = malloc(sizeof(char**)); 395172827Smatteo if (hosts == NULL) 396172827Smatteo out_of_mem(); 397172827Smatteo hosts[0] = "*"; 398172827Smatteo nhosts = 1; 399172827Smatteo } else { 400172827Smatteo hosts_bak = hosts; 401172827Smatteo if (have_v6) { 402172827Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 403172827Smatteo sizeof(char *)); 404172827Smatteo if (hosts_bak == NULL) { 405172827Smatteo for (k = 0; k < nhosts; k++) 406172827Smatteo free(hosts[k]); 407172827Smatteo free(hosts); 408172827Smatteo out_of_mem(); 409172827Smatteo } else 410172827Smatteo hosts = hosts_bak; 411172827Smatteo nhosts += 2; 412172827Smatteo hosts[nhosts - 2] = "::1"; 413172827Smatteo } else { 414172827Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 415172827Smatteo if (hosts_bak == NULL) { 416172827Smatteo for (k = 0; k < nhosts; k++) 417172827Smatteo free(hosts[k]); 418172827Smatteo free(hosts); 419172827Smatteo out_of_mem(); 420172827Smatteo } else { 421172827Smatteo nhosts += 1; 422172827Smatteo hosts = hosts_bak; 423126572Sbms } 424172827Smatteo } 42574462Salfred 426172827Smatteo hosts[nhosts - 1] = "127.0.0.1"; 42774462Salfred } 42874462Salfred 429172827Smatteo nc_handle = setnetconfig(); 430172827Smatteo while ((nconf = getnetconfig(nc_handle))) { 431172827Smatteo if (nconf->nc_flag & NC_VISIBLE) { 432172827Smatteo if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 433172827Smatteo "inet6") == 0) { 434172827Smatteo /* DO NOTHING */ 435172827Smatteo } else 436172827Smatteo create_service(nconf); 437172827Smatteo } 43874462Salfred } 439172827Smatteo endnetconfig(nc_handle); 44074462Salfred 44174462Salfred if (xcreated == 0) { 44274462Salfred syslog(LOG_ERR, "could not create any services"); 4431558Srgrimes exit(1); 4441558Srgrimes } 44575754Siedowse 44675754Siedowse /* Expand svc_run() here so that we can call get_exportlist(). */ 44775754Siedowse for (;;) { 44875754Siedowse if (got_sighup) { 44975754Siedowse get_exportlist(); 45075754Siedowse got_sighup = 0; 45175754Siedowse } 45275754Siedowse readfds = svc_fdset; 45375754Siedowse switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 45475754Siedowse case -1: 45575754Siedowse if (errno == EINTR) 45675754Siedowse continue; 45775754Siedowse syslog(LOG_ERR, "mountd died: select: %m"); 45875754Siedowse exit(1); 45975754Siedowse case 0: 46075754Siedowse continue; 46175754Siedowse default: 46275754Siedowse svc_getreqset(&readfds); 46375754Siedowse } 46475754Siedowse } 465172827Smatteo} 466172827Smatteo 467172827Smatteo/* 468172827Smatteo * This routine creates and binds sockets on the appropriate 469172827Smatteo * addresses. It gets called one time for each transport and 470172827Smatteo * registrates the service with rpcbind on that trasport. 471172827Smatteo */ 472172827Smatteovoid 473172827Smatteocreate_service(struct netconfig *nconf) 474172827Smatteo{ 475172827Smatteo struct addrinfo hints, *res = NULL; 476172827Smatteo struct sockaddr_in *sin; 477172827Smatteo struct sockaddr_in6 *sin6; 478172827Smatteo struct __rpc_sockinfo si; 479172827Smatteo struct netbuf servaddr; 480172827Smatteo SVCXPRT *transp = NULL; 481172827Smatteo int aicode; 482172827Smatteo int fd; 483172827Smatteo int nhostsbak; 484172827Smatteo int one = 1; 485172827Smatteo int r; 486172827Smatteo int registered = 0; 487172827Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 488172827Smatteo 489172827Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 490172827Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 491172827Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 492172827Smatteo return; /* not my type */ 493172827Smatteo 494172827Smatteo /* 495172827Smatteo * XXX - using RPC library internal functions. 496172827Smatteo */ 497172827Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 498172827Smatteo syslog(LOG_ERR, "cannot get information for %s", 499172827Smatteo nconf->nc_netid); 500172827Smatteo return; 501172827Smatteo } 502172827Smatteo 503172827Smatteo /* Get mountd's address on this transport */ 504172827Smatteo memset(&hints, 0, sizeof hints); 505172827Smatteo hints.ai_flags = AI_PASSIVE; 506172827Smatteo hints.ai_family = si.si_af; 507172827Smatteo hints.ai_socktype = si.si_socktype; 508172827Smatteo hints.ai_protocol = si.si_proto; 509172827Smatteo 510172827Smatteo /* 511172827Smatteo * Bind to specific IPs if asked to 512172827Smatteo */ 513172827Smatteo nhostsbak = nhosts; 514172827Smatteo while (nhostsbak > 0) { 515172827Smatteo --nhostsbak; 516172827Smatteo /* 517172827Smatteo * XXX - using RPC library internal functions. 518172827Smatteo */ 519172827Smatteo if ((fd = __rpc_nconf2fd(nconf)) < 0) { 520172827Smatteo int non_fatal = 0; 521172827Smatteo if (errno == EPROTONOSUPPORT && 522172827Smatteo nconf->nc_semantics != NC_TPI_CLTS) 523172827Smatteo non_fatal = 1; 524172827Smatteo 525172827Smatteo syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 526172827Smatteo "cannot create socket for %s", nconf->nc_netid); 527172827Smatteo return; 528172827Smatteo } 529172827Smatteo 530172827Smatteo switch (hints.ai_family) { 531172827Smatteo case AF_INET: 532172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 533172827Smatteo host_addr) == 1) { 534172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 535172827Smatteo } else { 536172827Smatteo /* 537172827Smatteo * Skip if we have an AF_INET6 address. 538172827Smatteo */ 539172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 540172827Smatteo host_addr) == 1) { 541172827Smatteo close(fd); 542172827Smatteo continue; 543172827Smatteo } 544172827Smatteo } 545172827Smatteo break; 546172827Smatteo case AF_INET6: 547172827Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 548172827Smatteo host_addr) == 1) { 549172827Smatteo hints.ai_flags &= AI_NUMERICHOST; 550172827Smatteo } else { 551172827Smatteo /* 552172827Smatteo * Skip if we have an AF_INET address. 553172827Smatteo */ 554172827Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 555172827Smatteo host_addr) == 1) { 556172827Smatteo close(fd); 557172827Smatteo continue; 558172827Smatteo } 559172827Smatteo } 560172827Smatteo 561172827Smatteo /* 562172827Smatteo * We're doing host-based access checks here, so don't 563172827Smatteo * allow v4-in-v6 to confuse things. The kernel will 564172827Smatteo * disable it by default on NFS sockets too. 565172827Smatteo */ 566172827Smatteo if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 567172827Smatteo sizeof one) < 0) { 568172827Smatteo syslog(LOG_ERR, 569172827Smatteo "can't disable v4-in-v6 on IPv6 socket"); 570172827Smatteo exit(1); 571172827Smatteo } 572172827Smatteo break; 573172827Smatteo default: 574172827Smatteo break; 575172827Smatteo } 576172827Smatteo 577172827Smatteo /* 578172827Smatteo * If no hosts were specified, just bind to INADDR_ANY 579172827Smatteo */ 580172827Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 581172827Smatteo if (svcport_str == NULL) { 582172827Smatteo res = malloc(sizeof(struct addrinfo)); 583172827Smatteo if (res == NULL) 584172827Smatteo out_of_mem(); 585172827Smatteo res->ai_flags = hints.ai_flags; 586172827Smatteo res->ai_family = hints.ai_family; 587172827Smatteo res->ai_protocol = hints.ai_protocol; 588172827Smatteo switch (res->ai_family) { 589172827Smatteo case AF_INET: 590172827Smatteo sin = malloc(sizeof(struct sockaddr_in)); 591172827Smatteo if (sin == NULL) 592172827Smatteo out_of_mem(); 593172827Smatteo sin->sin_family = AF_INET; 594172827Smatteo sin->sin_port = htons(0); 595172827Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 596172827Smatteo res->ai_addr = (struct sockaddr*) sin; 597172827Smatteo res->ai_addrlen = (socklen_t) 598172827Smatteo sizeof(res->ai_addr); 599172827Smatteo break; 600172827Smatteo case AF_INET6: 601172827Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 602173056Ssimon if (sin6 == NULL) 603172827Smatteo out_of_mem(); 604172827Smatteo sin6->sin6_family = AF_INET6; 605172827Smatteo sin6->sin6_port = htons(0); 606172827Smatteo sin6->sin6_addr = in6addr_any; 607172827Smatteo res->ai_addr = (struct sockaddr*) sin6; 608172827Smatteo res->ai_addrlen = (socklen_t) 609172827Smatteo sizeof(res->ai_addr); 610172827Smatteo break; 611172827Smatteo default: 612172827Smatteo break; 613172827Smatteo } 614172827Smatteo } else { 615172827Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 616172827Smatteo &hints, &res)) != 0) { 617172827Smatteo syslog(LOG_ERR, 618172827Smatteo "cannot get local address for %s: %s", 619172827Smatteo nconf->nc_netid, 620172827Smatteo gai_strerror(aicode)); 621172827Smatteo continue; 622172827Smatteo } 623172827Smatteo } 624172827Smatteo } else { 625172827Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 626172827Smatteo &hints, &res)) != 0) { 627172827Smatteo syslog(LOG_ERR, 628172827Smatteo "cannot get local address for %s: %s", 629172827Smatteo nconf->nc_netid, gai_strerror(aicode)); 630172827Smatteo continue; 631172827Smatteo } 632172827Smatteo } 633172827Smatteo 634172827Smatteo r = bindresvport_sa(fd, res->ai_addr); 635172827Smatteo if (r != 0) { 636172827Smatteo syslog(LOG_ERR, "bindresvport_sa: %m"); 637172827Smatteo exit(1); 638172827Smatteo } 639172827Smatteo 640172827Smatteo if (nconf->nc_semantics != NC_TPI_CLTS) 641172827Smatteo listen(fd, SOMAXCONN); 642172827Smatteo 643172827Smatteo if (nconf->nc_semantics == NC_TPI_CLTS ) 644172827Smatteo transp = svc_dg_create(fd, 0, 0); 645172827Smatteo else 646172827Smatteo transp = svc_vc_create(fd, RPC_MAXDATASIZE, 647172827Smatteo RPC_MAXDATASIZE); 648172827Smatteo 649172827Smatteo if (transp != (SVCXPRT *) NULL) { 650172827Smatteo if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 651172827Smatteo NULL)) 652172827Smatteo syslog(LOG_ERR, 653172827Smatteo "can't register %s RPCMNT_VER1 service", 654172827Smatteo nconf->nc_netid); 655172827Smatteo if (!force_v2) { 656172827Smatteo if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER3, 657172827Smatteo mntsrv, NULL)) 658172827Smatteo syslog(LOG_ERR, 659172827Smatteo "can't register %s RPCMNT_VER3 service", 660172827Smatteo nconf->nc_netid); 661172827Smatteo } 662172827Smatteo } else 663172827Smatteo syslog(LOG_WARNING, "can't create %s services", 664172827Smatteo nconf->nc_netid); 665172827Smatteo 666172827Smatteo if (registered == 0) { 667172827Smatteo registered = 1; 668172827Smatteo memset(&hints, 0, sizeof hints); 669172827Smatteo hints.ai_flags = AI_PASSIVE; 670172827Smatteo hints.ai_family = si.si_af; 671172827Smatteo hints.ai_socktype = si.si_socktype; 672172827Smatteo hints.ai_protocol = si.si_proto; 673172827Smatteo 674172827Smatteo if (svcport_str == NULL) { 675172827Smatteo svcport_str = malloc(NI_MAXSERV * sizeof(char)); 676172827Smatteo if (svcport_str == NULL) 677172827Smatteo out_of_mem(); 678172827Smatteo 679172827Smatteo if (getnameinfo(res->ai_addr, 680172827Smatteo res->ai_addr->sa_len, NULL, NI_MAXHOST, 681172827Smatteo svcport_str, NI_MAXSERV * sizeof(char), 682172827Smatteo NI_NUMERICHOST | NI_NUMERICSERV)) 683172827Smatteo errx(1, "Cannot get port number"); 684172827Smatteo } 685172827Smatteo 686172827Smatteo if((aicode = getaddrinfo(NULL, svcport_str, &hints, 687172827Smatteo &res)) != 0) { 688172827Smatteo syslog(LOG_ERR, "cannot get local address: %s", 689172827Smatteo gai_strerror(aicode)); 690172827Smatteo exit(1); 691172827Smatteo } 692172827Smatteo 693172827Smatteo servaddr.buf = malloc(res->ai_addrlen); 694172827Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 695172827Smatteo servaddr.len = res->ai_addrlen; 696172827Smatteo 697172827Smatteo rpcb_set(RPCPROG_MNT, RPCMNT_VER1, nconf, &servaddr); 698172827Smatteo rpcb_set(RPCPROG_MNT, RPCMNT_VER3, nconf, &servaddr); 699172827Smatteo 700172827Smatteo xcreated++; 701172827Smatteo freeaddrinfo(res); 702172827Smatteo } 703172827Smatteo } /* end while */ 7041558Srgrimes} 7051558Srgrimes 70637663Scharnierstatic void 70737663Scharnierusage() 70837663Scharnier{ 70937663Scharnier fprintf(stderr, 710126572Sbms "usage: mountd [-2] [-d] [-l] [-n] [-p <port>] [-r] " 711172827Smatteo "[-h <bindip>] [export_file ...]\n"); 71237663Scharnier exit(1); 71337663Scharnier} 71437663Scharnier 7151558Srgrimes/* 7161558Srgrimes * The mount rpc service 7171558Srgrimes */ 7181558Srgrimesvoid 7191558Srgrimesmntsrv(rqstp, transp) 7201558Srgrimes struct svc_req *rqstp; 7211558Srgrimes SVCXPRT *transp; 7221558Srgrimes{ 7231558Srgrimes struct exportlist *ep; 7241558Srgrimes struct dirlist *dp; 7259336Sdfr struct fhreturn fhr; 7261558Srgrimes struct stat stb; 7271558Srgrimes struct statfs fsb; 72874462Salfred char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 72974462Salfred int lookup_failed = 1; 73074462Salfred struct sockaddr *saddr; 7319336Sdfr u_short sport; 73223681Speter char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 73328911Sguido int bad = 0, defset, hostset; 7349336Sdfr sigset_t sighup_mask; 7351558Srgrimes 7369336Sdfr sigemptyset(&sighup_mask); 7379336Sdfr sigaddset(&sighup_mask, SIGHUP); 73874462Salfred saddr = svc_getrpccaller(transp)->buf; 73974462Salfred switch (saddr->sa_family) { 74074462Salfred case AF_INET6: 74175635Siedowse sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 74274462Salfred break; 74374462Salfred case AF_INET: 74475635Siedowse sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 74574462Salfred break; 74674462Salfred default: 74774462Salfred syslog(LOG_ERR, "request from unknown address family"); 74874462Salfred return; 74974462Salfred } 75074462Salfred lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 75174462Salfred NULL, 0, 0); 75274462Salfred getnameinfo(saddr, saddr->sa_len, numerichost, 75374462Salfred sizeof numerichost, NULL, 0, NI_NUMERICHOST); 7541558Srgrimes switch (rqstp->rq_proc) { 7551558Srgrimes case NULLPROC: 756121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 75737663Scharnier syslog(LOG_ERR, "can't send reply"); 7581558Srgrimes return; 7591558Srgrimes case RPCMNT_MOUNT: 7609336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 76131656Sguido syslog(LOG_NOTICE, 76231656Sguido "mount request from %s from unprivileged port", 76374462Salfred numerichost); 7641558Srgrimes svcerr_weakauth(transp); 7651558Srgrimes return; 7661558Srgrimes } 767121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 76831656Sguido syslog(LOG_NOTICE, "undecodable mount request from %s", 76974462Salfred numerichost); 7701558Srgrimes svcerr_decode(transp); 7711558Srgrimes return; 7721558Srgrimes } 7731558Srgrimes 7741558Srgrimes /* 7751558Srgrimes * Get the real pathname and make sure it is a directory 7769336Sdfr * or a regular file if the -r option was specified 7779336Sdfr * and it exists. 7781558Srgrimes */ 77951968Salfred if (realpath(rpcpath, dirpath) == NULL || 7801558Srgrimes stat(dirpath, &stb) < 0 || 7819336Sdfr (!S_ISDIR(stb.st_mode) && 78274462Salfred (dir_only || !S_ISREG(stb.st_mode))) || 7831558Srgrimes statfs(dirpath, &fsb) < 0) { 7841558Srgrimes chdir("/"); /* Just in case realpath doesn't */ 78531656Sguido syslog(LOG_NOTICE, 78637663Scharnier "mount request from %s for non existent path %s", 78774462Salfred numerichost, dirpath); 7881558Srgrimes if (debug) 78937663Scharnier warnx("stat failed on %s", dirpath); 79028911Sguido bad = ENOENT; /* We will send error reply later */ 7911558Srgrimes } 7921558Srgrimes 7931558Srgrimes /* Check in the exports list */ 7949336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 7951558Srgrimes ep = ex_search(&fsb.f_fsid); 7969336Sdfr hostset = defset = 0; 7979336Sdfr if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 7981558Srgrimes ((dp = dirp_search(ep->ex_dirl, dirpath)) && 79974462Salfred chk_host(dp, saddr, &defset, &hostset)) || 80074462Salfred (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 80174462Salfred scan_tree(ep->ex_dirl, saddr) == 0))) { 80228911Sguido if (bad) { 803121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 80428911Sguido (caddr_t)&bad)) 80537663Scharnier syslog(LOG_ERR, "can't send reply"); 80628911Sguido sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 80728911Sguido return; 80828911Sguido } 8099336Sdfr if (hostset & DP_HOSTSET) 8109336Sdfr fhr.fhr_flag = hostset; 8119336Sdfr else 8129336Sdfr fhr.fhr_flag = defset; 8139336Sdfr fhr.fhr_vers = rqstp->rq_vers; 8141558Srgrimes /* Get the file handle */ 81523681Speter memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 8169336Sdfr if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 8171558Srgrimes bad = errno; 81837663Scharnier syslog(LOG_ERR, "can't get fh for %s", dirpath); 819121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 8201558Srgrimes (caddr_t)&bad)) 82137663Scharnier syslog(LOG_ERR, "can't send reply"); 8229336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8231558Srgrimes return; 8241558Srgrimes } 825184588Sdfr fhr.fhr_numsecflavors = ep->ex_numsecflavors; 826184588Sdfr fhr.fhr_secflavors = ep->ex_secflavors; 827121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 828121556Speter (caddr_t)&fhr)) 82937663Scharnier syslog(LOG_ERR, "can't send reply"); 83074462Salfred if (!lookup_failed) 83174462Salfred add_mlist(host, dirpath); 8321558Srgrimes else 83374462Salfred add_mlist(numerichost, dirpath); 8341558Srgrimes if (debug) 83537663Scharnier warnx("mount successful"); 836121767Speter if (dolog) 83731656Sguido syslog(LOG_NOTICE, 83831656Sguido "mount request succeeded from %s for %s", 83974462Salfred numerichost, dirpath); 84031656Sguido } else { 8411558Srgrimes bad = EACCES; 84231656Sguido syslog(LOG_NOTICE, 84331656Sguido "mount request denied from %s for %s", 84474462Salfred numerichost, dirpath); 84531656Sguido } 84628911Sguido 847121556Speter if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 848121556Speter (caddr_t)&bad)) 84937663Scharnier syslog(LOG_ERR, "can't send reply"); 8509336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 8511558Srgrimes return; 8521558Srgrimes case RPCMNT_DUMP: 853121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 85437663Scharnier syslog(LOG_ERR, "can't send reply"); 855121767Speter else if (dolog) 85631656Sguido syslog(LOG_NOTICE, 85731656Sguido "dump request succeeded from %s", 85874462Salfred numerichost); 8591558Srgrimes return; 8601558Srgrimes case RPCMNT_UMOUNT: 8619336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 86231656Sguido syslog(LOG_NOTICE, 86331656Sguido "umount request from %s from unprivileged port", 86474462Salfred numerichost); 8651558Srgrimes svcerr_weakauth(transp); 8661558Srgrimes return; 8671558Srgrimes } 868121556Speter if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 86931656Sguido syslog(LOG_NOTICE, "undecodable umount request from %s", 87074462Salfred numerichost); 8711558Srgrimes svcerr_decode(transp); 8721558Srgrimes return; 8731558Srgrimes } 87451968Salfred if (realpath(rpcpath, dirpath) == NULL) { 87551968Salfred syslog(LOG_NOTICE, "umount request from %s " 87651968Salfred "for non existent path %s", 87774462Salfred numerichost, dirpath); 87851968Salfred } 879121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 88037663Scharnier syslog(LOG_ERR, "can't send reply"); 88174462Salfred if (!lookup_failed) 88275635Siedowse del_mlist(host, dirpath); 88375635Siedowse del_mlist(numerichost, dirpath); 884121767Speter if (dolog) 88531656Sguido syslog(LOG_NOTICE, 88631656Sguido "umount request succeeded from %s for %s", 88774462Salfred numerichost, dirpath); 8881558Srgrimes return; 8891558Srgrimes case RPCMNT_UMNTALL: 8909336Sdfr if (sport >= IPPORT_RESERVED && resvport_only) { 89131656Sguido syslog(LOG_NOTICE, 89231656Sguido "umountall request from %s from unprivileged port", 89374462Salfred numerichost); 8941558Srgrimes svcerr_weakauth(transp); 8951558Srgrimes return; 8961558Srgrimes } 897121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 89837663Scharnier syslog(LOG_ERR, "can't send reply"); 89974462Salfred if (!lookup_failed) 90075635Siedowse del_mlist(host, NULL); 90175635Siedowse del_mlist(numerichost, NULL); 902121767Speter if (dolog) 90331656Sguido syslog(LOG_NOTICE, 90431656Sguido "umountall request succeeded from %s", 90574462Salfred numerichost); 9061558Srgrimes return; 9071558Srgrimes case RPCMNT_EXPORT: 908121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 909121556Speter if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 910121556Speter (caddr_t)NULL)) 911100117Salfred syslog(LOG_ERR, "can't send reply"); 912121767Speter if (dolog) 91331656Sguido syslog(LOG_NOTICE, 91431656Sguido "export request succeeded from %s", 91574462Salfred numerichost); 9161558Srgrimes return; 9171558Srgrimes default: 9181558Srgrimes svcerr_noproc(transp); 9191558Srgrimes return; 9201558Srgrimes } 9211558Srgrimes} 9221558Srgrimes 9231558Srgrimes/* 9241558Srgrimes * Xdr conversion for a dirpath string 9251558Srgrimes */ 9261558Srgrimesint 9271558Srgrimesxdr_dir(xdrsp, dirp) 9281558Srgrimes XDR *xdrsp; 9291558Srgrimes char *dirp; 9301558Srgrimes{ 9311558Srgrimes return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 9321558Srgrimes} 9331558Srgrimes 9341558Srgrimes/* 9359336Sdfr * Xdr routine to generate file handle reply 9361558Srgrimes */ 9371558Srgrimesint 9389336Sdfrxdr_fhs(xdrsp, cp) 9391558Srgrimes XDR *xdrsp; 9409336Sdfr caddr_t cp; 9411558Srgrimes{ 94292806Sobrien struct fhreturn *fhrp = (struct fhreturn *)cp; 9439336Sdfr u_long ok = 0, len, auth; 944184588Sdfr int i; 9451558Srgrimes 9461558Srgrimes if (!xdr_long(xdrsp, &ok)) 9471558Srgrimes return (0); 9489336Sdfr switch (fhrp->fhr_vers) { 9499336Sdfr case 1: 9509336Sdfr return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 9519336Sdfr case 3: 9529336Sdfr len = NFSX_V3FH; 9539336Sdfr if (!xdr_long(xdrsp, &len)) 9549336Sdfr return (0); 9559336Sdfr if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 9569336Sdfr return (0); 957184588Sdfr if (fhrp->fhr_numsecflavors) { 958184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 959184588Sdfr return (0); 960184588Sdfr for (i = 0; i < fhrp->fhr_numsecflavors; i++) 961184588Sdfr if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 962184588Sdfr return (0); 963184588Sdfr return (1); 964184588Sdfr } else { 965184588Sdfr auth = AUTH_SYS; 966184588Sdfr len = 1; 967184588Sdfr if (!xdr_long(xdrsp, &len)) 968184588Sdfr return (0); 969184588Sdfr return (xdr_long(xdrsp, &auth)); 970184588Sdfr } 9719336Sdfr }; 9729336Sdfr return (0); 9731558Srgrimes} 9741558Srgrimes 9751558Srgrimesint 9761558Srgrimesxdr_mlist(xdrsp, cp) 9771558Srgrimes XDR *xdrsp; 9781558Srgrimes caddr_t cp; 9791558Srgrimes{ 9801558Srgrimes struct mountlist *mlp; 9811558Srgrimes int true = 1; 9821558Srgrimes int false = 0; 9831558Srgrimes char *strp; 9841558Srgrimes 9851558Srgrimes mlp = mlhead; 9861558Srgrimes while (mlp) { 9871558Srgrimes if (!xdr_bool(xdrsp, &true)) 9881558Srgrimes return (0); 9891558Srgrimes strp = &mlp->ml_host[0]; 9901558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 9911558Srgrimes return (0); 9921558Srgrimes strp = &mlp->ml_dirp[0]; 9931558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 9941558Srgrimes return (0); 9951558Srgrimes mlp = mlp->ml_next; 9961558Srgrimes } 9971558Srgrimes if (!xdr_bool(xdrsp, &false)) 9981558Srgrimes return (0); 9991558Srgrimes return (1); 10001558Srgrimes} 10011558Srgrimes 10021558Srgrimes/* 10031558Srgrimes * Xdr conversion for export list 10041558Srgrimes */ 10051558Srgrimesint 1006100117Salfredxdr_explist_common(xdrsp, cp, brief) 10071558Srgrimes XDR *xdrsp; 10081558Srgrimes caddr_t cp; 1009100117Salfred int brief; 10101558Srgrimes{ 10111558Srgrimes struct exportlist *ep; 10121558Srgrimes int false = 0; 10139336Sdfr int putdef; 10149336Sdfr sigset_t sighup_mask; 10151558Srgrimes 10169336Sdfr sigemptyset(&sighup_mask); 10179336Sdfr sigaddset(&sighup_mask, SIGHUP); 10189336Sdfr sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 10191558Srgrimes ep = exphead; 10201558Srgrimes while (ep) { 10211558Srgrimes putdef = 0; 1022100117Salfred if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1023100117Salfred &putdef, brief)) 10241558Srgrimes goto errout; 10251558Srgrimes if (ep->ex_defdir && putdef == 0 && 10261558Srgrimes put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1027100117Salfred &putdef, brief)) 10281558Srgrimes goto errout; 10291558Srgrimes ep = ep->ex_next; 10301558Srgrimes } 10319336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10321558Srgrimes if (!xdr_bool(xdrsp, &false)) 10331558Srgrimes return (0); 10341558Srgrimes return (1); 10351558Srgrimeserrout: 10369336Sdfr sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 10371558Srgrimes return (0); 10381558Srgrimes} 10391558Srgrimes 10401558Srgrimes/* 10411558Srgrimes * Called from xdr_explist() to traverse the tree and export the 10421558Srgrimes * directory paths. 10431558Srgrimes */ 10441558Srgrimesint 1045100117Salfredput_exlist(dp, xdrsp, adp, putdefp, brief) 10461558Srgrimes struct dirlist *dp; 10471558Srgrimes XDR *xdrsp; 10481558Srgrimes struct dirlist *adp; 10491558Srgrimes int *putdefp; 1050100117Salfred int brief; 10511558Srgrimes{ 10521558Srgrimes struct grouplist *grp; 10531558Srgrimes struct hostlist *hp; 10541558Srgrimes int true = 1; 10551558Srgrimes int false = 0; 10561558Srgrimes int gotalldir = 0; 10571558Srgrimes char *strp; 10581558Srgrimes 10591558Srgrimes if (dp) { 1060100117Salfred if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 10611558Srgrimes return (1); 10621558Srgrimes if (!xdr_bool(xdrsp, &true)) 10631558Srgrimes return (1); 10641558Srgrimes strp = dp->dp_dirp; 10651558Srgrimes if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 10661558Srgrimes return (1); 10671558Srgrimes if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 10681558Srgrimes gotalldir = 1; 10691558Srgrimes *putdefp = 1; 10701558Srgrimes } 1071100117Salfred if (brief) { 1072100117Salfred if (!xdr_bool(xdrsp, &true)) 1073100117Salfred return (1); 1074100117Salfred strp = "(...)"; 1075100117Salfred if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1076100117Salfred return (1); 1077100117Salfred } else if ((dp->dp_flag & DP_DEFSET) == 0 && 10781558Srgrimes (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 10791558Srgrimes hp = dp->dp_hosts; 10801558Srgrimes while (hp) { 10811558Srgrimes grp = hp->ht_grp; 10821558Srgrimes if (grp->gr_type == GT_HOST) { 10831558Srgrimes if (!xdr_bool(xdrsp, &true)) 10841558Srgrimes return (1); 108574462Salfred strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 10868871Srgrimes if (!xdr_string(xdrsp, &strp, 10871558Srgrimes RPCMNT_NAMELEN)) 10881558Srgrimes return (1); 10891558Srgrimes } else if (grp->gr_type == GT_NET) { 10901558Srgrimes if (!xdr_bool(xdrsp, &true)) 10911558Srgrimes return (1); 10921558Srgrimes strp = grp->gr_ptr.gt_net.nt_name; 10938871Srgrimes if (!xdr_string(xdrsp, &strp, 10941558Srgrimes RPCMNT_NAMELEN)) 10951558Srgrimes return (1); 10961558Srgrimes } 10971558Srgrimes hp = hp->ht_next; 10981558Srgrimes if (gotalldir && hp == (struct hostlist *)NULL) { 10991558Srgrimes hp = adp->dp_hosts; 11001558Srgrimes gotalldir = 0; 11011558Srgrimes } 11021558Srgrimes } 11031558Srgrimes } 11041558Srgrimes if (!xdr_bool(xdrsp, &false)) 11051558Srgrimes return (1); 1106100117Salfred if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 11071558Srgrimes return (1); 11081558Srgrimes } 11091558Srgrimes return (0); 11101558Srgrimes} 11111558Srgrimes 1112100117Salfredint 1113100117Salfredxdr_explist(xdrsp, cp) 1114100117Salfred XDR *xdrsp; 1115100117Salfred caddr_t cp; 1116100117Salfred{ 1117100117Salfred 1118100117Salfred return xdr_explist_common(xdrsp, cp, 0); 1119100117Salfred} 1120100117Salfred 1121100117Salfredint 1122100117Salfredxdr_explist_brief(xdrsp, cp) 1123100117Salfred XDR *xdrsp; 1124100117Salfred caddr_t cp; 1125100117Salfred{ 1126100117Salfred 1127100117Salfred return xdr_explist_common(xdrsp, cp, 1); 1128100117Salfred} 1129100117Salfred 113096622Siedowsechar *line; 113196622Siedowseint linesize; 11321558SrgrimesFILE *exp_file; 11331558Srgrimes 11341558Srgrimes/* 1135166440Spjd * Get the export list from one, currently open file 11361558Srgrimes */ 1137166440Spjdstatic void 1138166440Spjdget_exportlist_one() 11391558Srgrimes{ 11401558Srgrimes struct exportlist *ep, *ep2; 11411558Srgrimes struct grouplist *grp, *tgrp; 11421558Srgrimes struct exportlist **epp; 11431558Srgrimes struct dirlist *dirhead; 1144166440Spjd struct statfs fsb; 114572650Sgreen struct xucred anon; 11461558Srgrimes char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1147166440Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 11481558Srgrimes 11491558Srgrimes dirhead = (struct dirlist *)NULL; 11501558Srgrimes while (get_line()) { 11511558Srgrimes if (debug) 115237663Scharnier warnx("got line %s", line); 11531558Srgrimes cp = line; 11541558Srgrimes nextfield(&cp, &endcp); 11551558Srgrimes if (*cp == '#') 11561558Srgrimes goto nextline; 11571558Srgrimes 11581558Srgrimes /* 11591558Srgrimes * Set defaults. 11601558Srgrimes */ 11611558Srgrimes has_host = FALSE; 11621558Srgrimes anon = def_anon; 11631558Srgrimes exflags = MNT_EXPORTED; 11641558Srgrimes got_nondir = 0; 11651558Srgrimes opt_flags = 0; 11661558Srgrimes ep = (struct exportlist *)NULL; 11671558Srgrimes 11681558Srgrimes /* 11691558Srgrimes * Create new exports list entry 11701558Srgrimes */ 11711558Srgrimes len = endcp-cp; 11721558Srgrimes tgrp = grp = get_grp(); 11731558Srgrimes while (len > 0) { 11741558Srgrimes if (len > RPCMNT_NAMELEN) { 11751558Srgrimes getexp_err(ep, tgrp); 11761558Srgrimes goto nextline; 11771558Srgrimes } 11781558Srgrimes if (*cp == '-') { 11791558Srgrimes if (ep == (struct exportlist *)NULL) { 11801558Srgrimes getexp_err(ep, tgrp); 11811558Srgrimes goto nextline; 11821558Srgrimes } 11831558Srgrimes if (debug) 118437663Scharnier warnx("doing opt %s", cp); 11851558Srgrimes got_nondir = 1; 11861558Srgrimes if (do_opt(&cp, &endcp, ep, grp, &has_host, 11871558Srgrimes &exflags, &anon)) { 11881558Srgrimes getexp_err(ep, tgrp); 11891558Srgrimes goto nextline; 11901558Srgrimes } 11911558Srgrimes } else if (*cp == '/') { 11921558Srgrimes savedc = *endcp; 11931558Srgrimes *endcp = '\0'; 11941558Srgrimes if (check_dirpath(cp) && 11951558Srgrimes statfs(cp, &fsb) >= 0) { 11961558Srgrimes if (got_nondir) { 119737663Scharnier syslog(LOG_ERR, "dirs must be first"); 11981558Srgrimes getexp_err(ep, tgrp); 11991558Srgrimes goto nextline; 12001558Srgrimes } 12011558Srgrimes if (ep) { 12021558Srgrimes if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 12031558Srgrimes ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 12041558Srgrimes getexp_err(ep, tgrp); 12051558Srgrimes goto nextline; 12061558Srgrimes } 12071558Srgrimes } else { 12081558Srgrimes /* 12091558Srgrimes * See if this directory is already 12101558Srgrimes * in the list. 12111558Srgrimes */ 12121558Srgrimes ep = ex_search(&fsb.f_fsid); 12131558Srgrimes if (ep == (struct exportlist *)NULL) { 12141558Srgrimes ep = get_exp(); 12151558Srgrimes ep->ex_fs = fsb.f_fsid; 12161558Srgrimes ep->ex_fsdir = (char *) 12171558Srgrimes malloc(strlen(fsb.f_mntonname) + 1); 12181558Srgrimes if (ep->ex_fsdir) 12191558Srgrimes strcpy(ep->ex_fsdir, 12201558Srgrimes fsb.f_mntonname); 12211558Srgrimes else 12221558Srgrimes out_of_mem(); 12231558Srgrimes if (debug) 122474462Salfred warnx("making new ep fs=0x%x,0x%x", 122574462Salfred fsb.f_fsid.val[0], 122674462Salfred fsb.f_fsid.val[1]); 12271558Srgrimes } else if (debug) 122837663Scharnier warnx("found ep fs=0x%x,0x%x", 12291558Srgrimes fsb.f_fsid.val[0], 12301558Srgrimes fsb.f_fsid.val[1]); 12311558Srgrimes } 12321558Srgrimes 12331558Srgrimes /* 12341558Srgrimes * Add dirpath to export mount point. 12351558Srgrimes */ 12361558Srgrimes dirp = add_expdir(&dirhead, cp, len); 12371558Srgrimes dirplen = len; 12381558Srgrimes } else { 12391558Srgrimes getexp_err(ep, tgrp); 12401558Srgrimes goto nextline; 12411558Srgrimes } 12421558Srgrimes *endcp = savedc; 12431558Srgrimes } else { 12441558Srgrimes savedc = *endcp; 12451558Srgrimes *endcp = '\0'; 12461558Srgrimes got_nondir = 1; 12471558Srgrimes if (ep == (struct exportlist *)NULL) { 12481558Srgrimes getexp_err(ep, tgrp); 12491558Srgrimes goto nextline; 12501558Srgrimes } 12511558Srgrimes 12521558Srgrimes /* 12531558Srgrimes * Get the host or netgroup. 12541558Srgrimes */ 12551558Srgrimes setnetgrent(cp); 12561558Srgrimes netgrp = getnetgrent(&hst, &usr, &dom); 12571558Srgrimes do { 12581558Srgrimes if (has_host) { 12591558Srgrimes grp->gr_next = get_grp(); 12601558Srgrimes grp = grp->gr_next; 12611558Srgrimes } 12621558Srgrimes if (netgrp) { 126337003Sjoerg if (hst == 0) { 126437663Scharnier syslog(LOG_ERR, 126537663Scharnier "null hostname in netgroup %s, skipping", cp); 126637004Sjoerg grp->gr_type = GT_IGNORE; 126737003Sjoerg } else if (get_host(hst, grp, tgrp)) { 126837663Scharnier syslog(LOG_ERR, 126937663Scharnier "bad host %s in netgroup %s, skipping", hst, cp); 127029317Sjlemon grp->gr_type = GT_IGNORE; 12711558Srgrimes } 12727401Swpaul } else if (get_host(cp, grp, tgrp)) { 127337663Scharnier syslog(LOG_ERR, "bad host %s, skipping", cp); 127429317Sjlemon grp->gr_type = GT_IGNORE; 12751558Srgrimes } 12761558Srgrimes has_host = TRUE; 12771558Srgrimes } while (netgrp && getnetgrent(&hst, &usr, &dom)); 12781558Srgrimes endnetgrent(); 12791558Srgrimes *endcp = savedc; 12801558Srgrimes } 12811558Srgrimes cp = endcp; 12821558Srgrimes nextfield(&cp, &endcp); 12831558Srgrimes len = endcp - cp; 12841558Srgrimes } 12851558Srgrimes if (check_options(dirhead)) { 12861558Srgrimes getexp_err(ep, tgrp); 12871558Srgrimes goto nextline; 12881558Srgrimes } 12891558Srgrimes if (!has_host) { 129075641Siedowse grp->gr_type = GT_DEFAULT; 12911558Srgrimes if (debug) 129237663Scharnier warnx("adding a default entry"); 12931558Srgrimes 12941558Srgrimes /* 12951558Srgrimes * Don't allow a network export coincide with a list of 12961558Srgrimes * host(s) on the same line. 12971558Srgrimes */ 12981558Srgrimes } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 129975801Siedowse syslog(LOG_ERR, "network/host conflict"); 13001558Srgrimes getexp_err(ep, tgrp); 13011558Srgrimes goto nextline; 130229317Sjlemon 130374462Salfred /* 130474462Salfred * If an export list was specified on this line, make sure 130529317Sjlemon * that we have at least one valid entry, otherwise skip it. 130629317Sjlemon */ 130729317Sjlemon } else { 130829317Sjlemon grp = tgrp; 130974462Salfred while (grp && grp->gr_type == GT_IGNORE) 131029317Sjlemon grp = grp->gr_next; 131129317Sjlemon if (! grp) { 131229317Sjlemon getexp_err(ep, tgrp); 131329317Sjlemon goto nextline; 131429317Sjlemon } 13151558Srgrimes } 13161558Srgrimes 13171558Srgrimes /* 13181558Srgrimes * Loop through hosts, pushing the exports into the kernel. 13191558Srgrimes * After loop, tgrp points to the start of the list and 13201558Srgrimes * grp points to the last entry in the list. 13211558Srgrimes */ 13221558Srgrimes grp = tgrp; 13231558Srgrimes do { 132475635Siedowse if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 132575635Siedowse &fsb)) { 132675635Siedowse getexp_err(ep, tgrp); 132775635Siedowse goto nextline; 132875635Siedowse } 13291558Srgrimes } while (grp->gr_next && (grp = grp->gr_next)); 13301558Srgrimes 13311558Srgrimes /* 13321558Srgrimes * Success. Update the data structures. 13331558Srgrimes */ 13341558Srgrimes if (has_host) { 13359336Sdfr hang_dirp(dirhead, tgrp, ep, opt_flags); 13361558Srgrimes grp->gr_next = grphead; 13371558Srgrimes grphead = tgrp; 13381558Srgrimes } else { 13391558Srgrimes hang_dirp(dirhead, (struct grouplist *)NULL, ep, 13409336Sdfr opt_flags); 13411558Srgrimes free_grp(grp); 13421558Srgrimes } 13431558Srgrimes dirhead = (struct dirlist *)NULL; 13441558Srgrimes if ((ep->ex_flag & EX_LINKED) == 0) { 13451558Srgrimes ep2 = exphead; 13461558Srgrimes epp = &exphead; 13471558Srgrimes 13481558Srgrimes /* 13491558Srgrimes * Insert in the list in alphabetical order. 13501558Srgrimes */ 13511558Srgrimes while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 13521558Srgrimes epp = &ep2->ex_next; 13531558Srgrimes ep2 = ep2->ex_next; 13541558Srgrimes } 13551558Srgrimes if (ep2) 13561558Srgrimes ep->ex_next = ep2; 13571558Srgrimes *epp = ep; 13581558Srgrimes ep->ex_flag |= EX_LINKED; 13591558Srgrimes } 13601558Srgrimesnextline: 13611558Srgrimes if (dirhead) { 13621558Srgrimes free_dir(dirhead); 13631558Srgrimes dirhead = (struct dirlist *)NULL; 13641558Srgrimes } 13651558Srgrimes } 13661558Srgrimes} 13671558Srgrimes 13681558Srgrimes/* 1369166440Spjd * Get the export list from all specified files 1370166440Spjd */ 1371166440Spjdvoid 1372166440Spjdget_exportlist() 1373166440Spjd{ 1374166440Spjd struct exportlist *ep, *ep2; 1375166440Spjd struct grouplist *grp, *tgrp; 1376166440Spjd struct export_args export; 1377166440Spjd struct iovec *iov; 1378166440Spjd struct statfs *fsp, *mntbufp; 1379166440Spjd struct xvfsconf vfc; 1380166440Spjd char *dirp; 1381166440Spjd char errmsg[255]; 1382166440Spjd int dirplen, num, i; 1383166440Spjd int iovlen; 1384168684Spjd int done; 1385166440Spjd 1386166440Spjd bzero(&export, sizeof(export)); 1387166440Spjd export.ex_flags = MNT_DELEXPORT; 1388166440Spjd dirp = NULL; 1389166440Spjd dirplen = 0; 1390166440Spjd iov = NULL; 1391166440Spjd iovlen = 0; 1392166440Spjd bzero(errmsg, sizeof(errmsg)); 1393166440Spjd 1394166440Spjd /* 1395166440Spjd * First, get rid of the old list 1396166440Spjd */ 1397166440Spjd ep = exphead; 1398166440Spjd while (ep) { 1399166440Spjd ep2 = ep; 1400166440Spjd ep = ep->ex_next; 1401166440Spjd free_exp(ep2); 1402166440Spjd } 1403166440Spjd exphead = (struct exportlist *)NULL; 1404166440Spjd 1405166440Spjd grp = grphead; 1406166440Spjd while (grp) { 1407166440Spjd tgrp = grp; 1408166440Spjd grp = grp->gr_next; 1409166440Spjd free_grp(tgrp); 1410166440Spjd } 1411166440Spjd grphead = (struct grouplist *)NULL; 1412166440Spjd 1413166440Spjd /* 1414166440Spjd * And delete exports that are in the kernel for all local 1415166440Spjd * filesystems. 1416166440Spjd * XXX: Should know how to handle all local exportable filesystems. 1417166440Spjd */ 1418166440Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1419166440Spjd 1420166440Spjd if (num > 0) { 1421166440Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1422166440Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1423166440Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1424166440Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1425166440Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1426166440Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1427166440Spjd } 1428166440Spjd 1429166440Spjd for (i = 0; i < num; i++) { 1430166440Spjd fsp = &mntbufp[i]; 1431166440Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1432166440Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1433166440Spjd fsp->f_fstypename); 1434166440Spjd continue; 1435166440Spjd } 1436166440Spjd 1437166440Spjd /* 1438166440Spjd * Do not delete export for network filesystem by 1439166440Spjd * passing "export" arg to nmount(). 1440166440Spjd * It only makes sense to do this for local filesystems. 1441166440Spjd */ 1442166440Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1443166440Spjd continue; 1444166440Spjd 1445166440Spjd iov[1].iov_base = fsp->f_fstypename; 1446166440Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1447166440Spjd iov[3].iov_base = fsp->f_mntonname; 1448166440Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1449166440Spjd iov[5].iov_base = fsp->f_mntfromname; 1450166440Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1451166440Spjd 1452166440Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1453166440Spjd errno != ENOENT && errno != ENOTSUP) { 1454166440Spjd syslog(LOG_ERR, 1455166440Spjd "can't delete exports for %s: %m %s", 1456166440Spjd fsp->f_mntonname, errmsg); 1457166440Spjd } 1458166440Spjd } 1459166440Spjd 1460166440Spjd if (iov != NULL) { 1461166440Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1462166440Spjd free(iov[0].iov_base); /* fstype */ 1463166440Spjd free(iov[2].iov_base); /* fspath */ 1464166440Spjd free(iov[4].iov_base); /* from */ 1465166440Spjd free(iov[6].iov_base); /* update */ 1466166440Spjd free(iov[8].iov_base); /* export */ 1467166440Spjd free(iov[10].iov_base); /* errmsg */ 1468166440Spjd 1469166440Spjd /* free iov, allocated by realloc() */ 1470166440Spjd free(iov); 1471166440Spjd iovlen = 0; 1472166440Spjd } 1473166440Spjd 1474166440Spjd /* 1475166440Spjd * Read in the exports file and build the list, calling 1476166440Spjd * nmount() as we go along to push the export rules into the kernel. 1477166440Spjd */ 1478168684Spjd done = 0; 1479166440Spjd for (i = 0; exnames[i] != NULL; i++) { 1480166440Spjd if (debug) 1481166440Spjd warnx("reading exports from %s", exnames[i]); 1482166440Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1483168684Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1484168684Spjd continue; 1485166440Spjd } 1486166440Spjd get_exportlist_one(); 1487166440Spjd fclose(exp_file); 1488168684Spjd done++; 1489166440Spjd } 1490168684Spjd if (done == 0) { 1491168684Spjd syslog(LOG_ERR, "can't open any exports file"); 1492168684Spjd exit(2); 1493168684Spjd } 1494166440Spjd} 1495166440Spjd 1496166440Spjd/* 14971558Srgrimes * Allocate an export list element 14981558Srgrimes */ 14991558Srgrimesstruct exportlist * 15001558Srgrimesget_exp() 15011558Srgrimes{ 15021558Srgrimes struct exportlist *ep; 15031558Srgrimes 15041558Srgrimes ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 15051558Srgrimes if (ep == (struct exportlist *)NULL) 15061558Srgrimes out_of_mem(); 150723681Speter memset(ep, 0, sizeof(struct exportlist)); 15081558Srgrimes return (ep); 15091558Srgrimes} 15101558Srgrimes 15111558Srgrimes/* 15121558Srgrimes * Allocate a group list element 15131558Srgrimes */ 15141558Srgrimesstruct grouplist * 15151558Srgrimesget_grp() 15161558Srgrimes{ 15171558Srgrimes struct grouplist *gp; 15181558Srgrimes 15191558Srgrimes gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 15201558Srgrimes if (gp == (struct grouplist *)NULL) 15211558Srgrimes out_of_mem(); 152223681Speter memset(gp, 0, sizeof(struct grouplist)); 15231558Srgrimes return (gp); 15241558Srgrimes} 15251558Srgrimes 15261558Srgrimes/* 15271558Srgrimes * Clean up upon an error in get_exportlist(). 15281558Srgrimes */ 15291558Srgrimesvoid 15301558Srgrimesgetexp_err(ep, grp) 15311558Srgrimes struct exportlist *ep; 15321558Srgrimes struct grouplist *grp; 15331558Srgrimes{ 15341558Srgrimes struct grouplist *tgrp; 15351558Srgrimes 1536100336Sjoerg if (!(opt_flags & OP_QUIET)) 1537100336Sjoerg syslog(LOG_ERR, "bad exports list line %s", line); 15381558Srgrimes if (ep && (ep->ex_flag & EX_LINKED) == 0) 15391558Srgrimes free_exp(ep); 15401558Srgrimes while (grp) { 15411558Srgrimes tgrp = grp; 15421558Srgrimes grp = grp->gr_next; 15431558Srgrimes free_grp(tgrp); 15441558Srgrimes } 15451558Srgrimes} 15461558Srgrimes 15471558Srgrimes/* 15481558Srgrimes * Search the export list for a matching fs. 15491558Srgrimes */ 15501558Srgrimesstruct exportlist * 15511558Srgrimesex_search(fsid) 15521558Srgrimes fsid_t *fsid; 15531558Srgrimes{ 15541558Srgrimes struct exportlist *ep; 15551558Srgrimes 15561558Srgrimes ep = exphead; 15571558Srgrimes while (ep) { 15581558Srgrimes if (ep->ex_fs.val[0] == fsid->val[0] && 15591558Srgrimes ep->ex_fs.val[1] == fsid->val[1]) 15601558Srgrimes return (ep); 15611558Srgrimes ep = ep->ex_next; 15621558Srgrimes } 15631558Srgrimes return (ep); 15641558Srgrimes} 15651558Srgrimes 15661558Srgrimes/* 15671558Srgrimes * Add a directory path to the list. 15681558Srgrimes */ 15691558Srgrimeschar * 15701558Srgrimesadd_expdir(dpp, cp, len) 15711558Srgrimes struct dirlist **dpp; 15721558Srgrimes char *cp; 15731558Srgrimes int len; 15741558Srgrimes{ 15751558Srgrimes struct dirlist *dp; 15761558Srgrimes 15771558Srgrimes dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 157837663Scharnier if (dp == (struct dirlist *)NULL) 157937663Scharnier out_of_mem(); 15801558Srgrimes dp->dp_left = *dpp; 15811558Srgrimes dp->dp_right = (struct dirlist *)NULL; 15821558Srgrimes dp->dp_flag = 0; 15831558Srgrimes dp->dp_hosts = (struct hostlist *)NULL; 15841558Srgrimes strcpy(dp->dp_dirp, cp); 15851558Srgrimes *dpp = dp; 15861558Srgrimes return (dp->dp_dirp); 15871558Srgrimes} 15881558Srgrimes 15891558Srgrimes/* 15901558Srgrimes * Hang the dir list element off the dirpath binary tree as required 15911558Srgrimes * and update the entry for host. 15921558Srgrimes */ 15931558Srgrimesvoid 15949336Sdfrhang_dirp(dp, grp, ep, flags) 15951558Srgrimes struct dirlist *dp; 15961558Srgrimes struct grouplist *grp; 15971558Srgrimes struct exportlist *ep; 15989336Sdfr int flags; 15991558Srgrimes{ 16001558Srgrimes struct hostlist *hp; 16011558Srgrimes struct dirlist *dp2; 16021558Srgrimes 16039336Sdfr if (flags & OP_ALLDIRS) { 16041558Srgrimes if (ep->ex_defdir) 16051558Srgrimes free((caddr_t)dp); 16061558Srgrimes else 16071558Srgrimes ep->ex_defdir = dp; 16089336Sdfr if (grp == (struct grouplist *)NULL) { 16091558Srgrimes ep->ex_defdir->dp_flag |= DP_DEFSET; 16109336Sdfr } else while (grp) { 16111558Srgrimes hp = get_ht(); 16121558Srgrimes hp->ht_grp = grp; 16131558Srgrimes hp->ht_next = ep->ex_defdir->dp_hosts; 16141558Srgrimes ep->ex_defdir->dp_hosts = hp; 16151558Srgrimes grp = grp->gr_next; 16161558Srgrimes } 16171558Srgrimes } else { 16181558Srgrimes 16191558Srgrimes /* 162037663Scharnier * Loop through the directories adding them to the tree. 16211558Srgrimes */ 16221558Srgrimes while (dp) { 16231558Srgrimes dp2 = dp->dp_left; 16249336Sdfr add_dlist(&ep->ex_dirl, dp, grp, flags); 16251558Srgrimes dp = dp2; 16261558Srgrimes } 16271558Srgrimes } 16281558Srgrimes} 16291558Srgrimes 16301558Srgrimes/* 16311558Srgrimes * Traverse the binary tree either updating a node that is already there 16321558Srgrimes * for the new directory or adding the new node. 16331558Srgrimes */ 16341558Srgrimesvoid 16359336Sdfradd_dlist(dpp, newdp, grp, flags) 16361558Srgrimes struct dirlist **dpp; 16371558Srgrimes struct dirlist *newdp; 16381558Srgrimes struct grouplist *grp; 16399336Sdfr int flags; 16401558Srgrimes{ 16411558Srgrimes struct dirlist *dp; 16421558Srgrimes struct hostlist *hp; 16431558Srgrimes int cmp; 16441558Srgrimes 16451558Srgrimes dp = *dpp; 16461558Srgrimes if (dp) { 16471558Srgrimes cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 16481558Srgrimes if (cmp > 0) { 16499336Sdfr add_dlist(&dp->dp_left, newdp, grp, flags); 16501558Srgrimes return; 16511558Srgrimes } else if (cmp < 0) { 16529336Sdfr add_dlist(&dp->dp_right, newdp, grp, flags); 16531558Srgrimes return; 16541558Srgrimes } else 16551558Srgrimes free((caddr_t)newdp); 16561558Srgrimes } else { 16571558Srgrimes dp = newdp; 16581558Srgrimes dp->dp_left = (struct dirlist *)NULL; 16591558Srgrimes *dpp = dp; 16601558Srgrimes } 16611558Srgrimes if (grp) { 16621558Srgrimes 16631558Srgrimes /* 16641558Srgrimes * Hang all of the host(s) off of the directory point. 16651558Srgrimes */ 16661558Srgrimes do { 16671558Srgrimes hp = get_ht(); 16681558Srgrimes hp->ht_grp = grp; 16691558Srgrimes hp->ht_next = dp->dp_hosts; 16701558Srgrimes dp->dp_hosts = hp; 16711558Srgrimes grp = grp->gr_next; 16721558Srgrimes } while (grp); 16739336Sdfr } else { 16741558Srgrimes dp->dp_flag |= DP_DEFSET; 16759336Sdfr } 16761558Srgrimes} 16771558Srgrimes 16781558Srgrimes/* 16791558Srgrimes * Search for a dirpath on the export point. 16801558Srgrimes */ 16811558Srgrimesstruct dirlist * 168274462Salfreddirp_search(dp, dirp) 16831558Srgrimes struct dirlist *dp; 168474462Salfred char *dirp; 16851558Srgrimes{ 16861558Srgrimes int cmp; 16871558Srgrimes 16881558Srgrimes if (dp) { 168974462Salfred cmp = strcmp(dp->dp_dirp, dirp); 16901558Srgrimes if (cmp > 0) 169174462Salfred return (dirp_search(dp->dp_left, dirp)); 16921558Srgrimes else if (cmp < 0) 169374462Salfred return (dirp_search(dp->dp_right, dirp)); 16941558Srgrimes else 16951558Srgrimes return (dp); 16961558Srgrimes } 16971558Srgrimes return (dp); 16981558Srgrimes} 16991558Srgrimes 17001558Srgrimes/* 17011558Srgrimes * Scan for a host match in a directory tree. 17021558Srgrimes */ 17031558Srgrimesint 17049336Sdfrchk_host(dp, saddr, defsetp, hostsetp) 17051558Srgrimes struct dirlist *dp; 170674462Salfred struct sockaddr *saddr; 17071558Srgrimes int *defsetp; 17089336Sdfr int *hostsetp; 17091558Srgrimes{ 17101558Srgrimes struct hostlist *hp; 17111558Srgrimes struct grouplist *grp; 171274462Salfred struct addrinfo *ai; 17131558Srgrimes 17141558Srgrimes if (dp) { 17151558Srgrimes if (dp->dp_flag & DP_DEFSET) 17169336Sdfr *defsetp = dp->dp_flag; 17171558Srgrimes hp = dp->dp_hosts; 17181558Srgrimes while (hp) { 17191558Srgrimes grp = hp->ht_grp; 17201558Srgrimes switch (grp->gr_type) { 17211558Srgrimes case GT_HOST: 172274462Salfred ai = grp->gr_ptr.gt_addrinfo; 172374462Salfred for (; ai; ai = ai->ai_next) { 172475801Siedowse if (!sacmp(ai->ai_addr, saddr, NULL)) { 172574462Salfred *hostsetp = 172674462Salfred (hp->ht_flag | DP_HOSTSET); 172774462Salfred return (1); 172874462Salfred } 17299336Sdfr } 173075801Siedowse break; 17311558Srgrimes case GT_NET: 173275801Siedowse if (!sacmp(saddr, (struct sockaddr *) 173375801Siedowse &grp->gr_ptr.gt_net.nt_net, 173475801Siedowse (struct sockaddr *) 173575801Siedowse &grp->gr_ptr.gt_net.nt_mask)) { 173674462Salfred *hostsetp = (hp->ht_flag | DP_HOSTSET); 173774462Salfred return (1); 173874462Salfred } 173975801Siedowse break; 174075801Siedowse } 17411558Srgrimes hp = hp->ht_next; 17421558Srgrimes } 17431558Srgrimes } 17441558Srgrimes return (0); 17451558Srgrimes} 17461558Srgrimes 17471558Srgrimes/* 17481558Srgrimes * Scan tree for a host that matches the address. 17491558Srgrimes */ 17501558Srgrimesint 17511558Srgrimesscan_tree(dp, saddr) 17521558Srgrimes struct dirlist *dp; 175374462Salfred struct sockaddr *saddr; 17541558Srgrimes{ 17559336Sdfr int defset, hostset; 17561558Srgrimes 17571558Srgrimes if (dp) { 17581558Srgrimes if (scan_tree(dp->dp_left, saddr)) 17591558Srgrimes return (1); 17609336Sdfr if (chk_host(dp, saddr, &defset, &hostset)) 17611558Srgrimes return (1); 17621558Srgrimes if (scan_tree(dp->dp_right, saddr)) 17631558Srgrimes return (1); 17641558Srgrimes } 17651558Srgrimes return (0); 17661558Srgrimes} 17671558Srgrimes 17681558Srgrimes/* 17691558Srgrimes * Traverse the dirlist tree and free it up. 17701558Srgrimes */ 17711558Srgrimesvoid 17721558Srgrimesfree_dir(dp) 17731558Srgrimes struct dirlist *dp; 17741558Srgrimes{ 17751558Srgrimes 17761558Srgrimes if (dp) { 17771558Srgrimes free_dir(dp->dp_left); 17781558Srgrimes free_dir(dp->dp_right); 17791558Srgrimes free_host(dp->dp_hosts); 17801558Srgrimes free((caddr_t)dp); 17811558Srgrimes } 17821558Srgrimes} 17831558Srgrimes 17841558Srgrimes/* 1785184588Sdfr * Parse a colon separated list of security flavors 1786184588Sdfr */ 1787184588Sdfrint 1788184588Sdfrparsesec(seclist, ep) 1789184588Sdfr char *seclist; 1790184588Sdfr struct exportlist *ep; 1791184588Sdfr{ 1792184588Sdfr char *cp, savedc; 1793184588Sdfr int flavor; 1794184588Sdfr 1795184588Sdfr ep->ex_numsecflavors = 0; 1796184588Sdfr for (;;) { 1797184588Sdfr cp = strchr(seclist, ':'); 1798184588Sdfr if (cp) { 1799184588Sdfr savedc = *cp; 1800184588Sdfr *cp = '\0'; 1801184588Sdfr } 1802184588Sdfr 1803184588Sdfr if (!strcmp(seclist, "sys")) 1804184588Sdfr flavor = AUTH_SYS; 1805184588Sdfr else if (!strcmp(seclist, "krb5")) 1806184588Sdfr flavor = RPCSEC_GSS_KRB5; 1807184588Sdfr else if (!strcmp(seclist, "krb5i")) 1808184588Sdfr flavor = RPCSEC_GSS_KRB5I; 1809184588Sdfr else if (!strcmp(seclist, "krb5p")) 1810184588Sdfr flavor = RPCSEC_GSS_KRB5P; 1811184588Sdfr else { 1812184588Sdfr if (cp) 1813184588Sdfr *cp = savedc; 1814184588Sdfr syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1815184588Sdfr return (1); 1816184588Sdfr } 1817184588Sdfr if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1818184588Sdfr if (cp) 1819184588Sdfr *cp = savedc; 1820184588Sdfr syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1821184588Sdfr return (1); 1822184588Sdfr } 1823184588Sdfr ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1824184588Sdfr ep->ex_numsecflavors++; 1825184588Sdfr if (cp) { 1826184588Sdfr *cp = savedc; 1827184588Sdfr seclist = cp + 1; 1828184588Sdfr } else { 1829184588Sdfr break; 1830184588Sdfr } 1831184588Sdfr } 1832184588Sdfr return (0); 1833184588Sdfr} 1834184588Sdfr 1835184588Sdfr/* 18361558Srgrimes * Parse the option string and update fields. 18371558Srgrimes * Option arguments may either be -<option>=<value> or 18381558Srgrimes * -<option> <value> 18391558Srgrimes */ 18401558Srgrimesint 18411558Srgrimesdo_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 18421558Srgrimes char **cpp, **endcpp; 18431558Srgrimes struct exportlist *ep; 18441558Srgrimes struct grouplist *grp; 18451558Srgrimes int *has_hostp; 18461558Srgrimes int *exflagsp; 184772650Sgreen struct xucred *cr; 18481558Srgrimes{ 18491558Srgrimes char *cpoptarg, *cpoptend; 18501558Srgrimes char *cp, *endcp, *cpopt, savedc, savedc2; 18511558Srgrimes int allflag, usedarg; 18521558Srgrimes 185351968Salfred savedc2 = '\0'; 18541558Srgrimes cpopt = *cpp; 18551558Srgrimes cpopt++; 18561558Srgrimes cp = *endcpp; 18571558Srgrimes savedc = *cp; 18581558Srgrimes *cp = '\0'; 18591558Srgrimes while (cpopt && *cpopt) { 18601558Srgrimes allflag = 1; 18611558Srgrimes usedarg = -2; 186237663Scharnier if ((cpoptend = strchr(cpopt, ','))) { 18631558Srgrimes *cpoptend++ = '\0'; 186437663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 18651558Srgrimes *cpoptarg++ = '\0'; 18661558Srgrimes } else { 186737663Scharnier if ((cpoptarg = strchr(cpopt, '='))) 18681558Srgrimes *cpoptarg++ = '\0'; 18691558Srgrimes else { 18701558Srgrimes *cp = savedc; 18711558Srgrimes nextfield(&cp, &endcp); 18721558Srgrimes **endcpp = '\0'; 18731558Srgrimes if (endcp > cp && *cp != '-') { 18741558Srgrimes cpoptarg = cp; 18751558Srgrimes savedc2 = *endcp; 18761558Srgrimes *endcp = '\0'; 18771558Srgrimes usedarg = 0; 18781558Srgrimes } 18791558Srgrimes } 18801558Srgrimes } 18811558Srgrimes if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 18821558Srgrimes *exflagsp |= MNT_EXRDONLY; 18831558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 18841558Srgrimes !(allflag = strcmp(cpopt, "mapall")) || 18851558Srgrimes !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 18861558Srgrimes usedarg++; 18871558Srgrimes parsecred(cpoptarg, cr); 18881558Srgrimes if (allflag == 0) { 18891558Srgrimes *exflagsp |= MNT_EXPORTANON; 18901558Srgrimes opt_flags |= OP_MAPALL; 18911558Srgrimes } else 18921558Srgrimes opt_flags |= OP_MAPROOT; 18931558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "mask") || 189475801Siedowse !strcmp(cpopt, "m"))) { 18951558Srgrimes if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 189637663Scharnier syslog(LOG_ERR, "bad mask: %s", cpoptarg); 18971558Srgrimes return (1); 18981558Srgrimes } 18991558Srgrimes usedarg++; 19001558Srgrimes opt_flags |= OP_MASK; 19011558Srgrimes } else if (cpoptarg && (!strcmp(cpopt, "network") || 19021558Srgrimes !strcmp(cpopt, "n"))) { 190374462Salfred if (strchr(cpoptarg, '/') != NULL) { 190474462Salfred if (debug) 190574462Salfred fprintf(stderr, "setting OP_MASKLEN\n"); 190674462Salfred opt_flags |= OP_MASKLEN; 190774462Salfred } 19081558Srgrimes if (grp->gr_type != GT_NULL) { 190937663Scharnier syslog(LOG_ERR, "network/host conflict"); 19101558Srgrimes return (1); 19111558Srgrimes } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 191237663Scharnier syslog(LOG_ERR, "bad net: %s", cpoptarg); 19131558Srgrimes return (1); 19141558Srgrimes } 19151558Srgrimes grp->gr_type = GT_NET; 19161558Srgrimes *has_hostp = 1; 19171558Srgrimes usedarg++; 19181558Srgrimes opt_flags |= OP_NET; 19191558Srgrimes } else if (!strcmp(cpopt, "alldirs")) { 19201558Srgrimes opt_flags |= OP_ALLDIRS; 192127447Sdfr } else if (!strcmp(cpopt, "public")) { 192227447Sdfr *exflagsp |= MNT_EXPUBLIC; 192327447Sdfr } else if (!strcmp(cpopt, "webnfs")) { 192427447Sdfr *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 192527447Sdfr opt_flags |= OP_MAPALL; 192627447Sdfr } else if (cpoptarg && !strcmp(cpopt, "index")) { 192727447Sdfr ep->ex_indexfile = strdup(cpoptarg); 1928100336Sjoerg } else if (!strcmp(cpopt, "quiet")) { 1929100336Sjoerg opt_flags |= OP_QUIET; 1930184588Sdfr } else if (!strcmp(cpopt, "sec")) { 1931184588Sdfr if (parsesec(cpoptarg, ep)) 1932184588Sdfr return (1); 1933184588Sdfr opt_flags |= OP_SEC; 1934184588Sdfr usedarg++; 19351558Srgrimes } else { 193637663Scharnier syslog(LOG_ERR, "bad opt %s", cpopt); 19371558Srgrimes return (1); 19381558Srgrimes } 19391558Srgrimes if (usedarg >= 0) { 19401558Srgrimes *endcp = savedc2; 19411558Srgrimes **endcpp = savedc; 19421558Srgrimes if (usedarg > 0) { 19431558Srgrimes *cpp = cp; 19441558Srgrimes *endcpp = endcp; 19451558Srgrimes } 19461558Srgrimes return (0); 19471558Srgrimes } 19481558Srgrimes cpopt = cpoptend; 19491558Srgrimes } 19501558Srgrimes **endcpp = savedc; 19511558Srgrimes return (0); 19521558Srgrimes} 19531558Srgrimes 19541558Srgrimes/* 19551558Srgrimes * Translate a character string to the corresponding list of network 19561558Srgrimes * addresses for a hostname. 19571558Srgrimes */ 19581558Srgrimesint 19597401Swpaulget_host(cp, grp, tgrp) 19601558Srgrimes char *cp; 19611558Srgrimes struct grouplist *grp; 19627401Swpaul struct grouplist *tgrp; 19631558Srgrimes{ 19647401Swpaul struct grouplist *checkgrp; 196575635Siedowse struct addrinfo *ai, *tai, hints; 196674462Salfred int ecode; 196774462Salfred char host[NI_MAXHOST]; 19681558Srgrimes 196974462Salfred if (grp->gr_type != GT_NULL) { 197074462Salfred syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 19711558Srgrimes return (1); 19721558Srgrimes } 197374462Salfred memset(&hints, 0, sizeof hints); 197474462Salfred hints.ai_flags = AI_CANONNAME; 197574462Salfred hints.ai_protocol = IPPROTO_UDP; 197674462Salfred ecode = getaddrinfo(cp, NULL, &hints, &ai); 197774462Salfred if (ecode != 0) { 197875635Siedowse syslog(LOG_ERR,"can't get address info for host %s", cp); 197974462Salfred return 1; 198074462Salfred } 198174462Salfred grp->gr_ptr.gt_addrinfo = ai; 198274462Salfred while (ai != NULL) { 198374462Salfred if (ai->ai_canonname == NULL) { 198474462Salfred if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1985146187Sume sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 198674462Salfred strlcpy(host, "?", sizeof(host)); 198774462Salfred ai->ai_canonname = strdup(host); 198874462Salfred ai->ai_flags |= AI_CANONNAME; 198975641Siedowse } 199074462Salfred if (debug) 199175635Siedowse fprintf(stderr, "got host %s\n", ai->ai_canonname); 199275635Siedowse /* 199375635Siedowse * Sanity check: make sure we don't already have an entry 199475635Siedowse * for this host in the grouplist. 199575635Siedowse */ 199675635Siedowse for (checkgrp = tgrp; checkgrp != NULL; 199775635Siedowse checkgrp = checkgrp->gr_next) { 199875635Siedowse if (checkgrp->gr_type != GT_HOST) 199975635Siedowse continue; 200075635Siedowse for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 200175635Siedowse tai = tai->ai_next) { 200275801Siedowse if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 200375635Siedowse continue; 200475635Siedowse if (debug) 200575635Siedowse fprintf(stderr, 200675635Siedowse "ignoring duplicate host %s\n", 200775635Siedowse ai->ai_canonname); 200875635Siedowse grp->gr_type = GT_IGNORE; 200975635Siedowse return (0); 201075635Siedowse } 201175635Siedowse } 201274462Salfred ai = ai->ai_next; 20131558Srgrimes } 201475635Siedowse grp->gr_type = GT_HOST; 20151558Srgrimes return (0); 20161558Srgrimes} 20171558Srgrimes 20181558Srgrimes/* 20191558Srgrimes * Free up an exports list component 20201558Srgrimes */ 20211558Srgrimesvoid 20221558Srgrimesfree_exp(ep) 20231558Srgrimes struct exportlist *ep; 20241558Srgrimes{ 20251558Srgrimes 20261558Srgrimes if (ep->ex_defdir) { 20271558Srgrimes free_host(ep->ex_defdir->dp_hosts); 20281558Srgrimes free((caddr_t)ep->ex_defdir); 20291558Srgrimes } 20301558Srgrimes if (ep->ex_fsdir) 20311558Srgrimes free(ep->ex_fsdir); 203227447Sdfr if (ep->ex_indexfile) 203327447Sdfr free(ep->ex_indexfile); 20341558Srgrimes free_dir(ep->ex_dirl); 20351558Srgrimes free((caddr_t)ep); 20361558Srgrimes} 20371558Srgrimes 20381558Srgrimes/* 20391558Srgrimes * Free hosts. 20401558Srgrimes */ 20411558Srgrimesvoid 20421558Srgrimesfree_host(hp) 20431558Srgrimes struct hostlist *hp; 20441558Srgrimes{ 20451558Srgrimes struct hostlist *hp2; 20461558Srgrimes 20471558Srgrimes while (hp) { 20481558Srgrimes hp2 = hp; 20491558Srgrimes hp = hp->ht_next; 20501558Srgrimes free((caddr_t)hp2); 20511558Srgrimes } 20521558Srgrimes} 20531558Srgrimes 20541558Srgrimesstruct hostlist * 20551558Srgrimesget_ht() 20561558Srgrimes{ 20571558Srgrimes struct hostlist *hp; 20581558Srgrimes 20591558Srgrimes hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 20601558Srgrimes if (hp == (struct hostlist *)NULL) 20611558Srgrimes out_of_mem(); 20621558Srgrimes hp->ht_next = (struct hostlist *)NULL; 20639336Sdfr hp->ht_flag = 0; 20641558Srgrimes return (hp); 20651558Srgrimes} 20661558Srgrimes 20671558Srgrimes/* 20681558Srgrimes * Out of memory, fatal 20691558Srgrimes */ 20701558Srgrimesvoid 20711558Srgrimesout_of_mem() 20721558Srgrimes{ 20731558Srgrimes 207437663Scharnier syslog(LOG_ERR, "out of memory"); 20751558Srgrimes exit(2); 20761558Srgrimes} 20771558Srgrimes 20781558Srgrimes/* 2079158857Srodrigc * Do the nmount() syscall with the update flag to push the export info into 20801558Srgrimes * the kernel. 20811558Srgrimes */ 20821558Srgrimesint 2083158857Srodrigcdo_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2084158857Srodrigc struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 20851558Srgrimes{ 208675841Siedowse struct statfs fsb1; 208774462Salfred struct addrinfo *ai; 2088158857Srodrigc struct export_args eap; 2089158857Srodrigc char errmsg[255]; 2090158857Srodrigc char *cp; 20911558Srgrimes int done; 2092158857Srodrigc char savedc; 2093158857Srodrigc struct iovec *iov; 2094184588Sdfr int i, iovlen; 2095158857Srodrigc int ret; 20961558Srgrimes 2097158857Srodrigc cp = NULL; 2098158857Srodrigc savedc = '\0'; 2099158857Srodrigc iov = NULL; 2100158857Srodrigc iovlen = 0; 2101158857Srodrigc ret = 0; 210275801Siedowse 2103158857Srodrigc bzero(&eap, sizeof(eap)); 2104158857Srodrigc bzero(errmsg, sizeof(errmsg)); 2105158857Srodrigc eap.ex_flags = exflags; 2106158857Srodrigc eap.ex_anon = *anoncrp; 2107158857Srodrigc eap.ex_indexfile = ep->ex_indexfile; 210875641Siedowse if (grp->gr_type == GT_HOST) 210974462Salfred ai = grp->gr_ptr.gt_addrinfo; 211075641Siedowse else 211175641Siedowse ai = NULL; 2112184588Sdfr eap.ex_numsecflavors = ep->ex_numsecflavors; 2113184588Sdfr for (i = 0; i < eap.ex_numsecflavors; i++) 2114184588Sdfr eap.ex_secflavors[i] = ep->ex_secflavors[i]; 2115184588Sdfr if (eap.ex_numsecflavors == 0) { 2116184588Sdfr eap.ex_numsecflavors = 1; 2117184588Sdfr eap.ex_secflavors[0] = AUTH_SYS; 2118184588Sdfr } 21191558Srgrimes done = FALSE; 2120158857Srodrigc 2121158857Srodrigc build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2122158857Srodrigc build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2123158857Srodrigc build_iovec(&iov, &iovlen, "from", NULL, 0); 2124158857Srodrigc build_iovec(&iov, &iovlen, "update", NULL, 0); 2125158857Srodrigc build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap)); 2126158857Srodrigc build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2127158857Srodrigc 21281558Srgrimes while (!done) { 21291558Srgrimes switch (grp->gr_type) { 21301558Srgrimes case GT_HOST: 213175641Siedowse if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 213274462Salfred goto skip; 2133158857Srodrigc eap.ex_addr = ai->ai_addr; 2134158857Srodrigc eap.ex_addrlen = ai->ai_addrlen; 2135158857Srodrigc eap.ex_masklen = 0; 21361558Srgrimes break; 21371558Srgrimes case GT_NET: 213875801Siedowse if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 213974462Salfred have_v6 == 0) 214074462Salfred goto skip; 2141158857Srodrigc eap.ex_addr = 214275801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2143158857Srodrigc eap.ex_addrlen = 2144158857Srodrigc ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2145158857Srodrigc eap.ex_mask = 214675801Siedowse (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2147158857Srodrigc eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 21481558Srgrimes break; 214975641Siedowse case GT_DEFAULT: 2150158857Srodrigc eap.ex_addr = NULL; 2151158857Srodrigc eap.ex_addrlen = 0; 2152158857Srodrigc eap.ex_mask = NULL; 2153158857Srodrigc eap.ex_masklen = 0; 215475641Siedowse break; 21557401Swpaul case GT_IGNORE: 2156158857Srodrigc ret = 0; 2157158857Srodrigc goto error_exit; 21587401Swpaul break; 21591558Srgrimes default: 216037663Scharnier syslog(LOG_ERR, "bad grouptype"); 21611558Srgrimes if (cp) 21621558Srgrimes *cp = savedc; 2163158857Srodrigc ret = 1; 2164158857Srodrigc goto error_exit; 21651558Srgrimes }; 21661558Srgrimes 21671558Srgrimes /* 21681558Srgrimes * XXX: 21691558Srgrimes * Maybe I should just use the fsb->f_mntonname path instead 21701558Srgrimes * of looping back up the dirp to the mount point?? 21711558Srgrimes * Also, needs to know how to export all types of local 217296707Strhodes * exportable filesystems and not just "ufs". 21731558Srgrimes */ 2174158857Srodrigc iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2175158857Srodrigc iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2176158857Srodrigc iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2177158857Srodrigc iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2178158857Srodrigc iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2179158857Srodrigc iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2180158857Srodrigc 2181176819Srodrigc while (nmount(iov, iovlen, fsb->f_flags) < 0) { 21821558Srgrimes if (cp) 21831558Srgrimes *cp-- = savedc; 21841558Srgrimes else 21851558Srgrimes cp = dirp + dirplen - 1; 2186158857Srodrigc if (opt_flags & OP_QUIET) { 2187158857Srodrigc ret = 1; 2188158857Srodrigc goto error_exit; 2189158857Srodrigc } 21901558Srgrimes if (errno == EPERM) { 219175635Siedowse if (debug) 219275635Siedowse warnx("can't change attributes for %s", 219375635Siedowse dirp); 21941558Srgrimes syslog(LOG_ERR, 219537663Scharnier "can't change attributes for %s", dirp); 2196158857Srodrigc ret = 1; 2197158857Srodrigc goto error_exit; 21981558Srgrimes } 21991558Srgrimes if (opt_flags & OP_ALLDIRS) { 2200100336Sjoerg if (errno == EINVAL) 2201100336Sjoerg syslog(LOG_ERR, 2202100336Sjoerg "-alldirs requested but %s is not a filesystem mountpoint", 2203100336Sjoerg dirp); 2204100336Sjoerg else 2205100336Sjoerg syslog(LOG_ERR, 2206100336Sjoerg "could not remount %s: %m", 2207100336Sjoerg dirp); 2208158857Srodrigc ret = 1; 2209158857Srodrigc goto error_exit; 22101558Srgrimes } 22111558Srgrimes /* back up over the last component */ 22121558Srgrimes while (*cp == '/' && cp > dirp) 22131558Srgrimes cp--; 22141558Srgrimes while (*(cp - 1) != '/' && cp > dirp) 22151558Srgrimes cp--; 22161558Srgrimes if (cp == dirp) { 22171558Srgrimes if (debug) 221837663Scharnier warnx("mnt unsucc"); 2219166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 2220166258Srodrigc errmsg); 2221158857Srodrigc ret = 1; 2222158857Srodrigc goto error_exit; 22231558Srgrimes } 22241558Srgrimes savedc = *cp; 22251558Srgrimes *cp = '\0'; 222675841Siedowse /* Check that we're still on the same filesystem. */ 222775841Siedowse if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 222875841Siedowse &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 222975841Siedowse *cp = savedc; 2230166258Srodrigc syslog(LOG_ERR, "can't export %s %s", dirp, 2231166258Srodrigc errmsg); 2232158857Srodrigc ret = 1; 2233158857Srodrigc goto error_exit; 223475841Siedowse } 22351558Srgrimes } 223674462Salfredskip: 223775641Siedowse if (ai != NULL) 223874462Salfred ai = ai->ai_next; 223975641Siedowse if (ai == NULL) 22401558Srgrimes done = TRUE; 22411558Srgrimes } 22421558Srgrimes if (cp) 22431558Srgrimes *cp = savedc; 2244158857Srodrigcerror_exit: 2245158857Srodrigc /* free strings allocated by strdup() in getmntopts.c */ 2246158857Srodrigc if (iov != NULL) { 2247158857Srodrigc free(iov[0].iov_base); /* fstype */ 2248158857Srodrigc free(iov[2].iov_base); /* fspath */ 2249158857Srodrigc free(iov[4].iov_base); /* from */ 2250158857Srodrigc free(iov[6].iov_base); /* update */ 2251158857Srodrigc free(iov[8].iov_base); /* export */ 2252158857Srodrigc free(iov[10].iov_base); /* errmsg */ 2253158857Srodrigc 2254158857Srodrigc /* free iov, allocated by realloc() */ 2255158857Srodrigc free(iov); 2256158857Srodrigc } 2257158857Srodrigc return (ret); 22581558Srgrimes} 22591558Srgrimes 22601558Srgrimes/* 22611558Srgrimes * Translate a net address. 226275801Siedowse * 226375801Siedowse * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 22641558Srgrimes */ 22651558Srgrimesint 22661558Srgrimesget_net(cp, net, maskflg) 22671558Srgrimes char *cp; 22681558Srgrimes struct netmsk *net; 22691558Srgrimes int maskflg; 22701558Srgrimes{ 227175861Siedowse struct netent *np = NULL; 227274462Salfred char *name, *p, *prefp; 227375801Siedowse struct sockaddr_in sin; 227475861Siedowse struct sockaddr *sa = NULL; 227574462Salfred struct addrinfo hints, *ai = NULL; 227674462Salfred char netname[NI_MAXHOST]; 227774462Salfred long preflen; 22781558Srgrimes 227975635Siedowse p = prefp = NULL; 228074462Salfred if ((opt_flags & OP_MASKLEN) && !maskflg) { 228174462Salfred p = strchr(cp, '/'); 228274462Salfred *p = '\0'; 228374462Salfred prefp = p + 1; 228474462Salfred } 228574462Salfred 228675861Siedowse /* 228775861Siedowse * Check for a numeric address first. We wish to avoid 228875861Siedowse * possible DNS lookups in getnetbyname(). 228975861Siedowse */ 229075861Siedowse if (isxdigit(*cp) || *cp == ':') { 229174462Salfred memset(&hints, 0, sizeof hints); 229275801Siedowse /* Ensure the mask and the network have the same family. */ 229375801Siedowse if (maskflg && (opt_flags & OP_NET)) 229475801Siedowse hints.ai_family = net->nt_net.ss_family; 229575801Siedowse else if (!maskflg && (opt_flags & OP_HAVEMASK)) 229675801Siedowse hints.ai_family = net->nt_mask.ss_family; 229775801Siedowse else 229875801Siedowse hints.ai_family = AF_UNSPEC; 229974462Salfred hints.ai_flags = AI_NUMERICHOST; 230075861Siedowse if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 230175861Siedowse sa = ai->ai_addr; 230275861Siedowse if (sa != NULL && ai->ai_family == AF_INET) { 230374462Salfred /* 230475801Siedowse * The address in `cp' is really a network address, so 230575801Siedowse * use inet_network() to re-interpret this correctly. 230675801Siedowse * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 230774462Salfred */ 230875801Siedowse bzero(&sin, sizeof sin); 230974462Salfred sin.sin_family = AF_INET; 231074462Salfred sin.sin_len = sizeof sin; 231175801Siedowse sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 231274462Salfred if (debug) 231375801Siedowse fprintf(stderr, "get_net: v4 addr %s\n", 231475801Siedowse inet_ntoa(sin.sin_addr)); 231574462Salfred sa = (struct sockaddr *)&sin; 231675861Siedowse } 231775861Siedowse } 231875861Siedowse if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 231975861Siedowse bzero(&sin, sizeof sin); 232075861Siedowse sin.sin_family = AF_INET; 232175861Siedowse sin.sin_len = sizeof sin; 232275861Siedowse sin.sin_addr = inet_makeaddr(np->n_net, 0); 232375861Siedowse sa = (struct sockaddr *)&sin; 232475861Siedowse } 232575861Siedowse if (sa == NULL) 232674462Salfred goto fail; 232725318Spst 232875801Siedowse if (maskflg) { 232975801Siedowse /* The specified sockaddr is a mask. */ 233075801Siedowse if (checkmask(sa) != 0) 233175801Siedowse goto fail; 233275801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 233375801Siedowse opt_flags |= OP_HAVEMASK; 233475801Siedowse } else { 233575801Siedowse /* The specified sockaddr is a network address. */ 233675801Siedowse bcopy(sa, &net->nt_net, sa->sa_len); 233774462Salfred 233875801Siedowse /* Get a network name for the export list. */ 233975801Siedowse if (np) { 234075801Siedowse name = np->n_name; 234175801Siedowse } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2342146187Sume NULL, 0, NI_NUMERICHOST) == 0) { 234375801Siedowse name = netname; 234475801Siedowse } else { 234575801Siedowse goto fail; 234675801Siedowse } 234775801Siedowse if ((net->nt_name = strdup(name)) == NULL) 234875801Siedowse out_of_mem(); 234975801Siedowse 235075801Siedowse /* 235175801Siedowse * Extract a mask from either a "/<masklen>" suffix, or 235275801Siedowse * from the class of an IPv4 address. 235375801Siedowse */ 235474462Salfred if (opt_flags & OP_MASKLEN) { 235574462Salfred preflen = strtol(prefp, NULL, 10); 235675801Siedowse if (preflen < 0L || preflen == LONG_MAX) 235774462Salfred goto fail; 235875801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 235975801Siedowse if (makemask(&net->nt_mask, (int)preflen) != 0) 236075801Siedowse goto fail; 236175801Siedowse opt_flags |= OP_HAVEMASK; 236274462Salfred *p = '/'; 236375801Siedowse } else if (sa->sa_family == AF_INET && 236475801Siedowse (opt_flags & OP_MASK) == 0) { 236575801Siedowse in_addr_t addr; 236674462Salfred 236775801Siedowse addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 236875801Siedowse if (IN_CLASSA(addr)) 236975801Siedowse preflen = 8; 237075801Siedowse else if (IN_CLASSB(addr)) 237175801Siedowse preflen = 16; 237275801Siedowse else if (IN_CLASSC(addr)) 237375801Siedowse preflen = 24; 237475801Siedowse else if (IN_CLASSD(addr)) 237575801Siedowse preflen = 28; 237675801Siedowse else 237775801Siedowse preflen = 32; /* XXX */ 237875801Siedowse 237975801Siedowse bcopy(sa, &net->nt_mask, sa->sa_len); 238075801Siedowse makemask(&net->nt_mask, (int)preflen); 238175801Siedowse opt_flags |= OP_HAVEMASK; 238274462Salfred } 238374462Salfred } 238474462Salfred 238574462Salfred if (ai) 238674462Salfred freeaddrinfo(ai); 238774462Salfred return 0; 238874462Salfred 238974462Salfredfail: 239074462Salfred if (ai) 239174462Salfred freeaddrinfo(ai); 239274462Salfred return 1; 23931558Srgrimes} 23941558Srgrimes 23951558Srgrimes/* 23961558Srgrimes * Parse out the next white space separated field 23971558Srgrimes */ 23981558Srgrimesvoid 23991558Srgrimesnextfield(cp, endcp) 24001558Srgrimes char **cp; 24011558Srgrimes char **endcp; 24021558Srgrimes{ 24031558Srgrimes char *p; 24041558Srgrimes 24051558Srgrimes p = *cp; 24061558Srgrimes while (*p == ' ' || *p == '\t') 24071558Srgrimes p++; 24081558Srgrimes if (*p == '\n' || *p == '\0') 24091558Srgrimes *cp = *endcp = p; 24101558Srgrimes else { 24111558Srgrimes *cp = p++; 24121558Srgrimes while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 24131558Srgrimes p++; 24141558Srgrimes *endcp = p; 24151558Srgrimes } 24161558Srgrimes} 24171558Srgrimes 24181558Srgrimes/* 24191558Srgrimes * Get an exports file line. Skip over blank lines and handle line 24201558Srgrimes * continuations. 24211558Srgrimes */ 24221558Srgrimesint 24231558Srgrimesget_line() 24241558Srgrimes{ 24251558Srgrimes char *p, *cp; 242696622Siedowse size_t len; 24271558Srgrimes int totlen, cont_line; 24281558Srgrimes 24291558Srgrimes /* 24301558Srgrimes * Loop around ignoring blank lines and getting all continuation lines. 24311558Srgrimes */ 24321558Srgrimes p = line; 24331558Srgrimes totlen = 0; 24341558Srgrimes do { 243596622Siedowse if ((p = fgetln(exp_file, &len)) == NULL) 24361558Srgrimes return (0); 24371558Srgrimes cp = p + len - 1; 24381558Srgrimes cont_line = 0; 24391558Srgrimes while (cp >= p && 24401558Srgrimes (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 24411558Srgrimes if (*cp == '\\') 24421558Srgrimes cont_line = 1; 24431558Srgrimes cp--; 24441558Srgrimes len--; 24451558Srgrimes } 244679117Sdd if (cont_line) { 244779117Sdd *++cp = ' '; 244879117Sdd len++; 244979117Sdd } 245096622Siedowse if (linesize < len + totlen + 1) { 245196622Siedowse linesize = len + totlen + 1; 245296622Siedowse line = realloc(line, linesize); 245396622Siedowse if (line == NULL) 245496622Siedowse out_of_mem(); 24551558Srgrimes } 245696622Siedowse memcpy(line + totlen, p, len); 245796622Siedowse totlen += len; 245896622Siedowse line[totlen] = '\0'; 24591558Srgrimes } while (totlen == 0 || cont_line); 24601558Srgrimes return (1); 24611558Srgrimes} 24621558Srgrimes 24631558Srgrimes/* 24641558Srgrimes * Parse a description of a credential. 24651558Srgrimes */ 24661558Srgrimesvoid 24671558Srgrimesparsecred(namelist, cr) 24681558Srgrimes char *namelist; 246972650Sgreen struct xucred *cr; 24701558Srgrimes{ 24711558Srgrimes char *name; 24721558Srgrimes int cnt; 24731558Srgrimes char *names; 24741558Srgrimes struct passwd *pw; 24751558Srgrimes struct group *gr; 2476136051Sstefanf gid_t groups[NGROUPS + 1]; 2477136051Sstefanf int ngroups; 24781558Srgrimes 247991354Sdd cr->cr_version = XUCRED_VERSION; 24801558Srgrimes /* 248137663Scharnier * Set up the unprivileged user. 24821558Srgrimes */ 24831558Srgrimes cr->cr_uid = -2; 24841558Srgrimes cr->cr_groups[0] = -2; 24851558Srgrimes cr->cr_ngroups = 1; 24861558Srgrimes /* 24871558Srgrimes * Get the user's password table entry. 24881558Srgrimes */ 24891558Srgrimes names = strsep(&namelist, " \t\n"); 24901558Srgrimes name = strsep(&names, ":"); 24911558Srgrimes if (isdigit(*name) || *name == '-') 24921558Srgrimes pw = getpwuid(atoi(name)); 24931558Srgrimes else 24941558Srgrimes pw = getpwnam(name); 24951558Srgrimes /* 24961558Srgrimes * Credentials specified as those of a user. 24971558Srgrimes */ 24981558Srgrimes if (names == NULL) { 24991558Srgrimes if (pw == NULL) { 250037663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 25011558Srgrimes return; 25021558Srgrimes } 25031558Srgrimes cr->cr_uid = pw->pw_uid; 25041558Srgrimes ngroups = NGROUPS + 1; 25051558Srgrimes if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 250637663Scharnier syslog(LOG_ERR, "too many groups"); 25071558Srgrimes /* 2508136051Sstefanf * Compress out duplicate. 25091558Srgrimes */ 25101558Srgrimes cr->cr_ngroups = ngroups - 1; 25111558Srgrimes cr->cr_groups[0] = groups[0]; 25121558Srgrimes for (cnt = 2; cnt < ngroups; cnt++) 25131558Srgrimes cr->cr_groups[cnt - 1] = groups[cnt]; 25141558Srgrimes return; 25151558Srgrimes } 25161558Srgrimes /* 25171558Srgrimes * Explicit credential specified as a colon separated list: 25181558Srgrimes * uid:gid:gid:... 25191558Srgrimes */ 25201558Srgrimes if (pw != NULL) 25211558Srgrimes cr->cr_uid = pw->pw_uid; 25221558Srgrimes else if (isdigit(*name) || *name == '-') 25231558Srgrimes cr->cr_uid = atoi(name); 25241558Srgrimes else { 252537663Scharnier syslog(LOG_ERR, "unknown user: %s", name); 25261558Srgrimes return; 25271558Srgrimes } 25281558Srgrimes cr->cr_ngroups = 0; 25291558Srgrimes while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 25301558Srgrimes name = strsep(&names, ":"); 25311558Srgrimes if (isdigit(*name) || *name == '-') { 25321558Srgrimes cr->cr_groups[cr->cr_ngroups++] = atoi(name); 25331558Srgrimes } else { 25341558Srgrimes if ((gr = getgrnam(name)) == NULL) { 253537663Scharnier syslog(LOG_ERR, "unknown group: %s", name); 25361558Srgrimes continue; 25371558Srgrimes } 25381558Srgrimes cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 25391558Srgrimes } 25401558Srgrimes } 25411558Srgrimes if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 254237663Scharnier syslog(LOG_ERR, "too many groups"); 25431558Srgrimes} 25441558Srgrimes 25451558Srgrimes#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 25461558Srgrimes/* 25471558Srgrimes * Routines that maintain the remote mounttab 25481558Srgrimes */ 25491558Srgrimesvoid 25501558Srgrimesget_mountlist() 25511558Srgrimes{ 25521558Srgrimes struct mountlist *mlp, **mlpp; 255323681Speter char *host, *dirp, *cp; 25541558Srgrimes char str[STRSIZ]; 25551558Srgrimes FILE *mlfile; 25561558Srgrimes 25571558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 255853117Sbillf if (errno == ENOENT) 255953117Sbillf return; 256053117Sbillf else { 256153117Sbillf syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 256253117Sbillf return; 256353117Sbillf } 25641558Srgrimes } 25651558Srgrimes mlpp = &mlhead; 25661558Srgrimes while (fgets(str, STRSIZ, mlfile) != NULL) { 256723681Speter cp = str; 256823681Speter host = strsep(&cp, " \t\n"); 256923681Speter dirp = strsep(&cp, " \t\n"); 257023681Speter if (host == NULL || dirp == NULL) 25711558Srgrimes continue; 25721558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 257337663Scharnier if (mlp == (struct mountlist *)NULL) 257437663Scharnier out_of_mem(); 257523681Speter strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 257623681Speter mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 257723681Speter strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 257823681Speter mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 25791558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 25801558Srgrimes *mlpp = mlp; 25811558Srgrimes mlpp = &mlp->ml_next; 25821558Srgrimes } 25831558Srgrimes fclose(mlfile); 25841558Srgrimes} 25851558Srgrimes 258675635Siedowsevoid 258775635Siedowsedel_mlist(char *hostp, char *dirp) 25881558Srgrimes{ 25891558Srgrimes struct mountlist *mlp, **mlpp; 25901558Srgrimes struct mountlist *mlp2; 25911558Srgrimes FILE *mlfile; 25921558Srgrimes int fnd = 0; 25931558Srgrimes 25941558Srgrimes mlpp = &mlhead; 25951558Srgrimes mlp = mlhead; 25961558Srgrimes while (mlp) { 25971558Srgrimes if (!strcmp(mlp->ml_host, hostp) && 25981558Srgrimes (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 25991558Srgrimes fnd = 1; 26001558Srgrimes mlp2 = mlp; 26011558Srgrimes *mlpp = mlp = mlp->ml_next; 26021558Srgrimes free((caddr_t)mlp2); 26031558Srgrimes } else { 26041558Srgrimes mlpp = &mlp->ml_next; 26051558Srgrimes mlp = mlp->ml_next; 26061558Srgrimes } 26071558Srgrimes } 26081558Srgrimes if (fnd) { 26091558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 261037663Scharnier syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 26111558Srgrimes return; 26121558Srgrimes } 26131558Srgrimes mlp = mlhead; 26141558Srgrimes while (mlp) { 26151558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 26161558Srgrimes mlp = mlp->ml_next; 26171558Srgrimes } 26181558Srgrimes fclose(mlfile); 26191558Srgrimes } 26201558Srgrimes} 26211558Srgrimes 26221558Srgrimesvoid 26231558Srgrimesadd_mlist(hostp, dirp) 26241558Srgrimes char *hostp, *dirp; 26251558Srgrimes{ 26261558Srgrimes struct mountlist *mlp, **mlpp; 26271558Srgrimes FILE *mlfile; 26281558Srgrimes 26291558Srgrimes mlpp = &mlhead; 26301558Srgrimes mlp = mlhead; 26311558Srgrimes while (mlp) { 26321558Srgrimes if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 26331558Srgrimes return; 26341558Srgrimes mlpp = &mlp->ml_next; 26351558Srgrimes mlp = mlp->ml_next; 26361558Srgrimes } 26371558Srgrimes mlp = (struct mountlist *)malloc(sizeof (*mlp)); 263837663Scharnier if (mlp == (struct mountlist *)NULL) 263937663Scharnier out_of_mem(); 26401558Srgrimes strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 26411558Srgrimes mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 26421558Srgrimes strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 26431558Srgrimes mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 26441558Srgrimes mlp->ml_next = (struct mountlist *)NULL; 26451558Srgrimes *mlpp = mlp; 26461558Srgrimes if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 264737663Scharnier syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 26481558Srgrimes return; 26491558Srgrimes } 26501558Srgrimes fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 26511558Srgrimes fclose(mlfile); 26521558Srgrimes} 26531558Srgrimes 26541558Srgrimes/* 26551558Srgrimes * Free up a group list. 26561558Srgrimes */ 26571558Srgrimesvoid 26581558Srgrimesfree_grp(grp) 26591558Srgrimes struct grouplist *grp; 26601558Srgrimes{ 26611558Srgrimes if (grp->gr_type == GT_HOST) { 266274462Salfred if (grp->gr_ptr.gt_addrinfo != NULL) 266374462Salfred freeaddrinfo(grp->gr_ptr.gt_addrinfo); 26641558Srgrimes } else if (grp->gr_type == GT_NET) { 26651558Srgrimes if (grp->gr_ptr.gt_net.nt_name) 26661558Srgrimes free(grp->gr_ptr.gt_net.nt_name); 26671558Srgrimes } 26681558Srgrimes free((caddr_t)grp); 26691558Srgrimes} 26701558Srgrimes 26711558Srgrimes#ifdef DEBUG 26721558Srgrimesvoid 26731558SrgrimesSYSLOG(int pri, const char *fmt, ...) 26741558Srgrimes{ 26751558Srgrimes va_list ap; 26761558Srgrimes 26771558Srgrimes va_start(ap, fmt); 26781558Srgrimes vfprintf(stderr, fmt, ap); 26791558Srgrimes va_end(ap); 26801558Srgrimes} 26811558Srgrimes#endif /* DEBUG */ 26821558Srgrimes 26831558Srgrimes/* 26841558Srgrimes * Check options for consistency. 26851558Srgrimes */ 26861558Srgrimesint 26871558Srgrimescheck_options(dp) 26881558Srgrimes struct dirlist *dp; 26891558Srgrimes{ 26901558Srgrimes 26911558Srgrimes if (dp == (struct dirlist *)NULL) 26921558Srgrimes return (1); 269383653Speter if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 269483653Speter syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 26951558Srgrimes return (1); 26961558Srgrimes } 26971558Srgrimes if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 269875801Siedowse syslog(LOG_ERR, "-mask requires -network"); 269975801Siedowse return (1); 27001558Srgrimes } 270175801Siedowse if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 270275801Siedowse syslog(LOG_ERR, "-network requires mask specification"); 270375801Siedowse return (1); 270475801Siedowse } 270575801Siedowse if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 270675801Siedowse syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 270775801Siedowse return (1); 270875801Siedowse } 27091558Srgrimes if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 271045927Salex syslog(LOG_ERR, "-alldirs has multiple directories"); 27111558Srgrimes return (1); 27121558Srgrimes } 27131558Srgrimes return (0); 27141558Srgrimes} 27151558Srgrimes 27161558Srgrimes/* 27171558Srgrimes * Check an absolute directory path for any symbolic links. Return true 27181558Srgrimes */ 27191558Srgrimesint 27201558Srgrimescheck_dirpath(dirp) 27211558Srgrimes char *dirp; 27221558Srgrimes{ 27231558Srgrimes char *cp; 27241558Srgrimes int ret = 1; 27251558Srgrimes struct stat sb; 27261558Srgrimes 27271558Srgrimes cp = dirp + 1; 27281558Srgrimes while (*cp && ret) { 27291558Srgrimes if (*cp == '/') { 27301558Srgrimes *cp = '\0'; 27319336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 27321558Srgrimes ret = 0; 27331558Srgrimes *cp = '/'; 27341558Srgrimes } 27351558Srgrimes cp++; 27361558Srgrimes } 27379336Sdfr if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 27381558Srgrimes ret = 0; 27391558Srgrimes return (ret); 27401558Srgrimes} 27419336Sdfr 274275801Siedowse/* 274375801Siedowse * Make a netmask according to the specified prefix length. The ss_family 274475801Siedowse * and other non-address fields must be initialised before calling this. 274575801Siedowse */ 274675801Siedowseint 274775801Siedowsemakemask(struct sockaddr_storage *ssp, int bitlen) 274874462Salfred{ 274975801Siedowse u_char *p; 275075801Siedowse int bits, i, len; 275174462Salfred 275275801Siedowse if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 275375801Siedowse return (-1); 2754103949Smike if (bitlen > len * CHAR_BIT) 275575801Siedowse return (-1); 275674462Salfred 275775801Siedowse for (i = 0; i < len; i++) { 2758103949Smike bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 275975801Siedowse *p++ = (1 << bits) - 1; 276075801Siedowse bitlen -= bits; 276174462Salfred } 276275801Siedowse return 0; 276374462Salfred} 276474462Salfred 276575801Siedowse/* 276675801Siedowse * Check that the sockaddr is a valid netmask. Returns 0 if the mask 276775801Siedowse * is acceptable (i.e. of the form 1...10....0). 276875801Siedowse */ 276975801Siedowseint 277075801Siedowsecheckmask(struct sockaddr *sa) 277174462Salfred{ 277275801Siedowse u_char *mask; 277375801Siedowse int i, len; 277474462Salfred 277575801Siedowse if ((mask = sa_rawaddr(sa, &len)) == NULL) 277675801Siedowse return (-1); 277775801Siedowse 277875801Siedowse for (i = 0; i < len; i++) 277975801Siedowse if (mask[i] != 0xff) 278075801Siedowse break; 278175801Siedowse if (i < len) { 278275801Siedowse if (~mask[i] & (u_char)(~mask[i] + 1)) 278375801Siedowse return (-1); 278475801Siedowse i++; 278574462Salfred } 278675801Siedowse for (; i < len; i++) 278775801Siedowse if (mask[i] != 0) 278875801Siedowse return (-1); 278975801Siedowse return (0); 279074462Salfred} 279174462Salfred 279275801Siedowse/* 279375801Siedowse * Compare two sockaddrs according to a specified mask. Return zero if 279475801Siedowse * `sa1' matches `sa2' when filtered by the netmask in `samask'. 279575801Siedowse * If samask is NULL, perform a full comparision. 279675801Siedowse */ 279775801Siedowseint 279875801Siedowsesacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 279974462Salfred{ 280075801Siedowse unsigned char *p1, *p2, *mask; 280175801Siedowse int len, i; 280274462Salfred 280375801Siedowse if (sa1->sa_family != sa2->sa_family || 280475801Siedowse (p1 = sa_rawaddr(sa1, &len)) == NULL || 280575801Siedowse (p2 = sa_rawaddr(sa2, NULL)) == NULL) 280675801Siedowse return (1); 280775801Siedowse 280875801Siedowse switch (sa1->sa_family) { 280974462Salfred case AF_INET6: 281075801Siedowse if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 281175801Siedowse ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 281275801Siedowse return (1); 281374462Salfred break; 281474462Salfred } 281574462Salfred 281675801Siedowse /* Simple binary comparison if no mask specified. */ 281775801Siedowse if (samask == NULL) 281875801Siedowse return (memcmp(p1, p2, len)); 281974462Salfred 282075801Siedowse /* Set up the mask, and do a mask-based comparison. */ 282175801Siedowse if (sa1->sa_family != samask->sa_family || 282275801Siedowse (mask = sa_rawaddr(samask, NULL)) == NULL) 282375801Siedowse return (1); 282474462Salfred 282575801Siedowse for (i = 0; i < len; i++) 282675801Siedowse if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 282775801Siedowse return (1); 282875801Siedowse return (0); 282974462Salfred} 283074462Salfred 283175801Siedowse/* 283275801Siedowse * Return a pointer to the part of the sockaddr that contains the 283375801Siedowse * raw address, and set *nbytes to its length in bytes. Returns 283475801Siedowse * NULL if the address family is unknown. 283575801Siedowse */ 283675801Siedowsevoid * 283775801Siedowsesa_rawaddr(struct sockaddr *sa, int *nbytes) { 283875801Siedowse void *p; 283974462Salfred int len; 284074462Salfred 284175801Siedowse switch (sa->sa_family) { 284274462Salfred case AF_INET: 284375801Siedowse len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 284475801Siedowse p = &((struct sockaddr_in *)sa)->sin_addr; 284574462Salfred break; 284674462Salfred case AF_INET6: 284775801Siedowse len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 284875801Siedowse p = &((struct sockaddr_in6 *)sa)->sin6_addr; 284974462Salfred break; 285074462Salfred default: 285175801Siedowse p = NULL; 285275801Siedowse len = 0; 285374462Salfred } 285474462Salfred 285575801Siedowse if (nbytes != NULL) 285675801Siedowse *nbytes = len; 285775801Siedowse return (p); 285874462Salfred} 285974462Salfred 286075754Siedowsevoid 286175754Siedowsehuphandler(int sig) 286275754Siedowse{ 286375754Siedowse got_sighup = 1; 286475754Siedowse} 286575754Siedowse 286674462Salfredvoid terminate(sig) 286774462Salfredint sig; 286874462Salfred{ 2869149433Spjd pidfile_remove(pfh); 287074792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 287174792Salfred rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 287274462Salfred exit (0); 287374462Salfred} 2874