mountd.c revision 216587
1204076Spjd/* 2204076Spjd * Copyright (c) 1989, 1993 3219351Spjd * The Regents of the University of California. All rights reserved. 4204076Spjd * 5204076Spjd * This code is derived from software contributed to Berkeley by 6204076Spjd * Herb Hasler and Rick Macklem at The University of Guelph. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 4. Neither the name of the University nor the names of its contributors 17204076Spjd * may be used to endorse or promote products derived from this software 18204076Spjd * without specific prior written permission. 19204076Spjd * 20204076Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30204076Spjd * SUCH DAMAGE. 31204076Spjd */ 32204076Spjd 33204076Spjd#ifndef lint 34204076Spjdstatic const char copyright[] = 35204076Spjd"@(#) Copyright (c) 1989, 1993\n\ 36204076Spjd The Regents of the University of California. All rights reserved.\n"; 37204076Spjd#endif /*not lint*/ 38204076Spjd 39204076Spjd#if 0 40204076Spjd#ifndef lint 41204076Spjdstatic char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42204076Spjd#endif /*not lint*/ 43204076Spjd#endif 44204076Spjd 45204076Spjd#include <sys/cdefs.h> 46204076Spjd__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 216587 2010-12-20 09:28:28Z charnier $"); 47204076Spjd 48211982Spjd#include <sys/param.h> 49204076Spjd#include <sys/fcntl.h> 50204076Spjd#include <sys/linker.h> 51204076Spjd#include <sys/module.h> 52204076Spjd#include <sys/mount.h> 53204076Spjd#include <sys/stat.h> 54204076Spjd#include <sys/sysctl.h> 55204076Spjd#include <sys/syslog.h> 56204076Spjd 57204076Spjd#include <rpc/rpc.h> 58204076Spjd#include <rpc/rpc_com.h> 59204076Spjd#include <rpc/pmap_clnt.h> 60212038Spjd#include <rpc/pmap_prot.h> 61204076Spjd#include <rpcsvc/mount.h> 62204076Spjd#include <nfs/nfsproto.h> 63204076Spjd#include <nfs/nfssvc.h> 64211886Spjd#include <nfsserver/nfs.h> 65204076Spjd 66204076Spjd#include <fs/nfs/nfsport.h> 67204076Spjd 68204076Spjd#include <arpa/inet.h> 69204076Spjd 70204076Spjd#include <ctype.h> 71210886Spjd#include <err.h> 72210886Spjd#include <errno.h> 73210886Spjd#include <grp.h> 74204076Spjd#include <libutil.h> 75204076Spjd#include <limits.h> 76204076Spjd#include <netdb.h> 77204076Spjd#include <pwd.h> 78204076Spjd#include <signal.h> 79204076Spjd#include <stdio.h> 80204076Spjd#include <stdlib.h> 81204076Spjd#include <string.h> 82204076Spjd#include <unistd.h> 83204076Spjd#include "pathnames.h" 84204076Spjd#include "mntopts.h" 85204076Spjd 86204076Spjd#ifdef DEBUG 87204076Spjd#include <stdarg.h> 88204076Spjd#endif 89219818Spjd 90204076Spjd/* 91204076Spjd * Structures for keeping the mount list and export list 92204076Spjd */ 93204076Spjdstruct mountlist { 94204076Spjd struct mountlist *ml_next; 95204076Spjd char ml_host[MNTNAMLEN+1]; 96204076Spjd char ml_dirp[MNTPATHLEN+1]; 97204076Spjd}; 98204076Spjd 99204076Spjdstruct dirlist { 100204076Spjd struct dirlist *dp_left; 101204076Spjd struct dirlist *dp_right; 102204076Spjd int dp_flag; 103204076Spjd struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 104204076Spjd char dp_dirp[1]; /* Actually malloc'd to size of dir */ 105204076Spjd}; 106204076Spjd/* dp_flag bits */ 107204076Spjd#define DP_DEFSET 0x1 108204076Spjd#define DP_HOSTSET 0x2 109204076Spjd 110204076Spjdstruct exportlist { 111204076Spjd struct exportlist *ex_next; 112204076Spjd struct dirlist *ex_dirl; 113204076Spjd struct dirlist *ex_defdir; 114204076Spjd int ex_flag; 115204076Spjd fsid_t ex_fs; 116204076Spjd char *ex_fsdir; 117204076Spjd char *ex_indexfile; 118204076Spjd int ex_numsecflavors; 119204076Spjd int ex_secflavors[MAXSECFLAVORS]; 120204076Spjd}; 121204076Spjd/* ex_flag bits */ 122204076Spjd#define EX_LINKED 0x1 123204076Spjd 124204076Spjdstruct netmsk { 125204076Spjd struct sockaddr_storage nt_net; 126204076Spjd struct sockaddr_storage nt_mask; 127204076Spjd char *nt_name; 128204076Spjd}; 129204076Spjd 130204076Spjdunion grouptypes { 131204076Spjd struct addrinfo *gt_addrinfo; 132204076Spjd struct netmsk gt_net; 133204076Spjd}; 134204076Spjd 135204076Spjdstruct grouplist { 136204076Spjd int gr_type; 137204076Spjd union grouptypes gr_ptr; 138204076Spjd struct grouplist *gr_next; 139204076Spjd}; 140204076Spjd/* Group types */ 141204076Spjd#define GT_NULL 0x0 142204076Spjd#define GT_HOST 0x1 143204076Spjd#define GT_NET 0x2 144204076Spjd#define GT_DEFAULT 0x3 145204076Spjd#define GT_IGNORE 0x5 146204076Spjd 147204076Spjdstruct hostlist { 148204076Spjd int ht_flag; /* Uses DP_xx bits */ 149204076Spjd struct grouplist *ht_grp; 150204076Spjd struct hostlist *ht_next; 151204076Spjd}; 152204076Spjd 153204076Spjdstruct fhreturn { 154204076Spjd int fhr_flag; 155204076Spjd int fhr_vers; 156204076Spjd nfsfh_t fhr_fh; 157204076Spjd int fhr_numsecflavors; 158204076Spjd int *fhr_secflavors; 159204076Spjd}; 160204076Spjd 161204076Spjd/* Global defs */ 162204076Spjdchar *add_expdir(struct dirlist **, char *, int); 163204076Spjdvoid add_dlist(struct dirlist **, struct dirlist *, 164204076Spjd struct grouplist *, int); 165204076Spjdvoid add_mlist(char *, char *); 166204076Spjdint check_dirpath(char *); 167204076Spjdint check_options(struct dirlist *); 168204076Spjdint checkmask(struct sockaddr *sa); 169204076Spjdint chk_host(struct dirlist *, struct sockaddr *, int *, int *); 170204076Spjdvoid create_service(struct netconfig *nconf); 171204076Spjdvoid del_mlist(char *hostp, char *dirp); 172204076Spjdstruct dirlist *dirp_search(struct dirlist *, char *); 173204076Spjdint do_mount(struct exportlist *, struct grouplist *, int, 174204076Spjd struct xucred *, char *, int, struct statfs *); 175204076Spjdint do_opt(char **, char **, struct exportlist *, struct grouplist *, 176204076Spjd int *, int *, struct xucred *); 177204076Spjdstruct exportlist *ex_search(fsid_t *); 178214692Spjdstruct exportlist *get_exp(void); 179214692Spjdvoid free_dir(struct dirlist *); 180214692Spjdvoid free_exp(struct exportlist *); 181204076Spjdvoid free_grp(struct grouplist *); 182214692Spjdvoid free_host(struct hostlist *); 183214692Spjdvoid get_exportlist(void); 184214692Spjdint get_host(char *, struct grouplist *, struct grouplist *); 185214692Spjdstruct hostlist *get_ht(void); 186214692Spjdint get_line(void); 187214692Spjdvoid get_mountlist(void); 188204076Spjdint get_net(char *, struct netmsk *, int); 189214692Spjdvoid getexp_err(struct exportlist *, struct grouplist *); 190214692Spjdstruct grouplist *get_grp(void); 191214692Spjdvoid hang_dirp(struct dirlist *, struct grouplist *, 192214692Spjd struct exportlist *, int); 193204076Spjdvoid huphandler(int sig); 194204076Spjdint makemask(struct sockaddr_storage *ssp, int bitlen); 195204076Spjdvoid mntsrv(struct svc_req *, SVCXPRT *); 196204076Spjdvoid nextfield(char **, char **); 197204076Spjdvoid out_of_mem(void); 198204076Spjdvoid parsecred(char *, struct xucred *); 199204076Spjdint parsesec(char *, struct exportlist *); 200204076Spjdint put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 201204076Spjdvoid *sa_rawaddr(struct sockaddr *sa, int *nbytes); 202204076Spjdint sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 203204076Spjd struct sockaddr *samask); 204204076Spjdint scan_tree(struct dirlist *, struct sockaddr *); 205209183Spjdstatic void usage(void); 206209183Spjdint xdr_dir(XDR *, char *); 207209183Spjdint xdr_explist(XDR *, caddr_t); 208209183Spjdint xdr_explist_brief(XDR *, caddr_t); 209204076Spjdint xdr_explist_common(XDR *, caddr_t, int); 210204076Spjdint xdr_fhs(XDR *, caddr_t); 211204076Spjdint xdr_mlist(XDR *, caddr_t); 212204076Spjdvoid terminate(int); 213204076Spjd 214204076Spjdstruct exportlist *exphead; 215204076Spjdstruct mountlist *mlhead; 216204076Spjdstruct grouplist *grphead; 217204076Spjdchar *exnames_default[2] = { _PATH_EXPORTS, NULL }; 218204076Spjdchar **exnames; 219204076Spjdchar **hosts = NULL; 220204076Spjdstruct xucred def_anon = { 221204076Spjd XUCRED_VERSION, 222204076Spjd (uid_t)-2, 223204076Spjd 1, 224204076Spjd { (gid_t)-2 }, 225204076Spjd NULL 226204076Spjd}; 227204076Spjdint force_v2 = 0; 228204076Spjdint resvport_only = 1; 229204076Spjdint nhosts = 0; 230204076Spjdint dir_only = 1; 231211982Spjdint dolog = 0; 232204076Spjdint got_sighup = 0; 233204076Spjdint xcreated = 0; 234204076Spjd 235204076Spjdchar *svcport_str = NULL; 236204076Spjd 237204076Spjdint opt_flags; 238204076Spjdstatic int have_v6 = 1; 239204076Spjd 240204076Spjdint v4root_phase = 0; 241204076Spjdchar v4root_dirpath[PATH_MAX + 1]; 242204076Spjdint run_v4server = 0; 243213533Spjdint has_publicfh = 0; 244204076Spjd 245204076Spjdstruct pidfh *pfh = NULL; 246204076Spjd/* Bits for opt_flags above */ 247204076Spjd#define OP_MAPROOT 0x01 248213531Spjd#define OP_MAPALL 0x02 249213531Spjd/* 0x4 free */ 250204076Spjd#define OP_MASK 0x08 251204076Spjd#define OP_NET 0x10 252204076Spjd#define OP_ALLDIRS 0x40 253204076Spjd#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 254204076Spjd#define OP_QUIET 0x100 255204076Spjd#define OP_MASKLEN 0x200 256204076Spjd#define OP_SEC 0x400 257204076Spjd 258204076Spjd#ifdef DEBUG 259212899Spjdint debug = 1; 260204076Spjdvoid SYSLOG(int, const char *, ...) __printflike(2, 3); 261204076Spjd#define syslog SYSLOG 262204076Spjd#else 263204076Spjdint debug = 0; 264218138Spjd#endif 265204076Spjd 266204076Spjd/* 267204076Spjd * Mountd server for NFS mount protocol as described in: 268204076Spjd * NFS: Network File System Protocol Specification, RFC1094, Appendix A 269204076Spjd * The optional arguments are the exports file name 270204076Spjd * default: _PATH_EXPORTS 271204076Spjd * and "-n" to allow nonroot mount. 272212899Spjd */ 273204076Spjdint 274204076Spjdmain(int argc, char **argv) 275204076Spjd{ 276204076Spjd fd_set readfds; 277204076Spjd struct netconfig *nconf; 278204076Spjd char *endptr, **hosts_bak; 279204076Spjd void *nc_handle; 280204076Spjd pid_t otherpid; 281204076Spjd in_port_t svcport; 282204076Spjd int c, k, s; 283204076Spjd int maxrec = RPC_MAXDATASIZE; 284204076Spjd 285204076Spjd /* Check that another mountd isn't already running. */ 286204076Spjd pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 287204076Spjd if (pfh == NULL) { 288204076Spjd if (errno == EEXIST) 289204076Spjd errx(1, "mountd already running, pid: %d.", otherpid); 290204076Spjd warn("cannot open or create pidfile"); 291218138Spjd } 292218138Spjd 293204076Spjd s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 294204076Spjd if (s < 0) 295204076Spjd have_v6 = 0; 296204076Spjd else 297204076Spjd close(s); 298204076Spjd 299204076Spjd while ((c = getopt(argc, argv, "2deh:lnp:r")) != -1) 300204076Spjd switch (c) { 301204076Spjd case '2': 302210881Spjd force_v2 = 1; 303210881Spjd break; 304210881Spjd case 'e': 305210881Spjd run_v4server = 1; 306210881Spjd break; 307210881Spjd case 'n': 308210881Spjd resvport_only = 0; 309204076Spjd break; 310204076Spjd case 'r': 311204076Spjd dir_only = 0; 312204076Spjd break; 313204076Spjd case 'd': 314204076Spjd debug = debug ? 0 : 1; 315204076Spjd break; 316204076Spjd case 'l': 317204076Spjd dolog = 1; 318204076Spjd break; 319204076Spjd case 'p': 320204076Spjd endptr = NULL; 321204076Spjd svcport = (in_port_t)strtoul(optarg, &endptr, 10); 322204076Spjd if (endptr == NULL || *endptr != '\0' || 323204076Spjd svcport == 0 || svcport >= IPPORT_MAX) 324204076Spjd usage(); 325204076Spjd svcport_str = strdup(optarg); 326204076Spjd break; 327204076Spjd case 'h': 328204076Spjd ++nhosts; 329204076Spjd hosts_bak = hosts; 330204076Spjd hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 331204076Spjd if (hosts_bak == NULL) { 332204076Spjd if (hosts != NULL) { 333204076Spjd for (k = 0; k < nhosts; k++) 334204076Spjd free(hosts[k]); 335204076Spjd free(hosts); 336204076Spjd out_of_mem(); 337204076Spjd } 338204076Spjd } 339204076Spjd hosts = hosts_bak; 340204076Spjd hosts[nhosts - 1] = strdup(optarg); 341204076Spjd if (hosts[nhosts - 1] == NULL) { 342204076Spjd for (k = 0; k < (nhosts - 1); k++) 343204076Spjd free(hosts[k]); 344204076Spjd free(hosts); 345204076Spjd out_of_mem(); 346204076Spjd } 347204076Spjd break; 348204076Spjd default: 349204076Spjd usage(); 350204076Spjd }; 351204076Spjd 352204076Spjd /* 353204076Spjd * If the "-e" option was specified OR only the nfsd module is 354204076Spjd * found in the server, run "nfsd". 355204076Spjd * Otherwise, try and run "nfsserver". 356204076Spjd */ 357204076Spjd if (run_v4server > 0) { 358204076Spjd if (modfind("nfsd") < 0) { 359204076Spjd /* Not present in kernel, try loading it */ 360204076Spjd if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 361204076Spjd errx(1, "NFS server is not available"); 362204076Spjd } 363204076Spjd } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { 364204076Spjd run_v4server = 1; 365204076Spjd } else if (modfind("nfsserver") < 0) { 366204076Spjd /* Not present in kernel, try loading it */ 367204076Spjd if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 368204076Spjd errx(1, "NFS server is not available"); 369204076Spjd } 370204076Spjd 371204076Spjd argc -= optind; 372204076Spjd argv += optind; 373204076Spjd grphead = (struct grouplist *)NULL; 374204076Spjd exphead = (struct exportlist *)NULL; 375204076Spjd mlhead = (struct mountlist *)NULL; 376204076Spjd if (argc > 0) 377204076Spjd exnames = argv; 378204076Spjd else 379204076Spjd exnames = exnames_default; 380204076Spjd openlog("mountd", LOG_PID, LOG_DAEMON); 381204076Spjd if (debug) 382204076Spjd warnx("getting export list"); 383204076Spjd get_exportlist(); 384204076Spjd if (debug) 385204076Spjd warnx("getting mount list"); 386204076Spjd get_mountlist(); 387204076Spjd if (debug) 388204076Spjd warnx("here we go"); 389204076Spjd if (debug == 0) { 390204076Spjd daemon(0, 0); 391204076Spjd signal(SIGINT, SIG_IGN); 392204076Spjd signal(SIGQUIT, SIG_IGN); 393204076Spjd } 394204076Spjd signal(SIGHUP, huphandler); 395204076Spjd signal(SIGTERM, terminate); 396204076Spjd signal(SIGPIPE, SIG_IGN); 397204076Spjd 398204076Spjd pidfile_write(pfh); 399204076Spjd 400204076Spjd rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 401204076Spjd rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 402204076Spjd rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 403204076Spjd 404204076Spjd if (!resvport_only) { 405204076Spjd if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 406204076Spjd &resvport_only, sizeof(resvport_only)) != 0 && 407204076Spjd errno != ENOENT) { 408204076Spjd syslog(LOG_ERR, "sysctl: %m"); 409204076Spjd exit(1); 410204076Spjd } 411204076Spjd } 412204076Spjd 413204076Spjd /* 414204076Spjd * If no hosts were specified, add a wildcard entry to bind to 415204076Spjd * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 416204076Spjd * list. 417204076Spjd */ 418204076Spjd if (nhosts == 0) { 419204076Spjd hosts = malloc(sizeof(char**)); 420204076Spjd if (hosts == NULL) 421204076Spjd out_of_mem(); 422214284Spjd hosts[0] = "*"; 423214284Spjd nhosts = 1; 424214284Spjd } else { 425214284Spjd hosts_bak = hosts; 426214284Spjd if (have_v6) { 427214284Spjd hosts_bak = realloc(hosts, (nhosts + 2) * 428214284Spjd sizeof(char *)); 429214284Spjd if (hosts_bak == NULL) { 430214284Spjd for (k = 0; k < nhosts; k++) 431214284Spjd free(hosts[k]); 432214284Spjd free(hosts); 433214284Spjd out_of_mem(); 434214284Spjd } else 435214284Spjd hosts = hosts_bak; 436214284Spjd nhosts += 2; 437214284Spjd hosts[nhosts - 2] = "::1"; 438214284Spjd } else { 439214284Spjd hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 440204076Spjd if (hosts_bak == NULL) { 441204076Spjd for (k = 0; k < nhosts; k++) 442204076Spjd free(hosts[k]); 443204076Spjd free(hosts); 444204076Spjd out_of_mem(); 445204076Spjd } else { 446204076Spjd nhosts += 1; 447204076Spjd hosts = hosts_bak; 448204076Spjd } 449204076Spjd } 450204076Spjd 451204076Spjd hosts[nhosts - 1] = "127.0.0.1"; 452204076Spjd } 453204076Spjd 454204076Spjd nc_handle = setnetconfig(); 455204076Spjd while ((nconf = getnetconfig(nc_handle))) { 456204076Spjd if (nconf->nc_flag & NC_VISIBLE) { 457204076Spjd if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 458204076Spjd "inet6") == 0) { 459204076Spjd /* DO NOTHING */ 460204076Spjd } else 461204076Spjd create_service(nconf); 462204076Spjd } 463204076Spjd } 464204076Spjd endnetconfig(nc_handle); 465204076Spjd 466204076Spjd if (xcreated == 0) { 467204076Spjd syslog(LOG_ERR, "could not create any services"); 468204076Spjd exit(1); 469204076Spjd } 470204076Spjd 471209181Spjd /* Expand svc_run() here so that we can call get_exportlist(). */ 472204076Spjd for (;;) { 473204076Spjd if (got_sighup) { 474204076Spjd get_exportlist(); 475214284Spjd got_sighup = 0; 476214284Spjd } 477214284Spjd readfds = svc_fdset; 478214284Spjd switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 479214284Spjd case -1: 480204076Spjd if (errno == EINTR) 481219844Spjd continue; 482204076Spjd syslog(LOG_ERR, "mountd died: select: %m"); 483204076Spjd exit(1); 484204076Spjd case 0: 485204076Spjd continue; 486204076Spjd default: 487218218Spjd svc_getreqset(&readfds); 488218218Spjd } 489218218Spjd } 490218218Spjd} 491218218Spjd 492218218Spjd/* 493218218Spjd * This routine creates and binds sockets on the appropriate 494218218Spjd * addresses. It gets called one time for each transport and 495218218Spjd * registrates the service with rpcbind on that trasport. 496218218Spjd */ 497218218Spjdvoid 498218218Spjdcreate_service(struct netconfig *nconf) 499218218Spjd{ 500218218Spjd struct addrinfo hints, *res = NULL; 501218218Spjd struct sockaddr_in *sin; 502218218Spjd struct sockaddr_in6 *sin6; 503218218Spjd struct __rpc_sockinfo si; 504218218Spjd struct netbuf servaddr; 505218218Spjd SVCXPRT *transp = NULL; 506218218Spjd int aicode; 507218218Spjd int fd; 508218218Spjd int nhostsbak; 509218218Spjd int one = 1; 510218218Spjd int r; 511218218Spjd int registered = 0; 512218218Spjd u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 513218218Spjd 514218218Spjd if ((nconf->nc_semantics != NC_TPI_CLTS) && 515218218Spjd (nconf->nc_semantics != NC_TPI_COTS) && 516218218Spjd (nconf->nc_semantics != NC_TPI_COTS_ORD)) 517218218Spjd return; /* not my type */ 518218218Spjd 519218218Spjd /* 520218218Spjd * XXX - using RPC library internal functions. 521218218Spjd */ 522218218Spjd if (!__rpc_nconf2sockinfo(nconf, &si)) { 523218218Spjd syslog(LOG_ERR, "cannot get information for %s", 524218218Spjd nconf->nc_netid); 525218218Spjd return; 526218218Spjd } 527205738Spjd 528205738Spjd /* Get mountd's address on this transport */ 529205738Spjd memset(&hints, 0, sizeof hints); 530204076Spjd hints.ai_flags = AI_PASSIVE; 531205738Spjd hints.ai_family = si.si_af; 532204076Spjd hints.ai_socktype = si.si_socktype; 533204076Spjd hints.ai_protocol = si.si_proto; 534204076Spjd 535204076Spjd /* 536204076Spjd * Bind to specific IPs if asked to 537204076Spjd */ 538204076Spjd nhostsbak = nhosts; 539204076Spjd while (nhostsbak > 0) { 540204076Spjd --nhostsbak; 541218138Spjd /* 542218138Spjd * XXX - using RPC library internal functions. 543205738Spjd */ 544205738Spjd if ((fd = __rpc_nconf2fd(nconf)) < 0) { 545211983Spjd int non_fatal = 0; 546205738Spjd if (errno == EPROTONOSUPPORT && 547218218Spjd nconf->nc_semantics != NC_TPI_CLTS) 548218218Spjd non_fatal = 1; 549218218Spjd 550204076Spjd syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 551204076Spjd "cannot create socket for %s", nconf->nc_netid); 552204076Spjd return; 553204076Spjd } 554204076Spjd 555204076Spjd switch (hints.ai_family) { 556204076Spjd case AF_INET: 557204076Spjd if (inet_pton(AF_INET, hosts[nhostsbak], 558204076Spjd host_addr) == 1) { 559204076Spjd hints.ai_flags &= AI_NUMERICHOST; 560204076Spjd } else { 561204076Spjd /* 562204076Spjd * Skip if we have an AF_INET6 address. 563205738Spjd */ 564204076Spjd if (inet_pton(AF_INET6, hosts[nhostsbak], 565204076Spjd host_addr) == 1) { 566204076Spjd close(fd); 567204076Spjd continue; 568204076Spjd } 569204076Spjd } 570204076Spjd break; 571205738Spjd case AF_INET6: 572204076Spjd if (inet_pton(AF_INET6, hosts[nhostsbak], 573204076Spjd host_addr) == 1) { 574204076Spjd hints.ai_flags &= AI_NUMERICHOST; 575204076Spjd } else { 576204076Spjd /* 577204076Spjd * Skip if we have an AF_INET address. 578204076Spjd */ 579204076Spjd if (inet_pton(AF_INET, hosts[nhostsbak], 580204076Spjd host_addr) == 1) { 581204076Spjd close(fd); 582204076Spjd continue; 583204076Spjd } 584204076Spjd } 585204076Spjd 586204076Spjd /* 587204076Spjd * We're doing host-based access checks here, so don't 588204076Spjd * allow v4-in-v6 to confuse things. The kernel will 589204076Spjd * disable it by default on NFS sockets too. 590204076Spjd */ 591204076Spjd if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 592204076Spjd sizeof one) < 0) { 593204076Spjd syslog(LOG_ERR, 594204076Spjd "can't disable v4-in-v6 on IPv6 socket"); 595204076Spjd exit(1); 596204076Spjd } 597204076Spjd break; 598204076Spjd default: 599204076Spjd break; 600204076Spjd } 601204076Spjd 602204076Spjd /* 603218218Spjd * If no hosts were specified, just bind to INADDR_ANY 604204076Spjd */ 605218218Spjd if (strcmp("*", hosts[nhostsbak]) == 0) { 606204076Spjd if (svcport_str == NULL) { 607204076Spjd res = malloc(sizeof(struct addrinfo)); 608204076Spjd if (res == NULL) 609204076Spjd out_of_mem(); 610214284Spjd res->ai_flags = hints.ai_flags; 611214284Spjd res->ai_family = hints.ai_family; 612214284Spjd res->ai_protocol = hints.ai_protocol; 613214284Spjd switch (res->ai_family) { 614214284Spjd case AF_INET: 615214284Spjd sin = malloc(sizeof(struct sockaddr_in)); 616214284Spjd if (sin == NULL) 617214284Spjd out_of_mem(); 618214284Spjd sin->sin_family = AF_INET; 619214284Spjd sin->sin_port = htons(0); 620214284Spjd sin->sin_addr.s_addr = htonl(INADDR_ANY); 621214284Spjd res->ai_addr = (struct sockaddr*) sin; 622214284Spjd res->ai_addrlen = (socklen_t) 623204076Spjd sizeof(res->ai_addr); 624204076Spjd break; 625204076Spjd case AF_INET6: 626204076Spjd sin6 = malloc(sizeof(struct sockaddr_in6)); 627204076Spjd if (sin6 == NULL) 628204076Spjd out_of_mem(); 629204076Spjd sin6->sin6_family = AF_INET6; 630204076Spjd sin6->sin6_port = htons(0); 631204076Spjd sin6->sin6_addr = in6addr_any; 632204076Spjd res->ai_addr = (struct sockaddr*) sin6; 633205738Spjd res->ai_addrlen = (socklen_t) 634204076Spjd sizeof(res->ai_addr); 635204076Spjd break; 636204076Spjd default: 637204076Spjd break; 638204076Spjd } 639204076Spjd } else { 640204076Spjd if ((aicode = getaddrinfo(NULL, svcport_str, 641205738Spjd &hints, &res)) != 0) { 642204076Spjd syslog(LOG_ERR, 643204076Spjd "cannot get local address for %s: %s", 644204076Spjd nconf->nc_netid, 645204076Spjd gai_strerror(aicode)); 646204076Spjd continue; 647204076Spjd } 648204076Spjd } 649204076Spjd } else { 650204076Spjd if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 651204076Spjd &hints, &res)) != 0) { 652204076Spjd syslog(LOG_ERR, 653204076Spjd "cannot get local address for %s: %s", 654204076Spjd nconf->nc_netid, gai_strerror(aicode)); 655204076Spjd continue; 656204076Spjd } 657204076Spjd } 658204076Spjd 659204076Spjd r = bindresvport_sa(fd, res->ai_addr); 660204076Spjd if (r != 0) { 661204076Spjd syslog(LOG_ERR, "bindresvport_sa: %m"); 662204076Spjd exit(1); 663204076Spjd } 664204076Spjd 665204076Spjd if (nconf->nc_semantics != NC_TPI_CLTS) 666204076Spjd listen(fd, SOMAXCONN); 667204076Spjd 668204076Spjd if (nconf->nc_semantics == NC_TPI_CLTS ) 669204076Spjd transp = svc_dg_create(fd, 0, 0); 670204076Spjd else 671204076Spjd transp = svc_vc_create(fd, RPC_MAXDATASIZE, 672204076Spjd RPC_MAXDATASIZE); 673204076Spjd 674204076Spjd if (transp != (SVCXPRT *) NULL) { 675204076Spjd if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 676204076Spjd NULL)) 677204076Spjd syslog(LOG_ERR, 678204076Spjd "can't register %s MOUNTVERS service", 679204076Spjd nconf->nc_netid); 680204076Spjd if (!force_v2) { 681204076Spjd if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 682204076Spjd mntsrv, NULL)) 683204076Spjd syslog(LOG_ERR, 684205738Spjd "can't register %s MOUNTVERS3 service", 685204076Spjd nconf->nc_netid); 686204076Spjd } 687204076Spjd } else 688204076Spjd syslog(LOG_WARNING, "can't create %s services", 689204076Spjd nconf->nc_netid); 690204076Spjd 691204076Spjd if (registered == 0) { 692204076Spjd registered = 1; 693204076Spjd memset(&hints, 0, sizeof hints); 694204076Spjd hints.ai_flags = AI_PASSIVE; 695204076Spjd hints.ai_family = si.si_af; 696204076Spjd hints.ai_socktype = si.si_socktype; 697204076Spjd hints.ai_protocol = si.si_proto; 698204076Spjd 699204076Spjd if (svcport_str == NULL) { 700204076Spjd svcport_str = malloc(NI_MAXSERV * sizeof(char)); 701204076Spjd if (svcport_str == NULL) 702204076Spjd out_of_mem(); 703214274Spjd 704204076Spjd if (getnameinfo(res->ai_addr, 705205738Spjd res->ai_addr->sa_len, NULL, NI_MAXHOST, 706205738Spjd svcport_str, NI_MAXSERV * sizeof(char), 707205738Spjd NI_NUMERICHOST | NI_NUMERICSERV)) 708205738Spjd errx(1, "Cannot get port number"); 709205738Spjd } 710205738Spjd 711205738Spjd if((aicode = getaddrinfo(NULL, svcport_str, &hints, 712212038Spjd &res)) != 0) { 713205738Spjd syslog(LOG_ERR, "cannot get local address: %s", 714205738Spjd gai_strerror(aicode)); 715211983Spjd exit(1); 716212038Spjd } 717205738Spjd 718205738Spjd servaddr.buf = malloc(res->ai_addrlen); 719205738Spjd memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 720205738Spjd servaddr.len = res->ai_addrlen; 721205738Spjd 722205738Spjd rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 723205738Spjd rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 724205738Spjd 725205738Spjd xcreated++; 726205738Spjd freeaddrinfo(res); 727204076Spjd } 728204076Spjd } /* end while */ 729204076Spjd} 730204076Spjd 731204076Spjdstatic void 732204076Spjdusage(void) 733204076Spjd{ 734211878Spjd fprintf(stderr, 735211878Spjd "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 736211878Spjd "[-h <bindip>] [export_file ...]\n"); 737211878Spjd exit(1); 738211878Spjd} 739211878Spjd 740211878Spjd/* 741211878Spjd * The mount rpc service 742211878Spjd */ 743211878Spjdvoid 744204076Spjdmntsrv(struct svc_req *rqstp, SVCXPRT *transp) 745204076Spjd{ 746204076Spjd struct exportlist *ep; 747204076Spjd struct dirlist *dp; 748204076Spjd struct fhreturn fhr; 749204076Spjd struct stat stb; 750204076Spjd struct statfs fsb; 751204076Spjd char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 752204076Spjd int lookup_failed = 1; 753204076Spjd struct sockaddr *saddr; 754204076Spjd u_short sport; 755204076Spjd char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 756204076Spjd int bad = 0, defset, hostset; 757204076Spjd sigset_t sighup_mask; 758204076Spjd 759213533Spjd sigemptyset(&sighup_mask); 760204076Spjd sigaddset(&sighup_mask, SIGHUP); 761204076Spjd saddr = svc_getrpccaller(transp)->buf; 762204076Spjd switch (saddr->sa_family) { 763204076Spjd case AF_INET6: 764206669Spjd sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 765204076Spjd break; 766204076Spjd case AF_INET: 767204076Spjd sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 768204076Spjd break; 769204076Spjd default: 770204076Spjd syslog(LOG_ERR, "request from unknown address family"); 771204076Spjd return; 772204076Spjd } 773204076Spjd lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 774204076Spjd NULL, 0, 0); 775204076Spjd getnameinfo(saddr, saddr->sa_len, numerichost, 776204076Spjd sizeof numerichost, NULL, 0, NI_NUMERICHOST); 777204076Spjd switch (rqstp->rq_proc) { 778204076Spjd case NULLPROC: 779204076Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 780204076Spjd syslog(LOG_ERR, "can't send reply"); 781204076Spjd return; 782204076Spjd case MOUNTPROC_MNT: 783204076Spjd if (sport >= IPPORT_RESERVED && resvport_only) { 784204076Spjd syslog(LOG_NOTICE, 785204076Spjd "mount request from %s from unprivileged port", 786213533Spjd numerichost); 787204076Spjd svcerr_weakauth(transp); 788204076Spjd return; 789204076Spjd } 790204076Spjd if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 791204076Spjd syslog(LOG_NOTICE, "undecodable mount request from %s", 792204076Spjd numerichost); 793204076Spjd svcerr_decode(transp); 794204076Spjd return; 795204076Spjd } 796204076Spjd 797204076Spjd /* 798204076Spjd * Get the real pathname and make sure it is a directory 799204076Spjd * or a regular file if the -r option was specified 800204076Spjd * and it exists. 801204076Spjd */ 802204076Spjd if (realpath(rpcpath, dirpath) == NULL || 803204076Spjd stat(dirpath, &stb) < 0 || 804204076Spjd (!S_ISDIR(stb.st_mode) && 805219482Strociny (dir_only || !S_ISREG(stb.st_mode))) || 806204076Spjd statfs(dirpath, &fsb) < 0) { 807204076Spjd chdir("/"); /* Just in case realpath doesn't */ 808218218Spjd syslog(LOG_NOTICE, 809218218Spjd "mount request from %s for non existent path %s", 810204076Spjd numerichost, dirpath); 811219818Spjd if (debug) 812218042Spjd warnx("stat failed on %s", dirpath); 813204076Spjd bad = ENOENT; /* We will send error reply later */ 814212034Spjd } 815204076Spjd 816204076Spjd /* Check in the exports list */ 817212038Spjd sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 818218218Spjd ep = ex_search(&fsb.f_fsid); 819212038Spjd hostset = defset = 0; 820219818Spjd if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 821218042Spjd ((dp = dirp_search(ep->ex_dirl, dirpath)) && 822212038Spjd chk_host(dp, saddr, &defset, &hostset)) || 823212038Spjd (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 824212038Spjd scan_tree(ep->ex_dirl, saddr) == 0))) { 825212038Spjd if (bad) { 826218218Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 827218218Spjd (caddr_t)&bad)) 828218218Spjd syslog(LOG_ERR, "can't send reply"); 829218218Spjd sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 830219818Spjd return; 831218218Spjd } 832218218Spjd if (hostset & DP_HOSTSET) 833218218Spjd fhr.fhr_flag = hostset; 834218218Spjd else 835218218Spjd fhr.fhr_flag = defset; 836204076Spjd fhr.fhr_vers = rqstp->rq_vers; 837204076Spjd /* Get the file handle */ 838204076Spjd memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 839218042Spjd if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 840204076Spjd bad = errno; 841212034Spjd syslog(LOG_ERR, "can't get fh for %s", dirpath); 842204076Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 843204076Spjd (caddr_t)&bad)) 844204076Spjd syslog(LOG_ERR, "can't send reply"); 845204076Spjd sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 846212038Spjd return; 847212038Spjd } 848218218Spjd fhr.fhr_numsecflavors = ep->ex_numsecflavors; 849218043Spjd fhr.fhr_secflavors = ep->ex_secflavors; 850218043Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 851204076Spjd (caddr_t)&fhr)) 852204076Spjd syslog(LOG_ERR, "can't send reply"); 853204076Spjd if (!lookup_failed) 854211977Spjd add_mlist(host, dirpath); 855211984Spjd else 856218043Spjd add_mlist(numerichost, dirpath); 857219482Strociny if (debug) 858211984Spjd warnx("mount successful"); 859218043Spjd if (dolog) 860218043Spjd syslog(LOG_NOTICE, 861218218Spjd "mount request succeeded from %s for %s", 862218043Spjd numerichost, dirpath); 863218043Spjd } else { 864218043Spjd bad = EACCES; 865204076Spjd syslog(LOG_NOTICE, 866218045Spjd "mount request denied from %s for %s", 867218045Spjd numerichost, dirpath); 868218043Spjd } 869219482Strociny 870218043Spjd if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 871204076Spjd (caddr_t)&bad)) 872204076Spjd syslog(LOG_ERR, "can't send reply"); 873204076Spjd sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 874213007Spjd return; 875213007Spjd case MOUNTPROC_DUMP: 876217784Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 877218049Spjd syslog(LOG_ERR, "can't send reply"); 878218049Spjd else if (dolog) 879218049Spjd syslog(LOG_NOTICE, 880218049Spjd "dump request succeeded from %s", 881218214Spjd numerichost); 882218049Spjd return; 883213007Spjd case MOUNTPROC_UMNT: 884213530Spjd if (sport >= IPPORT_RESERVED && resvport_only) { 885213530Spjd syslog(LOG_NOTICE, 886213530Spjd "umount request from %s from unprivileged port", 887213530Spjd numerichost); 888218138Spjd svcerr_weakauth(transp); 889213530Spjd return; 890213007Spjd } 891213007Spjd if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 892213007Spjd syslog(LOG_NOTICE, "undecodable umount request from %s", 893213007Spjd numerichost); 894213007Spjd svcerr_decode(transp); 895213007Spjd return; 896213007Spjd } 897213007Spjd if (realpath(rpcpath, dirpath) == NULL) { 898218138Spjd syslog(LOG_NOTICE, "umount request from %s " 899210881Spjd "for non existent path %s", 900205738Spjd numerichost, dirpath); 901204076Spjd } 902218138Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 903204076Spjd syslog(LOG_ERR, "can't send reply"); 904218138Spjd if (!lookup_failed) 905204076Spjd del_mlist(host, dirpath); 906218138Spjd del_mlist(numerichost, dirpath); 907204076Spjd if (dolog) 908218138Spjd syslog(LOG_NOTICE, 909204076Spjd "umount request succeeded from %s for %s", 910218138Spjd numerichost, dirpath); 911213530Spjd return; 912204076Spjd case MOUNTPROC_UMNTALL: 913204076Spjd if (sport >= IPPORT_RESERVED && resvport_only) { 914204076Spjd syslog(LOG_NOTICE, 915204076Spjd "umountall request from %s from unprivileged port", 916204076Spjd numerichost); 917204076Spjd svcerr_weakauth(transp); 918204076Spjd return; 919204076Spjd } 920204076Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 921204076Spjd syslog(LOG_ERR, "can't send reply"); 922204076Spjd if (!lookup_failed) 923204076Spjd del_mlist(host, NULL); 924204076Spjd del_mlist(numerichost, NULL); 925204076Spjd if (dolog) 926204076Spjd syslog(LOG_NOTICE, 927204076Spjd "umountall request succeeded from %s", 928204076Spjd numerichost); 929204076Spjd return; 930204076Spjd case MOUNTPROC_EXPORT: 931204076Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 932204076Spjd if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 933204076Spjd (caddr_t)NULL)) 934204076Spjd syslog(LOG_ERR, "can't send reply"); 935204076Spjd if (dolog) 936204076Spjd syslog(LOG_NOTICE, 937204076Spjd "export request succeeded from %s", 938204076Spjd numerichost); 939204076Spjd return; 940204076Spjd default: 941204076Spjd svcerr_noproc(transp); 942204076Spjd return; 943204076Spjd } 944204076Spjd} 945204076Spjd 946204076Spjd/* 947204076Spjd * Xdr conversion for a dirpath string 948204076Spjd */ 949204076Spjdint 950204076Spjdxdr_dir(XDR *xdrsp, char *dirp) 951204076Spjd{ 952204076Spjd return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 953204076Spjd} 954204076Spjd 955204076Spjd/* 956204076Spjd * Xdr routine to generate file handle reply 957204076Spjd */ 958204076Spjdint 959204076Spjdxdr_fhs(XDR *xdrsp, caddr_t cp) 960204076Spjd{ 961204076Spjd struct fhreturn *fhrp = (struct fhreturn *)cp; 962204076Spjd u_long ok = 0, len, auth; 963218138Spjd int i; 964218138Spjd 965204076Spjd if (!xdr_long(xdrsp, &ok)) 966204076Spjd return (0); 967204076Spjd switch (fhrp->fhr_vers) { 968204076Spjd case 1: 969218138Spjd return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 970218138Spjd case 3: 971204076Spjd len = NFSX_V3FH; 972211881Spjd if (!xdr_long(xdrsp, &len)) 973204076Spjd return (0); 974204076Spjd if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 975204076Spjd return (0); 976211881Spjd if (fhrp->fhr_numsecflavors) { 977204076Spjd if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 978204076Spjd return (0); 979204076Spjd for (i = 0; i < fhrp->fhr_numsecflavors; i++) 980204076Spjd if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 981204076Spjd return (0); 982204076Spjd return (1); 983211881Spjd } else { 984211881Spjd auth = AUTH_SYS; 985204076Spjd len = 1; 986204076Spjd if (!xdr_long(xdrsp, &len)) 987204076Spjd return (0); 988211878Spjd return (xdr_long(xdrsp, &auth)); 989211984Spjd } 990212038Spjd }; 991204076Spjd return (0); 992204076Spjd} 993204076Spjd 994204076Spjdint 995204076Spjdxdr_mlist(XDR *xdrsp, caddr_t cp __unused) 996204076Spjd{ 997204076Spjd struct mountlist *mlp; 998204076Spjd int true = 1; 999204076Spjd int false = 0; 1000204076Spjd char *strp; 1001204076Spjd 1002204076Spjd mlp = mlhead; 1003204076Spjd while (mlp) { 1004204076Spjd if (!xdr_bool(xdrsp, &true)) 1005204076Spjd return (0); 1006204076Spjd strp = &mlp->ml_host[0]; 1007204076Spjd if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 1008204076Spjd return (0); 1009204076Spjd strp = &mlp->ml_dirp[0]; 1010204076Spjd if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1011204076Spjd return (0); 1012204076Spjd mlp = mlp->ml_next; 1013204076Spjd } 1014204076Spjd if (!xdr_bool(xdrsp, &false)) 1015204076Spjd return (0); 1016204076Spjd return (1); 1017204076Spjd} 1018204076Spjd 1019204076Spjd/* 1020204076Spjd * Xdr conversion for export list 1021204076Spjd */ 1022204076Spjdint 1023204076Spjdxdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 1024204076Spjd{ 1025204076Spjd struct exportlist *ep; 1026204076Spjd int false = 0; 1027204076Spjd int putdef; 1028204076Spjd sigset_t sighup_mask; 1029204076Spjd 1030204076Spjd sigemptyset(&sighup_mask); 1031204076Spjd sigaddset(&sighup_mask, SIGHUP); 1032204076Spjd sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1033204076Spjd ep = exphead; 1034204076Spjd while (ep) { 1035204076Spjd putdef = 0; 1036204076Spjd if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1037204076Spjd &putdef, brief)) 1038204076Spjd goto errout; 1039204076Spjd if (ep->ex_defdir && putdef == 0 && 1040204076Spjd put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1041204076Spjd &putdef, brief)) 1042204076Spjd goto errout; 1043204076Spjd ep = ep->ex_next; 1044204076Spjd } 1045204076Spjd sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1046204076Spjd if (!xdr_bool(xdrsp, &false)) 1047204076Spjd return (0); 1048204076Spjd return (1); 1049204076Spjderrout: 1050204076Spjd sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1051204076Spjd return (0); 1052204076Spjd} 1053204076Spjd 1054204076Spjd/* 1055204076Spjd * Called from xdr_explist() to traverse the tree and export the 1056204076Spjd * directory paths. 1057204076Spjd */ 1058204076Spjdint 1059204076Spjdput_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1060204076Spjd int brief) 1061204076Spjd{ 1062204076Spjd struct grouplist *grp; 1063204076Spjd struct hostlist *hp; 1064204076Spjd int true = 1; 1065204076Spjd int false = 0; 1066204076Spjd int gotalldir = 0; 1067204076Spjd char *strp; 1068204076Spjd 1069204076Spjd if (dp) { 1070204076Spjd if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 1071204076Spjd return (1); 1072204076Spjd if (!xdr_bool(xdrsp, &true)) 1073204076Spjd return (1); 1074204076Spjd strp = dp->dp_dirp; 1075204076Spjd if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1076204076Spjd return (1); 1077204076Spjd if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 1078204076Spjd gotalldir = 1; 1079204076Spjd *putdefp = 1; 1080204076Spjd } 1081204076Spjd if (brief) { 1082218138Spjd if (!xdr_bool(xdrsp, &true)) 1083204076Spjd return (1); 1084204076Spjd strp = "(...)"; 1085204076Spjd if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1086204076Spjd return (1); 1087204076Spjd } else if ((dp->dp_flag & DP_DEFSET) == 0 && 1088204076Spjd (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 1089204076Spjd hp = dp->dp_hosts; 1090204076Spjd while (hp) { 1091204076Spjd grp = hp->ht_grp; 1092204076Spjd if (grp->gr_type == GT_HOST) { 1093204076Spjd if (!xdr_bool(xdrsp, &true)) 1094204076Spjd return (1); 1095214284Spjd strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 1096219844Spjd if (!xdr_string(xdrsp, &strp, 1097219844Spjd MNTNAMLEN)) 1098219844Spjd return (1); 1099219844Spjd } else if (grp->gr_type == GT_NET) { 1100219844Spjd if (!xdr_bool(xdrsp, &true)) 1101214284Spjd return (1); 1102214284Spjd strp = grp->gr_ptr.gt_net.nt_name; 1103204076Spjd if (!xdr_string(xdrsp, &strp, 1104204076Spjd MNTNAMLEN)) 1105204076Spjd return (1); 1106204076Spjd } 1107204076Spjd hp = hp->ht_next; 1108204076Spjd if (gotalldir && hp == (struct hostlist *)NULL) { 1109204076Spjd hp = adp->dp_hosts; 1110204076Spjd gotalldir = 0; 1111204076Spjd } 1112204076Spjd } 1113204076Spjd } 1114204076Spjd if (!xdr_bool(xdrsp, &false)) 1115204076Spjd return (1); 1116204076Spjd if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 1117204076Spjd return (1); 1118204076Spjd } 1119204076Spjd return (0); 1120204076Spjd} 1121204076Spjd 1122204076Spjdint 1123204076Spjdxdr_explist(XDR *xdrsp, caddr_t cp) 1124204076Spjd{ 1125204076Spjd 1126204076Spjd return xdr_explist_common(xdrsp, cp, 0); 1127204076Spjd} 1128204076Spjd 1129204076Spjdint 1130204076Spjdxdr_explist_brief(XDR *xdrsp, caddr_t cp) 1131204076Spjd{ 1132204076Spjd 1133204076Spjd return xdr_explist_common(xdrsp, cp, 1); 1134204076Spjd} 1135204076Spjd 1136204076Spjdchar *line; 1137204076Spjdint linesize; 1138204076SpjdFILE *exp_file; 1139204076Spjd 1140204076Spjd/* 1141204076Spjd * Get the export list from one, currently open file 1142204076Spjd */ 1143204076Spjdstatic void 1144204076Spjdget_exportlist_one(void) 1145204076Spjd{ 1146204076Spjd struct exportlist *ep, *ep2; 1147204076Spjd struct grouplist *grp, *tgrp; 1148204076Spjd struct exportlist **epp; 1149204076Spjd struct dirlist *dirhead; 1150204076Spjd struct statfs fsb; 1151204076Spjd struct xucred anon; 1152204076Spjd char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1153204076Spjd int len, has_host, exflags, got_nondir, dirplen, netgrp; 1154204076Spjd 1155204076Spjd v4root_phase = 0; 1156204076Spjd dirhead = (struct dirlist *)NULL; 1157204076Spjd while (get_line()) { 1158204076Spjd if (debug) 1159204076Spjd warnx("got line %s", line); 1160204076Spjd cp = line; 1161204076Spjd nextfield(&cp, &endcp); 1162204076Spjd if (*cp == '#') 1163204076Spjd goto nextline; 1164204076Spjd 1165204076Spjd /* 1166204076Spjd * Set defaults. 1167204076Spjd */ 1168204076Spjd has_host = FALSE; 1169204076Spjd anon = def_anon; 1170204076Spjd exflags = MNT_EXPORTED; 1171204076Spjd got_nondir = 0; 1172214692Spjd opt_flags = 0; 1173204076Spjd ep = (struct exportlist *)NULL; 1174204076Spjd dirp = NULL; 1175204076Spjd 1176204076Spjd /* 1177204076Spjd * Handle the V4 root dir. 1178204076Spjd */ 1179204076Spjd if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1180204076Spjd /* 1181204076Spjd * V4: just indicates that it is the v4 root point, 1182204076Spjd * so skip over that and set v4root_phase. 1183204076Spjd */ 1184204076Spjd if (v4root_phase > 0) { 1185204076Spjd syslog(LOG_ERR, "V4:duplicate line, ignored"); 1186216479Spjd goto nextline; 1187216479Spjd } 1188216479Spjd v4root_phase = 1; 1189216479Spjd cp += 3; 1190216479Spjd nextfield(&cp, &endcp); 1191216479Spjd } 1192216479Spjd 1193216494Spjd /* 1194216479Spjd * Create new exports list entry 1195204076Spjd */ 1196204076Spjd len = endcp-cp; 1197204076Spjd tgrp = grp = get_grp(); 1198204076Spjd while (len > 0) { 1199204076Spjd if (len > MNTNAMLEN) { 1200204076Spjd getexp_err(ep, tgrp); 1201204076Spjd goto nextline; 1202204076Spjd } 1203216479Spjd if (*cp == '-') { 1204204076Spjd if (ep == (struct exportlist *)NULL) { 1205216479Spjd getexp_err(ep, tgrp); 1206216479Spjd goto nextline; 1207216479Spjd } 1208216479Spjd if (debug) 1209204076Spjd warnx("doing opt %s", cp); 1210216479Spjd got_nondir = 1; 1211216479Spjd if (do_opt(&cp, &endcp, ep, grp, &has_host, 1212216494Spjd &exflags, &anon)) { 1213216479Spjd getexp_err(ep, tgrp); 1214204076Spjd goto nextline; 1215216479Spjd } 1216204076Spjd } else if (*cp == '/') { 1217204076Spjd savedc = *endcp; 1218204076Spjd *endcp = '\0'; 1219204076Spjd if (v4root_phase > 1) { 1220204076Spjd if (dirp != NULL) { 1221216479Spjd syslog(LOG_ERR, "Multiple V4 dirs"); 1222204076Spjd getexp_err(ep, tgrp); 1223216479Spjd goto nextline; 1224216479Spjd } 1225216479Spjd } 1226216479Spjd if (check_dirpath(cp) && 1227204076Spjd statfs(cp, &fsb) >= 0) { 1228216479Spjd if (got_nondir) { 1229204076Spjd syslog(LOG_ERR, "dirs must be first"); 1230204076Spjd getexp_err(ep, tgrp); 1231204076Spjd goto nextline; 1232216479Spjd } 1233204076Spjd if (v4root_phase == 1) { 1234216479Spjd if (dirp != NULL) { 1235216479Spjd syslog(LOG_ERR, "Multiple V4 dirs"); 1236216479Spjd getexp_err(ep, tgrp); 1237216479Spjd goto nextline; 1238204076Spjd } 1239216479Spjd if (strlen(v4root_dirpath) == 0) { 1240204076Spjd strlcpy(v4root_dirpath, cp, 1241204076Spjd sizeof (v4root_dirpath)); 1242204076Spjd } else if (strcmp(v4root_dirpath, cp) 1243204076Spjd != 0) { 1244204076Spjd syslog(LOG_ERR, 1245204076Spjd "different V4 dirpath %s", cp); 1246204076Spjd getexp_err(ep, tgrp); 1247204076Spjd goto nextline; 1248204076Spjd } 1249204076Spjd dirp = cp; 1250204076Spjd v4root_phase = 2; 1251204076Spjd got_nondir = 1; 1252204076Spjd ep = get_exp(); 1253204076Spjd } else { 1254204076Spjd if (ep) { 1255204076Spjd if (ep->ex_fs.val[0] != 1256204076Spjd fsb.f_fsid.val[0] || 1257204076Spjd ep->ex_fs.val[1] != 1258204076Spjd fsb.f_fsid.val[1]) { 1259204076Spjd getexp_err(ep, tgrp); 1260214692Spjd goto nextline; 1261214692Spjd } 1262214692Spjd } else { 1263214692Spjd /* 1264214692Spjd * See if this directory is already 1265218217Spjd * in the list. 1266218217Spjd */ 1267218217Spjd ep = ex_search(&fsb.f_fsid); 1268218217Spjd if (ep == (struct exportlist *)NULL) { 1269214692Spjd ep = get_exp(); 1270218217Spjd ep->ex_fs = fsb.f_fsid; 1271214692Spjd ep->ex_fsdir = (char *)malloc 1272218138Spjd (strlen(fsb.f_mntonname) + 1); 1273218138Spjd if (ep->ex_fsdir) 1274214692Spjd strcpy(ep->ex_fsdir, 1275214692Spjd fsb.f_mntonname); 1276214692Spjd else 1277214692Spjd out_of_mem(); 1278218217Spjd if (debug) 1279214692Spjd warnx( 1280214692Spjd "making new ep fs=0x%x,0x%x", 1281214692Spjd fsb.f_fsid.val[0], 1282214692Spjd fsb.f_fsid.val[1]); 1283214692Spjd } else if (debug) 1284214692Spjd warnx("found ep fs=0x%x,0x%x", 1285218217Spjd fsb.f_fsid.val[0], 1286214692Spjd fsb.f_fsid.val[1]); 1287214692Spjd } 1288214692Spjd 1289214692Spjd /* 1290214692Spjd * Add dirpath to export mount point. 1291214692Spjd */ 1292218217Spjd dirp = add_expdir(&dirhead, cp, len); 1293218217Spjd dirplen = len; 1294214692Spjd } 1295214692Spjd } else { 1296214692Spjd getexp_err(ep, tgrp); 1297214692Spjd goto nextline; 1298204076Spjd } 1299204076Spjd *endcp = savedc; 1300204076Spjd } else { 1301204076Spjd savedc = *endcp; 1302204076Spjd *endcp = '\0'; 1303204076Spjd got_nondir = 1; 1304204076Spjd if (ep == (struct exportlist *)NULL) { 1305204076Spjd getexp_err(ep, tgrp); 1306214692Spjd goto nextline; 1307204076Spjd } 1308204076Spjd 1309204076Spjd /* 1310204076Spjd * Get the host or netgroup. 1311204076Spjd */ 1312204076Spjd setnetgrent(cp); 1313204076Spjd netgrp = getnetgrent(&hst, &usr, &dom); 1314204076Spjd do { 1315204076Spjd if (has_host) { 1316204076Spjd grp->gr_next = get_grp(); 1317214692Spjd grp = grp->gr_next; 1318204076Spjd } 1319204076Spjd if (netgrp) { 1320204076Spjd if (hst == 0) { 1321219721Strociny syslog(LOG_ERR, 1322214692Spjd "null hostname in netgroup %s, skipping", cp); 1323214692Spjd grp->gr_type = GT_IGNORE; 1324219721Strociny } else if (get_host(hst, grp, tgrp)) { 1325214692Spjd syslog(LOG_ERR, 1326214692Spjd "bad host %s in netgroup %s, skipping", hst, cp); 1327214692Spjd grp->gr_type = GT_IGNORE; 1328214692Spjd } 1329214692Spjd } else if (get_host(cp, grp, tgrp)) { 1330204076Spjd syslog(LOG_ERR, "bad host %s, skipping", cp); 1331204076Spjd grp->gr_type = GT_IGNORE; 1332204076Spjd } 1333204076Spjd has_host = TRUE; 1334204076Spjd } while (netgrp && getnetgrent(&hst, &usr, &dom)); 1335204076Spjd endnetgrent(); 1336204076Spjd *endcp = savedc; 1337204076Spjd } 1338204076Spjd cp = endcp; 1339204076Spjd nextfield(&cp, &endcp); 1340204076Spjd len = endcp - cp; 1341204076Spjd } 1342204076Spjd if (check_options(dirhead)) { 1343204076Spjd getexp_err(ep, tgrp); 1344204076Spjd goto nextline; 1345204076Spjd } 1346204076Spjd if (!has_host) { 1347204076Spjd grp->gr_type = GT_DEFAULT; 1348204076Spjd if (debug) 1349204076Spjd warnx("adding a default entry"); 1350204076Spjd 1351204076Spjd /* 1352204076Spjd * Don't allow a network export coincide with a list of 1353204076Spjd * host(s) on the same line. 1354204076Spjd */ 1355204076Spjd } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1356204076Spjd syslog(LOG_ERR, "network/host conflict"); 1357204076Spjd getexp_err(ep, tgrp); 1358218138Spjd goto nextline; 1359204076Spjd 1360204076Spjd /* 1361204076Spjd * If an export list was specified on this line, make sure 1362204076Spjd * that we have at least one valid entry, otherwise skip it. 1363204076Spjd */ 1364204076Spjd } else { 1365204076Spjd grp = tgrp; 1366204076Spjd while (grp && grp->gr_type == GT_IGNORE) 1367204076Spjd grp = grp->gr_next; 1368204076Spjd if (! grp) { 1369204076Spjd getexp_err(ep, tgrp); 1370204076Spjd goto nextline; 1371204076Spjd } 1372204076Spjd } 1373204076Spjd 1374204076Spjd if (v4root_phase == 1) { 1375204076Spjd syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1376204076Spjd getexp_err(ep, tgrp); 1377204076Spjd goto nextline; 1378204076Spjd } 1379204076Spjd 1380204076Spjd /* 1381204076Spjd * Loop through hosts, pushing the exports into the kernel. 1382204076Spjd * After loop, tgrp points to the start of the list and 1383204076Spjd * grp points to the last entry in the list. 1384204076Spjd */ 1385204076Spjd grp = tgrp; 1386204076Spjd do { 1387204076Spjd if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 1388204076Spjd &fsb)) { 1389204076Spjd getexp_err(ep, tgrp); 1390204076Spjd goto nextline; 1391204076Spjd } 1392204076Spjd } while (grp->gr_next && (grp = grp->gr_next)); 1393204076Spjd 1394204076Spjd /* 1395204076Spjd * For V4: don't enter in mount lists. 1396204076Spjd */ 1397204076Spjd if (v4root_phase > 0 && v4root_phase <= 2) { 1398204076Spjd /* 1399204076Spjd * Since these structures aren't used by mountd, 1400204076Spjd * free them up now. 1401204076Spjd */ 1402204076Spjd if (ep != NULL) 1403204076Spjd free_exp(ep); 1404204076Spjd while (tgrp != NULL) { 1405204076Spjd grp = tgrp; 1406204076Spjd tgrp = tgrp->gr_next; 1407211979Spjd free_grp(grp); 1408204076Spjd } 1409204076Spjd goto nextline; 1410204076Spjd } 1411204076Spjd 1412204076Spjd /* 1413204076Spjd * Success. Update the data structures. 1414204076Spjd */ 1415204076Spjd if (has_host) { 1416204076Spjd hang_dirp(dirhead, tgrp, ep, opt_flags); 1417204076Spjd grp->gr_next = grphead; 1418204076Spjd grphead = tgrp; 1419204076Spjd } else { 1420204076Spjd hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1421204076Spjd opt_flags); 1422204076Spjd free_grp(grp); 1423204076Spjd } 1424204076Spjd dirhead = (struct dirlist *)NULL; 1425204076Spjd if ((ep->ex_flag & EX_LINKED) == 0) { 1426204076Spjd ep2 = exphead; 1427204076Spjd epp = &exphead; 1428204076Spjd 1429204076Spjd /* 1430204076Spjd * Insert in the list in alphabetical order. 1431204076Spjd */ 1432204076Spjd while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1433204076Spjd epp = &ep2->ex_next; 1434204076Spjd ep2 = ep2->ex_next; 1435204076Spjd } 1436204076Spjd if (ep2) 1437204076Spjd ep->ex_next = ep2; 1438204076Spjd *epp = ep; 1439204076Spjd ep->ex_flag |= EX_LINKED; 1440204076Spjd } 1441204076Spjdnextline: 1442204076Spjd v4root_phase = 0; 1443204076Spjd if (dirhead) { 1444204076Spjd free_dir(dirhead); 1445204076Spjd dirhead = (struct dirlist *)NULL; 1446204076Spjd } 1447204076Spjd } 1448204076Spjd} 1449204076Spjd 1450204076Spjd/* 1451204076Spjd * Get the export list from all specified files 1452204076Spjd */ 1453204076Spjdvoid 1454204076Spjdget_exportlist(void) 1455204076Spjd{ 1456204076Spjd struct exportlist *ep, *ep2; 1457204076Spjd struct grouplist *grp, *tgrp; 1458204076Spjd struct export_args export; 1459204076Spjd struct iovec *iov; 1460204076Spjd struct statfs *fsp, *mntbufp; 1461204076Spjd struct xvfsconf vfc; 1462204076Spjd char *dirp; 1463204076Spjd char errmsg[255]; 1464204076Spjd int dirplen, num, i; 1465204076Spjd int iovlen; 1466204076Spjd int done; 1467204076Spjd struct nfsex_args eargs; 1468204076Spjd 1469204076Spjd v4root_dirpath[0] = '\0'; 1470204076Spjd bzero(&export, sizeof(export)); 1471204076Spjd export.ex_flags = MNT_DELEXPORT; 1472204076Spjd dirp = NULL; 1473204076Spjd dirplen = 0; 1474204076Spjd iov = NULL; 1475204076Spjd iovlen = 0; 1476204076Spjd bzero(errmsg, sizeof(errmsg)); 1477204076Spjd 1478204076Spjd /* 1479204076Spjd * First, get rid of the old list 1480204076Spjd */ 1481204076Spjd ep = exphead; 1482204076Spjd while (ep) { 1483204076Spjd ep2 = ep; 1484204076Spjd ep = ep->ex_next; 1485204076Spjd free_exp(ep2); 1486204076Spjd } 1487204076Spjd exphead = (struct exportlist *)NULL; 1488218138Spjd 1489204076Spjd grp = grphead; 1490204076Spjd while (grp) { 1491204076Spjd tgrp = grp; 1492204076Spjd grp = grp->gr_next; 1493204076Spjd free_grp(tgrp); 1494204076Spjd } 1495204076Spjd grphead = (struct grouplist *)NULL; 1496204076Spjd 1497204076Spjd /* 1498204076Spjd * and the old V4 root dir. 1499204076Spjd */ 1500204076Spjd bzero(&eargs, sizeof (eargs)); 1501204076Spjd eargs.export.ex_flags = MNT_DELEXPORT; 1502204076Spjd if (run_v4server > 0 && 1503204076Spjd nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1504204076Spjd errno != ENOENT) 1505204076Spjd syslog(LOG_ERR, "Can't delete exports for V4:"); 1506204076Spjd 1507204076Spjd /* 1508204076Spjd * and clear flag that notes if a public fh has been exported. 1509204076Spjd */ 1510204076Spjd has_publicfh = 0; 1511204076Spjd 1512204076Spjd /* 1513204076Spjd * And delete exports that are in the kernel for all local 1514204076Spjd * filesystems. 1515204076Spjd * XXX: Should know how to handle all local exportable filesystems. 1516204076Spjd */ 1517204076Spjd num = getmntinfo(&mntbufp, MNT_NOWAIT); 1518204076Spjd 1519204076Spjd if (num > 0) { 1520204076Spjd build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1521204076Spjd build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1522204076Spjd build_iovec(&iov, &iovlen, "from", NULL, 0); 1523204076Spjd build_iovec(&iov, &iovlen, "update", NULL, 0); 1524204076Spjd build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1525204076Spjd build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1526216478Spjd } 1527216479Spjd 1528216479Spjd for (i = 0; i < num; i++) { 1529204076Spjd fsp = &mntbufp[i]; 1530204076Spjd if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1531204076Spjd syslog(LOG_ERR, "getvfsbyname() failed for %s", 1532204076Spjd fsp->f_fstypename); 1533204076Spjd continue; 1534204076Spjd } 1535204076Spjd 1536204076Spjd /* 1537204076Spjd * Do not delete export for network filesystem by 1538204076Spjd * passing "export" arg to nmount(). 1539204076Spjd * It only makes sense to do this for local filesystems. 1540204076Spjd */ 1541204076Spjd if (vfc.vfc_flags & VFCF_NETWORK) 1542204076Spjd continue; 1543204076Spjd 1544204076Spjd iov[1].iov_base = fsp->f_fstypename; 1545204076Spjd iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1546204076Spjd iov[3].iov_base = fsp->f_mntonname; 1547204076Spjd iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1548204076Spjd iov[5].iov_base = fsp->f_mntfromname; 1549204076Spjd iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1550204076Spjd 1551204076Spjd if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1552204076Spjd errno != ENOENT && errno != ENOTSUP) { 1553204076Spjd syslog(LOG_ERR, 1554204076Spjd "can't delete exports for %s: %m %s", 1555204076Spjd fsp->f_mntonname, errmsg); 1556204076Spjd } 1557204076Spjd } 1558218138Spjd 1559204076Spjd if (iov != NULL) { 1560204076Spjd /* Free strings allocated by strdup() in getmntopts.c */ 1561204076Spjd free(iov[0].iov_base); /* fstype */ 1562204076Spjd free(iov[2].iov_base); /* fspath */ 1563204076Spjd free(iov[4].iov_base); /* from */ 1564204076Spjd free(iov[6].iov_base); /* update */ 1565204076Spjd free(iov[8].iov_base); /* export */ 1566204076Spjd free(iov[10].iov_base); /* errmsg */ 1567204076Spjd 1568204076Spjd /* free iov, allocated by realloc() */ 1569204076Spjd free(iov); 1570204076Spjd iovlen = 0; 1571204076Spjd } 1572204076Spjd 1573204076Spjd /* 1574204076Spjd * Read in the exports file and build the list, calling 1575204076Spjd * nmount() as we go along to push the export rules into the kernel. 1576204076Spjd */ 1577204076Spjd done = 0; 1578204076Spjd for (i = 0; exnames[i] != NULL; i++) { 1579204076Spjd if (debug) 1580204076Spjd warnx("reading exports from %s", exnames[i]); 1581204076Spjd if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1582204076Spjd syslog(LOG_WARNING, "can't open %s", exnames[i]); 1583204076Spjd continue; 1584204076Spjd } 1585204076Spjd get_exportlist_one(); 1586204076Spjd fclose(exp_file); 1587204076Spjd done++; 1588204076Spjd } 1589204076Spjd if (done == 0) { 1590204076Spjd syslog(LOG_ERR, "can't open any exports file"); 1591204076Spjd exit(2); 1592204076Spjd } 1593204076Spjd 1594204076Spjd /* 1595204076Spjd * If there was no public fh, clear any previous one set. 1596204076Spjd */ 1597204076Spjd if (run_v4server > 0 && has_publicfh == 0) 1598204076Spjd (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1599204076Spjd} 1600204076Spjd 1601204076Spjd/* 1602204076Spjd * Allocate an export list element 1603204076Spjd */ 1604204076Spjdstruct exportlist * 1605204076Spjdget_exp(void) 1606204076Spjd{ 1607204076Spjd struct exportlist *ep; 1608204076Spjd 1609204076Spjd ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1610204076Spjd if (ep == (struct exportlist *)NULL) 1611204076Spjd out_of_mem(); 1612204076Spjd memset(ep, 0, sizeof(struct exportlist)); 1613204076Spjd return (ep); 1614204076Spjd} 1615204076Spjd 1616204076Spjd/* 1617204076Spjd * Allocate a group list element 1618204076Spjd */ 1619204076Spjdstruct grouplist * 1620204076Spjdget_grp(void) 1621204076Spjd{ 1622204076Spjd struct grouplist *gp; 1623204076Spjd 1624204076Spjd gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1625204076Spjd if (gp == (struct grouplist *)NULL) 1626204076Spjd out_of_mem(); 1627204076Spjd memset(gp, 0, sizeof(struct grouplist)); 1628204076Spjd return (gp); 1629204076Spjd} 1630204076Spjd 1631204076Spjd/* 1632204076Spjd * Clean up upon an error in get_exportlist(). 1633204076Spjd */ 1634204076Spjdvoid 1635204076Spjdgetexp_err(struct exportlist *ep, struct grouplist *grp) 1636204076Spjd{ 1637204076Spjd struct grouplist *tgrp; 1638204076Spjd 1639204076Spjd if (!(opt_flags & OP_QUIET)) 1640204076Spjd syslog(LOG_ERR, "bad exports list line %s", line); 1641204076Spjd if (ep && (ep->ex_flag & EX_LINKED) == 0) 1642204076Spjd free_exp(ep); 1643204076Spjd while (grp) { 1644204076Spjd tgrp = grp; 1645204076Spjd grp = grp->gr_next; 1646204076Spjd free_grp(tgrp); 1647204076Spjd } 1648204076Spjd} 1649204076Spjd 1650204076Spjd/* 1651204076Spjd * Search the export list for a matching fs. 1652204076Spjd */ 1653204076Spjdstruct exportlist * 1654204076Spjdex_search(fsid_t *fsid) 1655204076Spjd{ 1656204076Spjd struct exportlist *ep; 1657204076Spjd 1658204076Spjd ep = exphead; 1659204076Spjd while (ep) { 1660204076Spjd if (ep->ex_fs.val[0] == fsid->val[0] && 1661204076Spjd ep->ex_fs.val[1] == fsid->val[1]) 1662204076Spjd return (ep); 1663204076Spjd ep = ep->ex_next; 1664204076Spjd } 1665204076Spjd return (ep); 1666204076Spjd} 1667204076Spjd 1668204076Spjd/* 1669204076Spjd * Add a directory path to the list. 1670204076Spjd */ 1671204076Spjdchar * 1672219372Spjdadd_expdir(struct dirlist **dpp, char *cp, int len) 1673204076Spjd{ 1674204076Spjd struct dirlist *dp; 1675204076Spjd 1676204076Spjd dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1677204076Spjd if (dp == (struct dirlist *)NULL) 1678204076Spjd out_of_mem(); 1679204076Spjd dp->dp_left = *dpp; 1680211897Spjd dp->dp_right = (struct dirlist *)NULL; 1681211897Spjd dp->dp_flag = 0; 1682204076Spjd dp->dp_hosts = (struct hostlist *)NULL; 1683204076Spjd strcpy(dp->dp_dirp, cp); 1684204076Spjd *dpp = dp; 1685211897Spjd return (dp->dp_dirp); 1686219372Spjd} 1687219372Spjd 1688219372Spjd/* 1689219372Spjd * Hang the dir list element off the dirpath binary tree as required 1690211879Spjd * and update the entry for host. 1691212038Spjd */ 1692211879Spjdvoid 1693204076Spjdhang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1694204076Spjd int flags) 1695204076Spjd{ 1696204076Spjd struct hostlist *hp; 1697204076Spjd struct dirlist *dp2; 1698204076Spjd 1699204076Spjd if (flags & OP_ALLDIRS) { 1700204076Spjd if (ep->ex_defdir) 1701204076Spjd free((caddr_t)dp); 1702204076Spjd else 1703204076Spjd ep->ex_defdir = dp; 1704204076Spjd if (grp == (struct grouplist *)NULL) { 1705204076Spjd ep->ex_defdir->dp_flag |= DP_DEFSET; 1706204076Spjd } else while (grp) { 1707204076Spjd hp = get_ht(); 1708204076Spjd hp->ht_grp = grp; 1709204076Spjd hp->ht_next = ep->ex_defdir->dp_hosts; 1710204076Spjd ep->ex_defdir->dp_hosts = hp; 1711204076Spjd grp = grp->gr_next; 1712204076Spjd } 1713204076Spjd } else { 1714204076Spjd 1715204076Spjd /* 1716204076Spjd * Loop through the directories adding them to the tree. 1717204076Spjd */ 1718204076Spjd while (dp) { 1719204076Spjd dp2 = dp->dp_left; 1720204076Spjd add_dlist(&ep->ex_dirl, dp, grp, flags); 1721219372Spjd dp = dp2; 1722219372Spjd } 1723204076Spjd } 1724212038Spjd} 1725219372Spjd 1726204076Spjd/* 1727204076Spjd * Traverse the binary tree either updating a node that is already there 1728204076Spjd * for the new directory or adding the new node. 1729211878Spjd */ 1730204076Spjdvoid 1731204076Spjdadd_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1732204076Spjd int flags) 1733204076Spjd{ 1734204076Spjd struct dirlist *dp; 1735204076Spjd struct hostlist *hp; 1736204076Spjd int cmp; 1737204076Spjd 1738204076Spjd dp = *dpp; 1739219372Spjd if (dp) { 1740219372Spjd cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1741219372Spjd if (cmp > 0) { 1742219372Spjd add_dlist(&dp->dp_left, newdp, grp, flags); 1743219372Spjd return; 1744219372Spjd } else if (cmp < 0) { 1745219372Spjd add_dlist(&dp->dp_right, newdp, grp, flags); 1746204076Spjd return; 1747219372Spjd } else 1748219372Spjd free((caddr_t)newdp); 1749219372Spjd } else { 1750212038Spjd dp = newdp; 1751204076Spjd dp->dp_left = (struct dirlist *)NULL; 1752204076Spjd *dpp = dp; 1753204076Spjd } 1754204076Spjd if (grp) { 1755204076Spjd 1756204076Spjd /* 1757204076Spjd * Hang all of the host(s) off of the directory point. 1758204076Spjd */ 1759204076Spjd do { 1760204076Spjd hp = get_ht(); 1761204076Spjd hp->ht_grp = grp; 1762204076Spjd hp->ht_next = dp->dp_hosts; 1763204076Spjd dp->dp_hosts = hp; 1764204076Spjd grp = grp->gr_next; 1765204076Spjd } while (grp); 1766204076Spjd } else { 1767204076Spjd dp->dp_flag |= DP_DEFSET; 1768204076Spjd } 1769204076Spjd} 1770204076Spjd 1771204076Spjd/* 1772204076Spjd * Search for a dirpath on the export point. 1773204076Spjd */ 1774204076Spjdstruct dirlist * 1775204076Spjddirp_search(struct dirlist *dp, char *dirp) 1776204076Spjd{ 1777204076Spjd int cmp; 1778204076Spjd 1779204076Spjd if (dp) { 1780204076Spjd cmp = strcmp(dp->dp_dirp, dirp); 1781204076Spjd if (cmp > 0) 1782204076Spjd return (dirp_search(dp->dp_left, dirp)); 1783204076Spjd else if (cmp < 0) 1784204076Spjd return (dirp_search(dp->dp_right, dirp)); 1785204076Spjd else 1786204076Spjd return (dp); 1787204076Spjd } 1788204076Spjd return (dp); 1789204076Spjd} 1790204076Spjd 1791204076Spjd/* 1792204076Spjd * Scan for a host match in a directory tree. 1793204076Spjd */ 1794204076Spjdint 1795204076Spjdchk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 1796204076Spjd int *hostsetp) 1797204076Spjd{ 1798204076Spjd struct hostlist *hp; 1799204076Spjd struct grouplist *grp; 1800204076Spjd struct addrinfo *ai; 1801204076Spjd 1802204076Spjd if (dp) { 1803204076Spjd if (dp->dp_flag & DP_DEFSET) 1804204076Spjd *defsetp = dp->dp_flag; 1805204076Spjd hp = dp->dp_hosts; 1806204076Spjd while (hp) { 1807204076Spjd grp = hp->ht_grp; 1808204076Spjd switch (grp->gr_type) { 1809204076Spjd case GT_HOST: 1810204076Spjd ai = grp->gr_ptr.gt_addrinfo; 1811204076Spjd for (; ai; ai = ai->ai_next) { 1812204076Spjd if (!sacmp(ai->ai_addr, saddr, NULL)) { 1813204076Spjd *hostsetp = 1814204076Spjd (hp->ht_flag | DP_HOSTSET); 1815204076Spjd return (1); 1816204076Spjd } 1817204076Spjd } 1818204076Spjd break; 1819204076Spjd case GT_NET: 1820204076Spjd if (!sacmp(saddr, (struct sockaddr *) 1821204076Spjd &grp->gr_ptr.gt_net.nt_net, 1822218138Spjd (struct sockaddr *) 1823204076Spjd &grp->gr_ptr.gt_net.nt_mask)) { 1824204076Spjd *hostsetp = (hp->ht_flag | DP_HOSTSET); 1825204076Spjd return (1); 1826204076Spjd } 1827204076Spjd break; 1828204076Spjd } 1829204076Spjd hp = hp->ht_next; 1830204076Spjd } 1831204076Spjd } 1832204076Spjd return (0); 1833204076Spjd} 1834204076Spjd 1835204076Spjd/* 1836204076Spjd * Scan tree for a host that matches the address. 1837204076Spjd */ 1838204076Spjdint 1839204076Spjdscan_tree(struct dirlist *dp, struct sockaddr *saddr) 1840204076Spjd{ 1841204076Spjd int defset, hostset; 1842204076Spjd 1843204076Spjd if (dp) { 1844204076Spjd if (scan_tree(dp->dp_left, saddr)) 1845204076Spjd return (1); 1846204076Spjd if (chk_host(dp, saddr, &defset, &hostset)) 1847204076Spjd return (1); 1848204076Spjd if (scan_tree(dp->dp_right, saddr)) 1849204076Spjd return (1); 1850204076Spjd } 1851204076Spjd return (0); 1852204076Spjd} 1853204076Spjd 1854204076Spjd/* 1855204076Spjd * Traverse the dirlist tree and free it up. 1856204076Spjd */ 1857204076Spjdvoid 1858204076Spjdfree_dir(struct dirlist *dp) 1859204076Spjd{ 1860204076Spjd 1861204076Spjd if (dp) { 1862204076Spjd free_dir(dp->dp_left); 1863204076Spjd free_dir(dp->dp_right); 1864204076Spjd free_host(dp->dp_hosts); 1865204076Spjd free((caddr_t)dp); 1866204076Spjd } 1867204076Spjd} 1868204076Spjd 1869218138Spjd/* 1870204076Spjd * Parse a colon separated list of security flavors 1871204076Spjd */ 1872204076Spjdint 1873204076Spjdparsesec(char *seclist, struct exportlist *ep) 1874204076Spjd{ 1875204076Spjd char *cp, savedc; 1876204076Spjd int flavor; 1877204076Spjd 1878204076Spjd ep->ex_numsecflavors = 0; 1879204076Spjd for (;;) { 1880204076Spjd cp = strchr(seclist, ':'); 1881204076Spjd if (cp) { 1882204076Spjd savedc = *cp; 1883204076Spjd *cp = '\0'; 1884204076Spjd } 1885204076Spjd 1886204076Spjd if (!strcmp(seclist, "sys")) 1887204076Spjd flavor = AUTH_SYS; 1888204076Spjd else if (!strcmp(seclist, "krb5")) 1889204076Spjd flavor = RPCSEC_GSS_KRB5; 1890204076Spjd else if (!strcmp(seclist, "krb5i")) 1891204076Spjd flavor = RPCSEC_GSS_KRB5I; 1892204076Spjd else if (!strcmp(seclist, "krb5p")) 1893204076Spjd flavor = RPCSEC_GSS_KRB5P; 1894204076Spjd else { 1895204076Spjd if (cp) 1896204076Spjd *cp = savedc; 1897211880Spjd syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1898211880Spjd return (1); 1899204076Spjd } 1900204076Spjd if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1901204076Spjd if (cp) 1902204076Spjd *cp = savedc; 1903204076Spjd syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1904204076Spjd return (1); 1905204076Spjd } 1906204076Spjd ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1907204076Spjd ep->ex_numsecflavors++; 1908204076Spjd if (cp) { 1909204076Spjd *cp = savedc; 1910204076Spjd seclist = cp + 1; 1911204076Spjd } else { 1912204076Spjd break; 1913217784Spjd } 1914217784Spjd } 1915210886Spjd return (0); 1916210886Spjd} 1917217784Spjd 1918217784Spjd/* 1919210886Spjd * Parse the option string and update fields. 1920210886Spjd * Option arguments may either be -<option>=<value> or 1921210886Spjd * -<option> <value> 1922218138Spjd */ 1923218138Spjdint 1924217784Spjddo_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 1925219818Spjd int *has_hostp, int *exflagsp, struct xucred *cr) 1926217784Spjd{ 1927219351Spjd char *cpoptarg, *cpoptend; 1928219354Spjd char *cp, *endcp, *cpopt, savedc, savedc2; 1929217784Spjd int allflag, usedarg; 1930217784Spjd 1931217784Spjd savedc2 = '\0'; 1932210886Spjd cpopt = *cpp; 1933210886Spjd cpopt++; 1934219351Spjd cp = *endcpp; 1935219818Spjd savedc = *cp; 1936219818Spjd *cp = '\0'; 1937219818Spjd while (cpopt && *cpopt) { 1938219818Spjd allflag = 1; 1939219818Spjd usedarg = -2; 1940219818Spjd if ((cpoptend = strchr(cpopt, ','))) { 1941210886Spjd *cpoptend++ = '\0'; 1942217784Spjd if ((cpoptarg = strchr(cpopt, '='))) 1943217784Spjd *cpoptarg++ = '\0'; 1944217784Spjd } else { 1945210886Spjd if ((cpoptarg = strchr(cpopt, '='))) 1946210886Spjd *cpoptarg++ = '\0'; 1947210886Spjd else { 1948210886Spjd *cp = savedc; 1949210886Spjd nextfield(&cp, &endcp); 1950210886Spjd **endcpp = '\0'; 1951210886Spjd if (endcp > cp && *cp != '-') { 1952219818Spjd cpoptarg = cp; 1953219818Spjd savedc2 = *endcp; 1954219818Spjd *endcp = '\0'; 1955219818Spjd usedarg = 0; 1956219818Spjd } 1957217784Spjd } 1958217784Spjd } 1959217784Spjd if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1960210886Spjd *exflagsp |= MNT_EXRDONLY; 1961210886Spjd } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1962219351Spjd !(allflag = strcmp(cpopt, "mapall")) || 1963219351Spjd !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1964219351Spjd usedarg++; 1965219351Spjd parsecred(cpoptarg, cr); 1966219351Spjd if (allflag == 0) { 1967219354Spjd *exflagsp |= MNT_EXPORTANON; 1968219354Spjd opt_flags |= OP_MAPALL; 1969219354Spjd } else 1970219354Spjd opt_flags |= OP_MAPROOT; 1971219354Spjd } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1972217784Spjd !strcmp(cpopt, "m"))) { 1973217784Spjd if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1974217784Spjd syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1975210886Spjd return (1); 1976210886Spjd } 1977217784Spjd usedarg++; 1978217784Spjd opt_flags |= OP_MASK; 1979217784Spjd } else if (cpoptarg && (!strcmp(cpopt, "network") || 1980211886Spjd !strcmp(cpopt, "n"))) { 1981211886Spjd if (strchr(cpoptarg, '/') != NULL) { 1982217784Spjd if (debug) 1983210886Spjd fprintf(stderr, "setting OP_MASKLEN\n"); 1984219351Spjd opt_flags |= OP_MASKLEN; 1985219351Spjd } 1986210886Spjd if (grp->gr_type != GT_NULL) { 1987219351Spjd syslog(LOG_ERR, "network/host conflict"); 1988219818Spjd return (1); 1989219818Spjd } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1990210886Spjd syslog(LOG_ERR, "bad net: %s", cpoptarg); 1991210886Spjd return (1); 1992210886Spjd } 1993210886Spjd grp->gr_type = GT_NET; 1994210886Spjd *has_hostp = 1; 1995210886Spjd usedarg++; 1996210886Spjd opt_flags |= OP_NET; 1997210886Spjd } else if (!strcmp(cpopt, "alldirs")) { 1998210886Spjd opt_flags |= OP_ALLDIRS; 1999210886Spjd } else if (!strcmp(cpopt, "public")) { 2000210886Spjd *exflagsp |= MNT_EXPUBLIC; 2001210886Spjd } else if (!strcmp(cpopt, "webnfs")) { 2002210886Spjd *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2003210886Spjd opt_flags |= OP_MAPALL; 2004210886Spjd } else if (cpoptarg && !strcmp(cpopt, "index")) { 2005210886Spjd ep->ex_indexfile = strdup(cpoptarg); 2006210886Spjd } else if (!strcmp(cpopt, "quiet")) { 2007210886Spjd opt_flags |= OP_QUIET; 2008210886Spjd } else if (!strcmp(cpopt, "sec")) { 2009210886Spjd if (parsesec(cpoptarg, ep)) 2010219351Spjd return (1); 2011219818Spjd opt_flags |= OP_SEC; 2012219818Spjd usedarg++; 2013210886Spjd } else { 2014210886Spjd syslog(LOG_ERR, "bad opt %s", cpopt); 2015210886Spjd return (1); 2016210886Spjd } 2017210886Spjd if (usedarg >= 0) { 2018210886Spjd *endcp = savedc2; 2019217784Spjd **endcpp = savedc; 2020217784Spjd if (usedarg > 0) { 2021210886Spjd *cpp = cp; 2022210886Spjd *endcpp = endcp; 2023210886Spjd } 2024210886Spjd return (0); 2025219818Spjd } 2026210886Spjd cpopt = cpoptend; 2027219351Spjd } 2028219354Spjd **endcpp = savedc; 2029210886Spjd return (0); 2030211886Spjd} 2031210886Spjd 2032210886Spjd/* 2033210886Spjd * Translate a character string to the corresponding list of network 2034210886Spjd * addresses for a hostname. 2035211882Spjd */ 2036211981Spjdint 2037211981Spjdget_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 2038211981Spjd{ 2039211981Spjd struct grouplist *checkgrp; 2040211981Spjd struct addrinfo *ai, *tai, hints; 2041211981Spjd int ecode; 2042211981Spjd char host[NI_MAXHOST]; 2043211981Spjd 2044211981Spjd if (grp->gr_type != GT_NULL) { 2045211981Spjd syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 2046211981Spjd return (1); 2047211981Spjd } 2048211981Spjd memset(&hints, 0, sizeof hints); 2049211981Spjd hints.ai_flags = AI_CANONNAME; 2050211981Spjd hints.ai_protocol = IPPROTO_UDP; 2051218138Spjd ecode = getaddrinfo(cp, NULL, &hints, &ai); 2052218138Spjd if (ecode != 0) { 2053211981Spjd syslog(LOG_ERR,"can't get address info for host %s", cp); 2054211981Spjd return 1; 2055211981Spjd } 2056211981Spjd grp->gr_ptr.gt_addrinfo = ai; 2057211981Spjd while (ai != NULL) { 2058211981Spjd if (ai->ai_canonname == NULL) { 2059218138Spjd if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2060218138Spjd sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 2061211981Spjd strlcpy(host, "?", sizeof(host)); 2062211981Spjd ai->ai_canonname = strdup(host); 2063211981Spjd ai->ai_flags |= AI_CANONNAME; 2064211981Spjd } 2065211981Spjd if (debug) 2066211981Spjd fprintf(stderr, "got host %s\n", ai->ai_canonname); 2067211981Spjd /* 2068211981Spjd * Sanity check: make sure we don't already have an entry 2069211981Spjd * for this host in the grouplist. 2070211981Spjd */ 2071218138Spjd for (checkgrp = tgrp; checkgrp != NULL; 2072218138Spjd checkgrp = checkgrp->gr_next) { 2073218138Spjd if (checkgrp->gr_type != GT_HOST) 2074211981Spjd continue; 2075211981Spjd for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 2076211981Spjd tai = tai->ai_next) { 2077211981Spjd if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 2078211981Spjd continue; 2079211981Spjd if (debug) 2080211981Spjd fprintf(stderr, 2081211981Spjd "ignoring duplicate host %s\n", 2082218138Spjd ai->ai_canonname); 2083218138Spjd grp->gr_type = GT_IGNORE; 2084218138Spjd return (0); 2085211981Spjd } 2086211981Spjd } 2087211981Spjd ai = ai->ai_next; 2088211981Spjd } 2089211981Spjd grp->gr_type = GT_HOST; 2090204076Spjd return (0); 2091204076Spjd} 2092204076Spjd 2093204076Spjd/* 2094204076Spjd * Free up an exports list component 2095204076Spjd */ 2096204076Spjdvoid 2097204076Spjdfree_exp(struct exportlist *ep) 2098204076Spjd{ 2099211982Spjd 2100211981Spjd if (ep->ex_defdir) { 2101211982Spjd free_host(ep->ex_defdir->dp_hosts); 2102211982Spjd free((caddr_t)ep->ex_defdir); 2103204076Spjd } 2104204076Spjd if (ep->ex_fsdir) 2105211981Spjd free(ep->ex_fsdir); 2106204076Spjd if (ep->ex_indexfile) 2107211982Spjd free(ep->ex_indexfile); 2108211982Spjd free_dir(ep->ex_dirl); 2109211982Spjd free((caddr_t)ep); 2110211982Spjd} 2111219721Strociny 2112211982Spjd/* 2113211982Spjd * Free hosts. 2114211982Spjd */ 2115204076Spjdvoid 2116211982Spjdfree_host(struct hostlist *hp) 2117211982Spjd{ 2118211982Spjd struct hostlist *hp2; 2119211982Spjd 2120204076Spjd while (hp) { 2121204076Spjd hp2 = hp; 2122211982Spjd hp = hp->ht_next; 2123211982Spjd free((caddr_t)hp2); 2124211982Spjd } 2125204076Spjd} 2126211882Spjd 2127204076Spjdstruct hostlist * 2128211981Spjdget_ht(void) 2129219721Strociny{ 2130211982Spjd struct hostlist *hp; 2131211981Spjd 2132211981Spjd hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 2133204076Spjd if (hp == (struct hostlist *)NULL) 2134211982Spjd out_of_mem(); 2135204076Spjd hp->ht_next = (struct hostlist *)NULL; 2136204076Spjd hp->ht_flag = 0; 2137204076Spjd return (hp); 2138204076Spjd} 2139 2140/* 2141 * Out of memory, fatal 2142 */ 2143void 2144out_of_mem(void) 2145{ 2146 2147 syslog(LOG_ERR, "out of memory"); 2148 exit(2); 2149} 2150 2151/* 2152 * Do the nmount() syscall with the update flag to push the export info into 2153 * the kernel. 2154 */ 2155int 2156do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2157 struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 2158{ 2159 struct statfs fsb1; 2160 struct addrinfo *ai; 2161 struct export_args ea, *eap; 2162 char errmsg[255]; 2163 char *cp; 2164 int done; 2165 char savedc; 2166 struct iovec *iov; 2167 int i, iovlen; 2168 int ret; 2169 struct nfsex_args nfsea; 2170 2171 if (run_v4server > 0) 2172 eap = &nfsea.export; 2173 else 2174 eap = &ea; 2175 2176 cp = NULL; 2177 savedc = '\0'; 2178 iov = NULL; 2179 iovlen = 0; 2180 ret = 0; 2181 2182 bzero(eap, sizeof (struct export_args)); 2183 bzero(errmsg, sizeof(errmsg)); 2184 eap->ex_flags = exflags; 2185 eap->ex_anon = *anoncrp; 2186 eap->ex_indexfile = ep->ex_indexfile; 2187 if (grp->gr_type == GT_HOST) 2188 ai = grp->gr_ptr.gt_addrinfo; 2189 else 2190 ai = NULL; 2191 eap->ex_numsecflavors = ep->ex_numsecflavors; 2192 for (i = 0; i < eap->ex_numsecflavors; i++) 2193 eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2194 if (eap->ex_numsecflavors == 0) { 2195 eap->ex_numsecflavors = 1; 2196 eap->ex_secflavors[0] = AUTH_SYS; 2197 } 2198 done = FALSE; 2199 2200 if (v4root_phase == 0) { 2201 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2202 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2203 build_iovec(&iov, &iovlen, "from", NULL, 0); 2204 build_iovec(&iov, &iovlen, "update", NULL, 0); 2205 build_iovec(&iov, &iovlen, "export", eap, 2206 sizeof (struct export_args)); 2207 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2208 } 2209 2210 while (!done) { 2211 switch (grp->gr_type) { 2212 case GT_HOST: 2213 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 2214 goto skip; 2215 eap->ex_addr = ai->ai_addr; 2216 eap->ex_addrlen = ai->ai_addrlen; 2217 eap->ex_masklen = 0; 2218 break; 2219 case GT_NET: 2220 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 2221 have_v6 == 0) 2222 goto skip; 2223 eap->ex_addr = 2224 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2225 eap->ex_addrlen = 2226 ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2227 eap->ex_mask = 2228 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2229 eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 2230 break; 2231 case GT_DEFAULT: 2232 eap->ex_addr = NULL; 2233 eap->ex_addrlen = 0; 2234 eap->ex_mask = NULL; 2235 eap->ex_masklen = 0; 2236 break; 2237 case GT_IGNORE: 2238 ret = 0; 2239 goto error_exit; 2240 break; 2241 default: 2242 syslog(LOG_ERR, "bad grouptype"); 2243 if (cp) 2244 *cp = savedc; 2245 ret = 1; 2246 goto error_exit; 2247 }; 2248 2249 /* 2250 * For V4:, use the nfssvc() syscall, instead of mount(). 2251 */ 2252 if (v4root_phase == 2) { 2253 nfsea.fspec = v4root_dirpath; 2254 if (run_v4server > 0 && 2255 nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2256 syslog(LOG_ERR, "Exporting V4: failed"); 2257 return (2); 2258 } 2259 } else { 2260 /* 2261 * XXX: 2262 * Maybe I should just use the fsb->f_mntonname path 2263 * instead of looping back up the dirp to the mount 2264 * point?? 2265 * Also, needs to know how to export all types of local 2266 * exportable filesystems and not just "ufs". 2267 */ 2268 iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2269 iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2270 iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2271 iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2272 iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2273 iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2274 2275 while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2276 if (cp) 2277 *cp-- = savedc; 2278 else 2279 cp = dirp + dirplen - 1; 2280 if (opt_flags & OP_QUIET) { 2281 ret = 1; 2282 goto error_exit; 2283 } 2284 if (errno == EPERM) { 2285 if (debug) 2286 warnx("can't change attributes for %s", 2287 dirp); 2288 syslog(LOG_ERR, 2289 "can't change attributes for %s", 2290 dirp); 2291 ret = 1; 2292 goto error_exit; 2293 } 2294 if (opt_flags & OP_ALLDIRS) { 2295 if (errno == EINVAL) 2296 syslog(LOG_ERR, 2297 "-alldirs requested but %s is not a filesystem mountpoint", 2298 dirp); 2299 else 2300 syslog(LOG_ERR, 2301 "could not remount %s: %m", 2302 dirp); 2303 ret = 1; 2304 goto error_exit; 2305 } 2306 /* back up over the last component */ 2307 while (*cp == '/' && cp > dirp) 2308 cp--; 2309 while (*(cp - 1) != '/' && cp > dirp) 2310 cp--; 2311 if (cp == dirp) { 2312 if (debug) 2313 warnx("mnt unsucc"); 2314 syslog(LOG_ERR, "can't export %s %s", 2315 dirp, errmsg); 2316 ret = 1; 2317 goto error_exit; 2318 } 2319 savedc = *cp; 2320 *cp = '\0'; 2321 /* 2322 * Check that we're still on the same 2323 * filesystem. 2324 */ 2325 if (statfs(dirp, &fsb1) != 0 || 2326 bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2327 sizeof (fsb1.f_fsid)) != 0) { 2328 *cp = savedc; 2329 syslog(LOG_ERR, 2330 "can't export %s %s", dirp, 2331 errmsg); 2332 ret = 1; 2333 goto error_exit; 2334 } 2335 } 2336 } 2337 2338 /* 2339 * For the experimental server: 2340 * If this is the public directory, get the file handle 2341 * and load it into the kernel via the nfssvc() syscall. 2342 */ 2343 if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2344 fhandle_t fh; 2345 char *public_name; 2346 2347 if (eap->ex_indexfile != NULL) 2348 public_name = eap->ex_indexfile; 2349 else 2350 public_name = dirp; 2351 if (getfh(public_name, &fh) < 0) 2352 syslog(LOG_ERR, 2353 "Can't get public fh for %s", public_name); 2354 else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2355 syslog(LOG_ERR, 2356 "Can't set public fh for %s", public_name); 2357 else 2358 has_publicfh = 1; 2359 } 2360skip: 2361 if (ai != NULL) 2362 ai = ai->ai_next; 2363 if (ai == NULL) 2364 done = TRUE; 2365 } 2366 if (cp) 2367 *cp = savedc; 2368error_exit: 2369 /* free strings allocated by strdup() in getmntopts.c */ 2370 if (iov != NULL) { 2371 free(iov[0].iov_base); /* fstype */ 2372 free(iov[2].iov_base); /* fspath */ 2373 free(iov[4].iov_base); /* from */ 2374 free(iov[6].iov_base); /* update */ 2375 free(iov[8].iov_base); /* export */ 2376 free(iov[10].iov_base); /* errmsg */ 2377 2378 /* free iov, allocated by realloc() */ 2379 free(iov); 2380 } 2381 return (ret); 2382} 2383 2384/* 2385 * Translate a net address. 2386 * 2387 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 2388 */ 2389int 2390get_net(char *cp, struct netmsk *net, int maskflg) 2391{ 2392 struct netent *np = NULL; 2393 char *name, *p, *prefp; 2394 struct sockaddr_in sin; 2395 struct sockaddr *sa = NULL; 2396 struct addrinfo hints, *ai = NULL; 2397 char netname[NI_MAXHOST]; 2398 long preflen; 2399 2400 p = prefp = NULL; 2401 if ((opt_flags & OP_MASKLEN) && !maskflg) { 2402 p = strchr(cp, '/'); 2403 *p = '\0'; 2404 prefp = p + 1; 2405 } 2406 2407 /* 2408 * Check for a numeric address first. We wish to avoid 2409 * possible DNS lookups in getnetbyname(). 2410 */ 2411 if (isxdigit(*cp) || *cp == ':') { 2412 memset(&hints, 0, sizeof hints); 2413 /* Ensure the mask and the network have the same family. */ 2414 if (maskflg && (opt_flags & OP_NET)) 2415 hints.ai_family = net->nt_net.ss_family; 2416 else if (!maskflg && (opt_flags & OP_HAVEMASK)) 2417 hints.ai_family = net->nt_mask.ss_family; 2418 else 2419 hints.ai_family = AF_UNSPEC; 2420 hints.ai_flags = AI_NUMERICHOST; 2421 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2422 sa = ai->ai_addr; 2423 if (sa != NULL && ai->ai_family == AF_INET) { 2424 /* 2425 * The address in `cp' is really a network address, so 2426 * use inet_network() to re-interpret this correctly. 2427 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 2428 */ 2429 bzero(&sin, sizeof sin); 2430 sin.sin_family = AF_INET; 2431 sin.sin_len = sizeof sin; 2432 sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 2433 if (debug) 2434 fprintf(stderr, "get_net: v4 addr %s\n", 2435 inet_ntoa(sin.sin_addr)); 2436 sa = (struct sockaddr *)&sin; 2437 } 2438 } 2439 if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2440 bzero(&sin, sizeof sin); 2441 sin.sin_family = AF_INET; 2442 sin.sin_len = sizeof sin; 2443 sin.sin_addr = inet_makeaddr(np->n_net, 0); 2444 sa = (struct sockaddr *)&sin; 2445 } 2446 if (sa == NULL) 2447 goto fail; 2448 2449 if (maskflg) { 2450 /* The specified sockaddr is a mask. */ 2451 if (checkmask(sa) != 0) 2452 goto fail; 2453 bcopy(sa, &net->nt_mask, sa->sa_len); 2454 opt_flags |= OP_HAVEMASK; 2455 } else { 2456 /* The specified sockaddr is a network address. */ 2457 bcopy(sa, &net->nt_net, sa->sa_len); 2458 2459 /* Get a network name for the export list. */ 2460 if (np) { 2461 name = np->n_name; 2462 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2463 NULL, 0, NI_NUMERICHOST) == 0) { 2464 name = netname; 2465 } else { 2466 goto fail; 2467 } 2468 if ((net->nt_name = strdup(name)) == NULL) 2469 out_of_mem(); 2470 2471 /* 2472 * Extract a mask from either a "/<masklen>" suffix, or 2473 * from the class of an IPv4 address. 2474 */ 2475 if (opt_flags & OP_MASKLEN) { 2476 preflen = strtol(prefp, NULL, 10); 2477 if (preflen < 0L || preflen == LONG_MAX) 2478 goto fail; 2479 bcopy(sa, &net->nt_mask, sa->sa_len); 2480 if (makemask(&net->nt_mask, (int)preflen) != 0) 2481 goto fail; 2482 opt_flags |= OP_HAVEMASK; 2483 *p = '/'; 2484 } else if (sa->sa_family == AF_INET && 2485 (opt_flags & OP_MASK) == 0) { 2486 in_addr_t addr; 2487 2488 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 2489 if (IN_CLASSA(addr)) 2490 preflen = 8; 2491 else if (IN_CLASSB(addr)) 2492 preflen = 16; 2493 else if (IN_CLASSC(addr)) 2494 preflen = 24; 2495 else if (IN_CLASSD(addr)) 2496 preflen = 28; 2497 else 2498 preflen = 32; /* XXX */ 2499 2500 bcopy(sa, &net->nt_mask, sa->sa_len); 2501 makemask(&net->nt_mask, (int)preflen); 2502 opt_flags |= OP_HAVEMASK; 2503 } 2504 } 2505 2506 if (ai) 2507 freeaddrinfo(ai); 2508 return 0; 2509 2510fail: 2511 if (ai) 2512 freeaddrinfo(ai); 2513 return 1; 2514} 2515 2516/* 2517 * Parse out the next white space separated field 2518 */ 2519void 2520nextfield(char **cp, char **endcp) 2521{ 2522 char *p; 2523 2524 p = *cp; 2525 while (*p == ' ' || *p == '\t') 2526 p++; 2527 if (*p == '\n' || *p == '\0') 2528 *cp = *endcp = p; 2529 else { 2530 *cp = p++; 2531 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2532 p++; 2533 *endcp = p; 2534 } 2535} 2536 2537/* 2538 * Get an exports file line. Skip over blank lines and handle line 2539 * continuations. 2540 */ 2541int 2542get_line(void) 2543{ 2544 char *p, *cp; 2545 size_t len; 2546 int totlen, cont_line; 2547 2548 /* 2549 * Loop around ignoring blank lines and getting all continuation lines. 2550 */ 2551 p = line; 2552 totlen = 0; 2553 do { 2554 if ((p = fgetln(exp_file, &len)) == NULL) 2555 return (0); 2556 cp = p + len - 1; 2557 cont_line = 0; 2558 while (cp >= p && 2559 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 2560 if (*cp == '\\') 2561 cont_line = 1; 2562 cp--; 2563 len--; 2564 } 2565 if (cont_line) { 2566 *++cp = ' '; 2567 len++; 2568 } 2569 if (linesize < len + totlen + 1) { 2570 linesize = len + totlen + 1; 2571 line = realloc(line, linesize); 2572 if (line == NULL) 2573 out_of_mem(); 2574 } 2575 memcpy(line + totlen, p, len); 2576 totlen += len; 2577 line[totlen] = '\0'; 2578 } while (totlen == 0 || cont_line); 2579 return (1); 2580} 2581 2582/* 2583 * Parse a description of a credential. 2584 */ 2585void 2586parsecred(char *namelist, struct xucred *cr) 2587{ 2588 char *name; 2589 int cnt; 2590 char *names; 2591 struct passwd *pw; 2592 struct group *gr; 2593 gid_t groups[XU_NGROUPS + 1]; 2594 int ngroups; 2595 2596 cr->cr_version = XUCRED_VERSION; 2597 /* 2598 * Set up the unprivileged user. 2599 */ 2600 cr->cr_uid = -2; 2601 cr->cr_groups[0] = -2; 2602 cr->cr_ngroups = 1; 2603 /* 2604 * Get the user's password table entry. 2605 */ 2606 names = strsep(&namelist, " \t\n"); 2607 name = strsep(&names, ":"); 2608 if (isdigit(*name) || *name == '-') 2609 pw = getpwuid(atoi(name)); 2610 else 2611 pw = getpwnam(name); 2612 /* 2613 * Credentials specified as those of a user. 2614 */ 2615 if (names == NULL) { 2616 if (pw == NULL) { 2617 syslog(LOG_ERR, "unknown user: %s", name); 2618 return; 2619 } 2620 cr->cr_uid = pw->pw_uid; 2621 ngroups = XU_NGROUPS + 1; 2622 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2623 syslog(LOG_ERR, "too many groups"); 2624 /* 2625 * Compress out duplicate. 2626 */ 2627 cr->cr_ngroups = ngroups - 1; 2628 cr->cr_groups[0] = groups[0]; 2629 for (cnt = 2; cnt < ngroups; cnt++) 2630 cr->cr_groups[cnt - 1] = groups[cnt]; 2631 return; 2632 } 2633 /* 2634 * Explicit credential specified as a colon separated list: 2635 * uid:gid:gid:... 2636 */ 2637 if (pw != NULL) 2638 cr->cr_uid = pw->pw_uid; 2639 else if (isdigit(*name) || *name == '-') 2640 cr->cr_uid = atoi(name); 2641 else { 2642 syslog(LOG_ERR, "unknown user: %s", name); 2643 return; 2644 } 2645 cr->cr_ngroups = 0; 2646 while (names != NULL && *names != '\0' && cr->cr_ngroups < XU_NGROUPS) { 2647 name = strsep(&names, ":"); 2648 if (isdigit(*name) || *name == '-') { 2649 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2650 } else { 2651 if ((gr = getgrnam(name)) == NULL) { 2652 syslog(LOG_ERR, "unknown group: %s", name); 2653 continue; 2654 } 2655 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2656 } 2657 } 2658 if (names != NULL && *names != '\0' && cr->cr_ngroups == XU_NGROUPS) 2659 syslog(LOG_ERR, "too many groups"); 2660} 2661 2662#define STRSIZ (MNTNAMLEN+MNTPATHLEN+50) 2663/* 2664 * Routines that maintain the remote mounttab 2665 */ 2666void 2667get_mountlist(void) 2668{ 2669 struct mountlist *mlp, **mlpp; 2670 char *host, *dirp, *cp; 2671 char str[STRSIZ]; 2672 FILE *mlfile; 2673 2674 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2675 if (errno == ENOENT) 2676 return; 2677 else { 2678 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 2679 return; 2680 } 2681 } 2682 mlpp = &mlhead; 2683 while (fgets(str, STRSIZ, mlfile) != NULL) { 2684 cp = str; 2685 host = strsep(&cp, " \t\n"); 2686 dirp = strsep(&cp, " \t\n"); 2687 if (host == NULL || dirp == NULL) 2688 continue; 2689 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2690 if (mlp == (struct mountlist *)NULL) 2691 out_of_mem(); 2692 strncpy(mlp->ml_host, host, MNTNAMLEN); 2693 mlp->ml_host[MNTNAMLEN] = '\0'; 2694 strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2695 mlp->ml_dirp[MNTPATHLEN] = '\0'; 2696 mlp->ml_next = (struct mountlist *)NULL; 2697 *mlpp = mlp; 2698 mlpp = &mlp->ml_next; 2699 } 2700 fclose(mlfile); 2701} 2702 2703void 2704del_mlist(char *hostp, char *dirp) 2705{ 2706 struct mountlist *mlp, **mlpp; 2707 struct mountlist *mlp2; 2708 FILE *mlfile; 2709 int fnd = 0; 2710 2711 mlpp = &mlhead; 2712 mlp = mlhead; 2713 while (mlp) { 2714 if (!strcmp(mlp->ml_host, hostp) && 2715 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2716 fnd = 1; 2717 mlp2 = mlp; 2718 *mlpp = mlp = mlp->ml_next; 2719 free((caddr_t)mlp2); 2720 } else { 2721 mlpp = &mlp->ml_next; 2722 mlp = mlp->ml_next; 2723 } 2724 } 2725 if (fnd) { 2726 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2727 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2728 return; 2729 } 2730 mlp = mlhead; 2731 while (mlp) { 2732 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2733 mlp = mlp->ml_next; 2734 } 2735 fclose(mlfile); 2736 } 2737} 2738 2739void 2740add_mlist(char *hostp, char *dirp) 2741{ 2742 struct mountlist *mlp, **mlpp; 2743 FILE *mlfile; 2744 2745 mlpp = &mlhead; 2746 mlp = mlhead; 2747 while (mlp) { 2748 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2749 return; 2750 mlpp = &mlp->ml_next; 2751 mlp = mlp->ml_next; 2752 } 2753 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2754 if (mlp == (struct mountlist *)NULL) 2755 out_of_mem(); 2756 strncpy(mlp->ml_host, hostp, MNTNAMLEN); 2757 mlp->ml_host[MNTNAMLEN] = '\0'; 2758 strncpy(mlp->ml_dirp, dirp, MNTPATHLEN); 2759 mlp->ml_dirp[MNTPATHLEN] = '\0'; 2760 mlp->ml_next = (struct mountlist *)NULL; 2761 *mlpp = mlp; 2762 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2763 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2764 return; 2765 } 2766 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2767 fclose(mlfile); 2768} 2769 2770/* 2771 * Free up a group list. 2772 */ 2773void 2774free_grp(struct grouplist *grp) 2775{ 2776 if (grp->gr_type == GT_HOST) { 2777 if (grp->gr_ptr.gt_addrinfo != NULL) 2778 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2779 } else if (grp->gr_type == GT_NET) { 2780 if (grp->gr_ptr.gt_net.nt_name) 2781 free(grp->gr_ptr.gt_net.nt_name); 2782 } 2783 free((caddr_t)grp); 2784} 2785 2786#ifdef DEBUG 2787void 2788SYSLOG(int pri, const char *fmt, ...) 2789{ 2790 va_list ap; 2791 2792 va_start(ap, fmt); 2793 vfprintf(stderr, fmt, ap); 2794 va_end(ap); 2795} 2796#endif /* DEBUG */ 2797 2798/* 2799 * Check options for consistency. 2800 */ 2801int 2802check_options(struct dirlist *dp) 2803{ 2804 2805 if (v4root_phase == 0 && dp == NULL) 2806 return (1); 2807 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2808 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2809 return (1); 2810 } 2811 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2812 syslog(LOG_ERR, "-mask requires -network"); 2813 return (1); 2814 } 2815 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 2816 syslog(LOG_ERR, "-network requires mask specification"); 2817 return (1); 2818 } 2819 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 2820 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 2821 return (1); 2822 } 2823 if (v4root_phase > 0 && 2824 (opt_flags & 2825 ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 2826 syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 2827 return (1); 2828 } 2829 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2830 syslog(LOG_ERR, "-alldirs has multiple directories"); 2831 return (1); 2832 } 2833 return (0); 2834} 2835 2836/* 2837 * Check an absolute directory path for any symbolic links. Return true 2838 */ 2839int 2840check_dirpath(char *dirp) 2841{ 2842 char *cp; 2843 int ret = 1; 2844 struct stat sb; 2845 2846 cp = dirp + 1; 2847 while (*cp && ret) { 2848 if (*cp == '/') { 2849 *cp = '\0'; 2850 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2851 ret = 0; 2852 *cp = '/'; 2853 } 2854 cp++; 2855 } 2856 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2857 ret = 0; 2858 return (ret); 2859} 2860 2861/* 2862 * Make a netmask according to the specified prefix length. The ss_family 2863 * and other non-address fields must be initialised before calling this. 2864 */ 2865int 2866makemask(struct sockaddr_storage *ssp, int bitlen) 2867{ 2868 u_char *p; 2869 int bits, i, len; 2870 2871 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 2872 return (-1); 2873 if (bitlen > len * CHAR_BIT) 2874 return (-1); 2875 2876 for (i = 0; i < len; i++) { 2877 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2878 *p++ = (1 << bits) - 1; 2879 bitlen -= bits; 2880 } 2881 return 0; 2882} 2883 2884/* 2885 * Check that the sockaddr is a valid netmask. Returns 0 if the mask 2886 * is acceptable (i.e. of the form 1...10....0). 2887 */ 2888int 2889checkmask(struct sockaddr *sa) 2890{ 2891 u_char *mask; 2892 int i, len; 2893 2894 if ((mask = sa_rawaddr(sa, &len)) == NULL) 2895 return (-1); 2896 2897 for (i = 0; i < len; i++) 2898 if (mask[i] != 0xff) 2899 break; 2900 if (i < len) { 2901 if (~mask[i] & (u_char)(~mask[i] + 1)) 2902 return (-1); 2903 i++; 2904 } 2905 for (; i < len; i++) 2906 if (mask[i] != 0) 2907 return (-1); 2908 return (0); 2909} 2910 2911/* 2912 * Compare two sockaddrs according to a specified mask. Return zero if 2913 * `sa1' matches `sa2' when filtered by the netmask in `samask'. 2914 * If samask is NULL, perform a full comparision. 2915 */ 2916int 2917sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 2918{ 2919 unsigned char *p1, *p2, *mask; 2920 int len, i; 2921 2922 if (sa1->sa_family != sa2->sa_family || 2923 (p1 = sa_rawaddr(sa1, &len)) == NULL || 2924 (p2 = sa_rawaddr(sa2, NULL)) == NULL) 2925 return (1); 2926 2927 switch (sa1->sa_family) { 2928 case AF_INET6: 2929 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 2930 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 2931 return (1); 2932 break; 2933 } 2934 2935 /* Simple binary comparison if no mask specified. */ 2936 if (samask == NULL) 2937 return (memcmp(p1, p2, len)); 2938 2939 /* Set up the mask, and do a mask-based comparison. */ 2940 if (sa1->sa_family != samask->sa_family || 2941 (mask = sa_rawaddr(samask, NULL)) == NULL) 2942 return (1); 2943 2944 for (i = 0; i < len; i++) 2945 if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 2946 return (1); 2947 return (0); 2948} 2949 2950/* 2951 * Return a pointer to the part of the sockaddr that contains the 2952 * raw address, and set *nbytes to its length in bytes. Returns 2953 * NULL if the address family is unknown. 2954 */ 2955void * 2956sa_rawaddr(struct sockaddr *sa, int *nbytes) { 2957 void *p; 2958 int len; 2959 2960 switch (sa->sa_family) { 2961 case AF_INET: 2962 len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 2963 p = &((struct sockaddr_in *)sa)->sin_addr; 2964 break; 2965 case AF_INET6: 2966 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 2967 p = &((struct sockaddr_in6 *)sa)->sin6_addr; 2968 break; 2969 default: 2970 p = NULL; 2971 len = 0; 2972 } 2973 2974 if (nbytes != NULL) 2975 *nbytes = len; 2976 return (p); 2977} 2978 2979void 2980huphandler(int sig __unused) 2981{ 2982 got_sighup = 1; 2983} 2984 2985void terminate(int sig __unused) 2986{ 2987 pidfile_remove(pfh); 2988 rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 2989 rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 2990 exit (0); 2991} 2992 2993