mountd.c revision 220980
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Herb Hasler and Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static const char copyright[] = 35"@(#) Copyright (c) 1989, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /*not lint*/ 38 39#if 0 40#ifndef lint 41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42#endif /*not lint*/ 43#endif 44 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 220980 2011-04-24 00:06:56Z rmacklem $"); 47 48#include <sys/param.h> 49#include <sys/fcntl.h> 50#include <sys/linker.h> 51#include <sys/module.h> 52#include <sys/mount.h> 53#include <sys/stat.h> 54#include <sys/sysctl.h> 55#include <sys/syslog.h> 56 57#include <rpc/rpc.h> 58#include <rpc/rpc_com.h> 59#include <rpc/pmap_clnt.h> 60#include <rpc/pmap_prot.h> 61#include <rpcsvc/mount.h> 62#include <nfs/nfsproto.h> 63#include <nfs/nfssvc.h> 64#include <nfsserver/nfs.h> 65 66#include <fs/nfs/nfsport.h> 67 68#include <arpa/inet.h> 69 70#include <ctype.h> 71#include <err.h> 72#include <errno.h> 73#include <grp.h> 74#include <libutil.h> 75#include <limits.h> 76#include <netdb.h> 77#include <pwd.h> 78#include <signal.h> 79#include <stdio.h> 80#include <stdlib.h> 81#include <string.h> 82#include <unistd.h> 83#include "pathnames.h" 84#include "mntopts.h" 85 86#ifdef DEBUG 87#include <stdarg.h> 88#endif 89 90/* 91 * Structures for keeping the mount list and export list 92 */ 93struct mountlist { 94 struct mountlist *ml_next; 95 char ml_host[MNTNAMLEN+1]; 96 char ml_dirp[MNTPATHLEN+1]; 97}; 98 99struct dirlist { 100 struct dirlist *dp_left; 101 struct dirlist *dp_right; 102 int dp_flag; 103 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 104 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 105}; 106/* dp_flag bits */ 107#define DP_DEFSET 0x1 108#define DP_HOSTSET 0x2 109 110struct exportlist { 111 struct exportlist *ex_next; 112 struct dirlist *ex_dirl; 113 struct dirlist *ex_defdir; 114 int ex_flag; 115 fsid_t ex_fs; 116 char *ex_fsdir; 117 char *ex_indexfile; 118 int ex_numsecflavors; 119 int ex_secflavors[MAXSECFLAVORS]; 120}; 121/* ex_flag bits */ 122#define EX_LINKED 0x1 123 124struct netmsk { 125 struct sockaddr_storage nt_net; 126 struct sockaddr_storage nt_mask; 127 char *nt_name; 128}; 129 130union grouptypes { 131 struct addrinfo *gt_addrinfo; 132 struct netmsk gt_net; 133}; 134 135struct grouplist { 136 int gr_type; 137 union grouptypes gr_ptr; 138 struct grouplist *gr_next; 139}; 140/* Group types */ 141#define GT_NULL 0x0 142#define GT_HOST 0x1 143#define GT_NET 0x2 144#define GT_DEFAULT 0x3 145#define GT_IGNORE 0x5 146 147struct hostlist { 148 int ht_flag; /* Uses DP_xx bits */ 149 struct grouplist *ht_grp; 150 struct hostlist *ht_next; 151}; 152 153struct fhreturn { 154 int fhr_flag; 155 int fhr_vers; 156 nfsfh_t fhr_fh; 157 int fhr_numsecflavors; 158 int *fhr_secflavors; 159}; 160 161/* Global defs */ 162char *add_expdir(struct dirlist **, char *, int); 163void add_dlist(struct dirlist **, struct dirlist *, 164 struct grouplist *, int); 165void add_mlist(char *, char *); 166int check_dirpath(char *); 167int check_options(struct dirlist *); 168int checkmask(struct sockaddr *sa); 169int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 170void create_service(struct netconfig *nconf); 171void del_mlist(char *hostp, char *dirp); 172struct dirlist *dirp_search(struct dirlist *, char *); 173int do_mount(struct exportlist *, struct grouplist *, int, 174 struct xucred *, char *, int, struct statfs *); 175int do_opt(char **, char **, struct exportlist *, struct grouplist *, 176 int *, int *, struct xucred *); 177struct exportlist *ex_search(fsid_t *); 178struct exportlist *get_exp(void); 179void free_dir(struct dirlist *); 180void free_exp(struct exportlist *); 181void free_grp(struct grouplist *); 182void free_host(struct hostlist *); 183void get_exportlist(void); 184int get_host(char *, struct grouplist *, struct grouplist *); 185struct hostlist *get_ht(void); 186int get_line(void); 187void get_mountlist(void); 188int get_net(char *, struct netmsk *, int); 189void getexp_err(struct exportlist *, struct grouplist *); 190struct grouplist *get_grp(void); 191void hang_dirp(struct dirlist *, struct grouplist *, 192 struct exportlist *, int); 193void huphandler(int sig); 194int makemask(struct sockaddr_storage *ssp, int bitlen); 195void mntsrv(struct svc_req *, SVCXPRT *); 196void nextfield(char **, char **); 197void out_of_mem(void); 198void parsecred(char *, struct xucred *); 199int parsesec(char *, struct exportlist *); 200int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 201void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 202int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 203 struct sockaddr *samask); 204int scan_tree(struct dirlist *, struct sockaddr *); 205static void usage(void); 206int xdr_dir(XDR *, char *); 207int xdr_explist(XDR *, caddr_t); 208int xdr_explist_brief(XDR *, caddr_t); 209int xdr_explist_common(XDR *, caddr_t, int); 210int xdr_fhs(XDR *, caddr_t); 211int xdr_mlist(XDR *, caddr_t); 212void terminate(int); 213 214struct exportlist *exphead; 215struct mountlist *mlhead; 216struct grouplist *grphead; 217char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 218char **exnames; 219char **hosts = NULL; 220struct xucred def_anon = { 221 XUCRED_VERSION, 222 (uid_t)-2, 223 1, 224 { (gid_t)-2 }, 225 NULL 226}; 227int force_v2 = 0; 228int resvport_only = 1; 229int nhosts = 0; 230int dir_only = 1; 231int dolog = 0; 232int got_sighup = 0; 233int xcreated = 0; 234 235char *svcport_str = NULL; 236 237int opt_flags; 238static int have_v6 = 1; 239 240int v4root_phase = 0; 241char v4root_dirpath[PATH_MAX + 1]; 242int run_v4server = 1; 243int has_publicfh = 0; 244 245struct pidfh *pfh = NULL; 246/* Bits for opt_flags above */ 247#define OP_MAPROOT 0x01 248#define OP_MAPALL 0x02 249/* 0x4 free */ 250#define OP_MASK 0x08 251#define OP_NET 0x10 252#define OP_ALLDIRS 0x40 253#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 254#define OP_QUIET 0x100 255#define OP_MASKLEN 0x200 256#define OP_SEC 0x400 257 258#ifdef DEBUG 259int debug = 1; 260void SYSLOG(int, const char *, ...) __printflike(2, 3); 261#define syslog SYSLOG 262#else 263int debug = 0; 264#endif 265 266/* 267 * Mountd server for NFS mount protocol as described in: 268 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 269 * The optional arguments are the exports file name 270 * default: _PATH_EXPORTS 271 * and "-n" to allow nonroot mount. 272 */ 273int 274main(int argc, char **argv) 275{ 276 fd_set readfds; 277 struct netconfig *nconf; 278 char *endptr, **hosts_bak; 279 void *nc_handle; 280 pid_t otherpid; 281 in_port_t svcport; 282 int c, k, s; 283 int maxrec = RPC_MAXDATASIZE; 284 285 /* Check that another mountd isn't already running. */ 286 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 287 if (pfh == NULL) { 288 if (errno == EEXIST) 289 errx(1, "mountd already running, pid: %d.", otherpid); 290 warn("cannot open or create pidfile"); 291 } 292 293 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 294 if (s < 0) 295 have_v6 = 0; 296 else 297 close(s); 298 299 while ((c = getopt(argc, argv, "2deh:lnop:r")) != -1) 300 switch (c) { 301 case '2': 302 force_v2 = 1; 303 break; 304 case 'e': 305 /* now a no-op, since this is the default */ 306 break; 307 case 'n': 308 resvport_only = 0; 309 break; 310 case 'r': 311 dir_only = 0; 312 break; 313 case 'd': 314 debug = debug ? 0 : 1; 315 break; 316 case 'l': 317 dolog = 1; 318 break; 319 case 'o': 320 run_v4server = 0; 321 break; 322 case 'p': 323 endptr = NULL; 324 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 325 if (endptr == NULL || *endptr != '\0' || 326 svcport == 0 || svcport >= IPPORT_MAX) 327 usage(); 328 svcport_str = strdup(optarg); 329 break; 330 case 'h': 331 ++nhosts; 332 hosts_bak = hosts; 333 hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 334 if (hosts_bak == NULL) { 335 if (hosts != NULL) { 336 for (k = 0; k < nhosts; k++) 337 free(hosts[k]); 338 free(hosts); 339 out_of_mem(); 340 } 341 } 342 hosts = hosts_bak; 343 hosts[nhosts - 1] = strdup(optarg); 344 if (hosts[nhosts - 1] == NULL) { 345 for (k = 0; k < (nhosts - 1); k++) 346 free(hosts[k]); 347 free(hosts); 348 out_of_mem(); 349 } 350 break; 351 default: 352 usage(); 353 }; 354 355 /* 356 * Unless the "-o" option was specified, try and run "nfsd". 357 * If "-o" was specified, try and run "nfsserver". 358 */ 359 if (run_v4server > 0) { 360 if (modfind("nfsd") < 0) { 361 /* Not present in kernel, try loading it */ 362 if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 363 errx(1, "NFS server is not available"); 364 } 365 } else if (modfind("nfsserver") < 0) { 366 /* Not present in kernel, try loading it */ 367 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 368 errx(1, "NFS server is not available"); 369 } 370 371 argc -= optind; 372 argv += optind; 373 grphead = (struct grouplist *)NULL; 374 exphead = (struct exportlist *)NULL; 375 mlhead = (struct mountlist *)NULL; 376 if (argc > 0) 377 exnames = argv; 378 else 379 exnames = exnames_default; 380 openlog("mountd", LOG_PID, LOG_DAEMON); 381 if (debug) 382 warnx("getting export list"); 383 get_exportlist(); 384 if (debug) 385 warnx("getting mount list"); 386 get_mountlist(); 387 if (debug) 388 warnx("here we go"); 389 if (debug == 0) { 390 daemon(0, 0); 391 signal(SIGINT, SIG_IGN); 392 signal(SIGQUIT, SIG_IGN); 393 } 394 signal(SIGHUP, huphandler); 395 signal(SIGTERM, terminate); 396 signal(SIGPIPE, SIG_IGN); 397 398 pidfile_write(pfh); 399 400 rpcb_unset(MOUNTPROG, MOUNTVERS, NULL); 401 rpcb_unset(MOUNTPROG, MOUNTVERS3, NULL); 402 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 403 404 if (!resvport_only) { 405 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 406 &resvport_only, sizeof(resvport_only)) != 0 && 407 errno != ENOENT) { 408 syslog(LOG_ERR, "sysctl: %m"); 409 exit(1); 410 } 411 } 412 413 /* 414 * If no hosts were specified, add a wildcard entry to bind to 415 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 416 * list. 417 */ 418 if (nhosts == 0) { 419 hosts = malloc(sizeof(char**)); 420 if (hosts == NULL) 421 out_of_mem(); 422 hosts[0] = "*"; 423 nhosts = 1; 424 } else { 425 hosts_bak = hosts; 426 if (have_v6) { 427 hosts_bak = realloc(hosts, (nhosts + 2) * 428 sizeof(char *)); 429 if (hosts_bak == NULL) { 430 for (k = 0; k < nhosts; k++) 431 free(hosts[k]); 432 free(hosts); 433 out_of_mem(); 434 } else 435 hosts = hosts_bak; 436 nhosts += 2; 437 hosts[nhosts - 2] = "::1"; 438 } else { 439 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 440 if (hosts_bak == NULL) { 441 for (k = 0; k < nhosts; k++) 442 free(hosts[k]); 443 free(hosts); 444 out_of_mem(); 445 } else { 446 nhosts += 1; 447 hosts = hosts_bak; 448 } 449 } 450 451 hosts[nhosts - 1] = "127.0.0.1"; 452 } 453 454 nc_handle = setnetconfig(); 455 while ((nconf = getnetconfig(nc_handle))) { 456 if (nconf->nc_flag & NC_VISIBLE) { 457 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 458 "inet6") == 0) { 459 /* DO NOTHING */ 460 } else 461 create_service(nconf); 462 } 463 } 464 endnetconfig(nc_handle); 465 466 if (xcreated == 0) { 467 syslog(LOG_ERR, "could not create any services"); 468 exit(1); 469 } 470 471 /* Expand svc_run() here so that we can call get_exportlist(). */ 472 for (;;) { 473 if (got_sighup) { 474 get_exportlist(); 475 got_sighup = 0; 476 } 477 readfds = svc_fdset; 478 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 479 case -1: 480 if (errno == EINTR) 481 continue; 482 syslog(LOG_ERR, "mountd died: select: %m"); 483 exit(1); 484 case 0: 485 continue; 486 default: 487 svc_getreqset(&readfds); 488 } 489 } 490} 491 492/* 493 * This routine creates and binds sockets on the appropriate 494 * addresses. It gets called one time for each transport and 495 * registrates the service with rpcbind on that trasport. 496 */ 497void 498create_service(struct netconfig *nconf) 499{ 500 struct addrinfo hints, *res = NULL; 501 struct sockaddr_in *sin; 502 struct sockaddr_in6 *sin6; 503 struct __rpc_sockinfo si; 504 struct netbuf servaddr; 505 SVCXPRT *transp = NULL; 506 int aicode; 507 int fd; 508 int nhostsbak; 509 int one = 1; 510 int r; 511 int registered = 0; 512 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 513 514 if ((nconf->nc_semantics != NC_TPI_CLTS) && 515 (nconf->nc_semantics != NC_TPI_COTS) && 516 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 517 return; /* not my type */ 518 519 /* 520 * XXX - using RPC library internal functions. 521 */ 522 if (!__rpc_nconf2sockinfo(nconf, &si)) { 523 syslog(LOG_ERR, "cannot get information for %s", 524 nconf->nc_netid); 525 return; 526 } 527 528 /* Get mountd's address on this transport */ 529 memset(&hints, 0, sizeof hints); 530 hints.ai_flags = AI_PASSIVE; 531 hints.ai_family = si.si_af; 532 hints.ai_socktype = si.si_socktype; 533 hints.ai_protocol = si.si_proto; 534 535 /* 536 * Bind to specific IPs if asked to 537 */ 538 nhostsbak = nhosts; 539 while (nhostsbak > 0) { 540 --nhostsbak; 541 /* 542 * XXX - using RPC library internal functions. 543 */ 544 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 545 int non_fatal = 0; 546 if (errno == EPROTONOSUPPORT && 547 nconf->nc_semantics != NC_TPI_CLTS) 548 non_fatal = 1; 549 550 syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 551 "cannot create socket for %s", nconf->nc_netid); 552 return; 553 } 554 555 switch (hints.ai_family) { 556 case AF_INET: 557 if (inet_pton(AF_INET, hosts[nhostsbak], 558 host_addr) == 1) { 559 hints.ai_flags &= AI_NUMERICHOST; 560 } else { 561 /* 562 * Skip if we have an AF_INET6 address. 563 */ 564 if (inet_pton(AF_INET6, hosts[nhostsbak], 565 host_addr) == 1) { 566 close(fd); 567 continue; 568 } 569 } 570 break; 571 case AF_INET6: 572 if (inet_pton(AF_INET6, hosts[nhostsbak], 573 host_addr) == 1) { 574 hints.ai_flags &= AI_NUMERICHOST; 575 } else { 576 /* 577 * Skip if we have an AF_INET address. 578 */ 579 if (inet_pton(AF_INET, hosts[nhostsbak], 580 host_addr) == 1) { 581 close(fd); 582 continue; 583 } 584 } 585 586 /* 587 * We're doing host-based access checks here, so don't 588 * allow v4-in-v6 to confuse things. The kernel will 589 * disable it by default on NFS sockets too. 590 */ 591 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 592 sizeof one) < 0) { 593 syslog(LOG_ERR, 594 "can't disable v4-in-v6 on IPv6 socket"); 595 exit(1); 596 } 597 break; 598 default: 599 break; 600 } 601 602 /* 603 * If no hosts were specified, just bind to INADDR_ANY 604 */ 605 if (strcmp("*", hosts[nhostsbak]) == 0) { 606 if (svcport_str == NULL) { 607 res = malloc(sizeof(struct addrinfo)); 608 if (res == NULL) 609 out_of_mem(); 610 res->ai_flags = hints.ai_flags; 611 res->ai_family = hints.ai_family; 612 res->ai_protocol = hints.ai_protocol; 613 switch (res->ai_family) { 614 case AF_INET: 615 sin = malloc(sizeof(struct sockaddr_in)); 616 if (sin == NULL) 617 out_of_mem(); 618 sin->sin_family = AF_INET; 619 sin->sin_port = htons(0); 620 sin->sin_addr.s_addr = htonl(INADDR_ANY); 621 res->ai_addr = (struct sockaddr*) sin; 622 res->ai_addrlen = (socklen_t) 623 sizeof(res->ai_addr); 624 break; 625 case AF_INET6: 626 sin6 = malloc(sizeof(struct sockaddr_in6)); 627 if (sin6 == NULL) 628 out_of_mem(); 629 sin6->sin6_family = AF_INET6; 630 sin6->sin6_port = htons(0); 631 sin6->sin6_addr = in6addr_any; 632 res->ai_addr = (struct sockaddr*) sin6; 633 res->ai_addrlen = (socklen_t) 634 sizeof(res->ai_addr); 635 break; 636 default: 637 break; 638 } 639 } else { 640 if ((aicode = getaddrinfo(NULL, svcport_str, 641 &hints, &res)) != 0) { 642 syslog(LOG_ERR, 643 "cannot get local address for %s: %s", 644 nconf->nc_netid, 645 gai_strerror(aicode)); 646 continue; 647 } 648 } 649 } else { 650 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 651 &hints, &res)) != 0) { 652 syslog(LOG_ERR, 653 "cannot get local address for %s: %s", 654 nconf->nc_netid, gai_strerror(aicode)); 655 continue; 656 } 657 } 658 659 r = bindresvport_sa(fd, res->ai_addr); 660 if (r != 0) { 661 syslog(LOG_ERR, "bindresvport_sa: %m"); 662 exit(1); 663 } 664 665 if (nconf->nc_semantics != NC_TPI_CLTS) 666 listen(fd, SOMAXCONN); 667 668 if (nconf->nc_semantics == NC_TPI_CLTS ) 669 transp = svc_dg_create(fd, 0, 0); 670 else 671 transp = svc_vc_create(fd, RPC_MAXDATASIZE, 672 RPC_MAXDATASIZE); 673 674 if (transp != (SVCXPRT *) NULL) { 675 if (!svc_reg(transp, MOUNTPROG, MOUNTVERS, mntsrv, 676 NULL)) 677 syslog(LOG_ERR, 678 "can't register %s MOUNTVERS service", 679 nconf->nc_netid); 680 if (!force_v2) { 681 if (!svc_reg(transp, MOUNTPROG, MOUNTVERS3, 682 mntsrv, NULL)) 683 syslog(LOG_ERR, 684 "can't register %s MOUNTVERS3 service", 685 nconf->nc_netid); 686 } 687 } else 688 syslog(LOG_WARNING, "can't create %s services", 689 nconf->nc_netid); 690 691 if (registered == 0) { 692 registered = 1; 693 memset(&hints, 0, sizeof hints); 694 hints.ai_flags = AI_PASSIVE; 695 hints.ai_family = si.si_af; 696 hints.ai_socktype = si.si_socktype; 697 hints.ai_protocol = si.si_proto; 698 699 if (svcport_str == NULL) { 700 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 701 if (svcport_str == NULL) 702 out_of_mem(); 703 704 if (getnameinfo(res->ai_addr, 705 res->ai_addr->sa_len, NULL, NI_MAXHOST, 706 svcport_str, NI_MAXSERV * sizeof(char), 707 NI_NUMERICHOST | NI_NUMERICSERV)) 708 errx(1, "Cannot get port number"); 709 } 710 711 if((aicode = getaddrinfo(NULL, svcport_str, &hints, 712 &res)) != 0) { 713 syslog(LOG_ERR, "cannot get local address: %s", 714 gai_strerror(aicode)); 715 exit(1); 716 } 717 718 servaddr.buf = malloc(res->ai_addrlen); 719 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 720 servaddr.len = res->ai_addrlen; 721 722 rpcb_set(MOUNTPROG, MOUNTVERS, nconf, &servaddr); 723 rpcb_set(MOUNTPROG, MOUNTVERS3, nconf, &servaddr); 724 725 xcreated++; 726 freeaddrinfo(res); 727 } 728 } /* end while */ 729} 730 731static void 732usage(void) 733{ 734 fprintf(stderr, 735 "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 736 "[-h <bindip>] [export_file ...]\n"); 737 exit(1); 738} 739 740/* 741 * The mount rpc service 742 */ 743void 744mntsrv(struct svc_req *rqstp, SVCXPRT *transp) 745{ 746 struct exportlist *ep; 747 struct dirlist *dp; 748 struct fhreturn fhr; 749 struct stat stb; 750 struct statfs fsb; 751 char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 752 int lookup_failed = 1; 753 struct sockaddr *saddr; 754 u_short sport; 755 char rpcpath[MNTPATHLEN + 1], dirpath[MAXPATHLEN]; 756 int bad = 0, defset, hostset; 757 sigset_t sighup_mask; 758 759 sigemptyset(&sighup_mask); 760 sigaddset(&sighup_mask, SIGHUP); 761 saddr = svc_getrpccaller(transp)->buf; 762 switch (saddr->sa_family) { 763 case AF_INET6: 764 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 765 break; 766 case AF_INET: 767 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 768 break; 769 default: 770 syslog(LOG_ERR, "request from unknown address family"); 771 return; 772 } 773 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 774 NULL, 0, 0); 775 getnameinfo(saddr, saddr->sa_len, numerichost, 776 sizeof numerichost, NULL, 0, NI_NUMERICHOST); 777 switch (rqstp->rq_proc) { 778 case NULLPROC: 779 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 780 syslog(LOG_ERR, "can't send reply"); 781 return; 782 case MOUNTPROC_MNT: 783 if (sport >= IPPORT_RESERVED && resvport_only) { 784 syslog(LOG_NOTICE, 785 "mount request from %s from unprivileged port", 786 numerichost); 787 svcerr_weakauth(transp); 788 return; 789 } 790 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 791 syslog(LOG_NOTICE, "undecodable mount request from %s", 792 numerichost); 793 svcerr_decode(transp); 794 return; 795 } 796 797 /* 798 * Get the real pathname and make sure it is a directory 799 * or a regular file if the -r option was specified 800 * and it exists. 801 */ 802 if (realpath(rpcpath, dirpath) == NULL || 803 stat(dirpath, &stb) < 0 || 804 (!S_ISDIR(stb.st_mode) && 805 (dir_only || !S_ISREG(stb.st_mode))) || 806 statfs(dirpath, &fsb) < 0) { 807 chdir("/"); /* Just in case realpath doesn't */ 808 syslog(LOG_NOTICE, 809 "mount request from %s for non existent path %s", 810 numerichost, dirpath); 811 if (debug) 812 warnx("stat failed on %s", dirpath); 813 bad = ENOENT; /* We will send error reply later */ 814 } 815 816 /* Check in the exports list */ 817 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 818 ep = ex_search(&fsb.f_fsid); 819 hostset = defset = 0; 820 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 821 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 822 chk_host(dp, saddr, &defset, &hostset)) || 823 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 824 scan_tree(ep->ex_dirl, saddr) == 0))) { 825 if (bad) { 826 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 827 (caddr_t)&bad)) 828 syslog(LOG_ERR, "can't send reply"); 829 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 830 return; 831 } 832 if (hostset & DP_HOSTSET) 833 fhr.fhr_flag = hostset; 834 else 835 fhr.fhr_flag = defset; 836 fhr.fhr_vers = rqstp->rq_vers; 837 /* Get the file handle */ 838 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 839 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 840 bad = errno; 841 syslog(LOG_ERR, "can't get fh for %s", dirpath); 842 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 843 (caddr_t)&bad)) 844 syslog(LOG_ERR, "can't send reply"); 845 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 846 return; 847 } 848 fhr.fhr_numsecflavors = ep->ex_numsecflavors; 849 fhr.fhr_secflavors = ep->ex_secflavors; 850 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 851 (caddr_t)&fhr)) 852 syslog(LOG_ERR, "can't send reply"); 853 if (!lookup_failed) 854 add_mlist(host, dirpath); 855 else 856 add_mlist(numerichost, dirpath); 857 if (debug) 858 warnx("mount successful"); 859 if (dolog) 860 syslog(LOG_NOTICE, 861 "mount request succeeded from %s for %s", 862 numerichost, dirpath); 863 } else { 864 bad = EACCES; 865 syslog(LOG_NOTICE, 866 "mount request denied from %s for %s", 867 numerichost, dirpath); 868 } 869 870 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 871 (caddr_t)&bad)) 872 syslog(LOG_ERR, "can't send reply"); 873 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 874 return; 875 case MOUNTPROC_DUMP: 876 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 877 syslog(LOG_ERR, "can't send reply"); 878 else if (dolog) 879 syslog(LOG_NOTICE, 880 "dump request succeeded from %s", 881 numerichost); 882 return; 883 case MOUNTPROC_UMNT: 884 if (sport >= IPPORT_RESERVED && resvport_only) { 885 syslog(LOG_NOTICE, 886 "umount request from %s from unprivileged port", 887 numerichost); 888 svcerr_weakauth(transp); 889 return; 890 } 891 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 892 syslog(LOG_NOTICE, "undecodable umount request from %s", 893 numerichost); 894 svcerr_decode(transp); 895 return; 896 } 897 if (realpath(rpcpath, dirpath) == NULL) { 898 syslog(LOG_NOTICE, "umount request from %s " 899 "for non existent path %s", 900 numerichost, dirpath); 901 } 902 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 903 syslog(LOG_ERR, "can't send reply"); 904 if (!lookup_failed) 905 del_mlist(host, dirpath); 906 del_mlist(numerichost, dirpath); 907 if (dolog) 908 syslog(LOG_NOTICE, 909 "umount request succeeded from %s for %s", 910 numerichost, dirpath); 911 return; 912 case MOUNTPROC_UMNTALL: 913 if (sport >= IPPORT_RESERVED && resvport_only) { 914 syslog(LOG_NOTICE, 915 "umountall request from %s from unprivileged port", 916 numerichost); 917 svcerr_weakauth(transp); 918 return; 919 } 920 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 921 syslog(LOG_ERR, "can't send reply"); 922 if (!lookup_failed) 923 del_mlist(host, NULL); 924 del_mlist(numerichost, NULL); 925 if (dolog) 926 syslog(LOG_NOTICE, 927 "umountall request succeeded from %s", 928 numerichost); 929 return; 930 case MOUNTPROC_EXPORT: 931 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 932 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 933 (caddr_t)NULL)) 934 syslog(LOG_ERR, "can't send reply"); 935 if (dolog) 936 syslog(LOG_NOTICE, 937 "export request succeeded from %s", 938 numerichost); 939 return; 940 default: 941 svcerr_noproc(transp); 942 return; 943 } 944} 945 946/* 947 * Xdr conversion for a dirpath string 948 */ 949int 950xdr_dir(XDR *xdrsp, char *dirp) 951{ 952 return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 953} 954 955/* 956 * Xdr routine to generate file handle reply 957 */ 958int 959xdr_fhs(XDR *xdrsp, caddr_t cp) 960{ 961 struct fhreturn *fhrp = (struct fhreturn *)cp; 962 u_long ok = 0, len, auth; 963 int i; 964 965 if (!xdr_long(xdrsp, &ok)) 966 return (0); 967 switch (fhrp->fhr_vers) { 968 case 1: 969 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 970 case 3: 971 len = NFSX_V3FH; 972 if (!xdr_long(xdrsp, &len)) 973 return (0); 974 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 975 return (0); 976 if (fhrp->fhr_numsecflavors) { 977 if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 978 return (0); 979 for (i = 0; i < fhrp->fhr_numsecflavors; i++) 980 if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 981 return (0); 982 return (1); 983 } else { 984 auth = AUTH_SYS; 985 len = 1; 986 if (!xdr_long(xdrsp, &len)) 987 return (0); 988 return (xdr_long(xdrsp, &auth)); 989 } 990 }; 991 return (0); 992} 993 994int 995xdr_mlist(XDR *xdrsp, caddr_t cp __unused) 996{ 997 struct mountlist *mlp; 998 int true = 1; 999 int false = 0; 1000 char *strp; 1001 1002 mlp = mlhead; 1003 while (mlp) { 1004 if (!xdr_bool(xdrsp, &true)) 1005 return (0); 1006 strp = &mlp->ml_host[0]; 1007 if (!xdr_string(xdrsp, &strp, MNTNAMLEN)) 1008 return (0); 1009 strp = &mlp->ml_dirp[0]; 1010 if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1011 return (0); 1012 mlp = mlp->ml_next; 1013 } 1014 if (!xdr_bool(xdrsp, &false)) 1015 return (0); 1016 return (1); 1017} 1018 1019/* 1020 * Xdr conversion for export list 1021 */ 1022int 1023xdr_explist_common(XDR *xdrsp, caddr_t cp __unused, int brief) 1024{ 1025 struct exportlist *ep; 1026 int false = 0; 1027 int putdef; 1028 sigset_t sighup_mask; 1029 1030 sigemptyset(&sighup_mask); 1031 sigaddset(&sighup_mask, SIGHUP); 1032 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1033 ep = exphead; 1034 while (ep) { 1035 putdef = 0; 1036 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1037 &putdef, brief)) 1038 goto errout; 1039 if (ep->ex_defdir && putdef == 0 && 1040 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1041 &putdef, brief)) 1042 goto errout; 1043 ep = ep->ex_next; 1044 } 1045 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1046 if (!xdr_bool(xdrsp, &false)) 1047 return (0); 1048 return (1); 1049errout: 1050 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1051 return (0); 1052} 1053 1054/* 1055 * Called from xdr_explist() to traverse the tree and export the 1056 * directory paths. 1057 */ 1058int 1059put_exlist(struct dirlist *dp, XDR *xdrsp, struct dirlist *adp, int *putdefp, 1060 int brief) 1061{ 1062 struct grouplist *grp; 1063 struct hostlist *hp; 1064 int true = 1; 1065 int false = 0; 1066 int gotalldir = 0; 1067 char *strp; 1068 1069 if (dp) { 1070 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 1071 return (1); 1072 if (!xdr_bool(xdrsp, &true)) 1073 return (1); 1074 strp = dp->dp_dirp; 1075 if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1076 return (1); 1077 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 1078 gotalldir = 1; 1079 *putdefp = 1; 1080 } 1081 if (brief) { 1082 if (!xdr_bool(xdrsp, &true)) 1083 return (1); 1084 strp = "(...)"; 1085 if (!xdr_string(xdrsp, &strp, MNTPATHLEN)) 1086 return (1); 1087 } else if ((dp->dp_flag & DP_DEFSET) == 0 && 1088 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 1089 hp = dp->dp_hosts; 1090 while (hp) { 1091 grp = hp->ht_grp; 1092 if (grp->gr_type == GT_HOST) { 1093 if (!xdr_bool(xdrsp, &true)) 1094 return (1); 1095 strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 1096 if (!xdr_string(xdrsp, &strp, 1097 MNTNAMLEN)) 1098 return (1); 1099 } else if (grp->gr_type == GT_NET) { 1100 if (!xdr_bool(xdrsp, &true)) 1101 return (1); 1102 strp = grp->gr_ptr.gt_net.nt_name; 1103 if (!xdr_string(xdrsp, &strp, 1104 MNTNAMLEN)) 1105 return (1); 1106 } 1107 hp = hp->ht_next; 1108 if (gotalldir && hp == (struct hostlist *)NULL) { 1109 hp = adp->dp_hosts; 1110 gotalldir = 0; 1111 } 1112 } 1113 } 1114 if (!xdr_bool(xdrsp, &false)) 1115 return (1); 1116 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 1117 return (1); 1118 } 1119 return (0); 1120} 1121 1122int 1123xdr_explist(XDR *xdrsp, caddr_t cp) 1124{ 1125 1126 return xdr_explist_common(xdrsp, cp, 0); 1127} 1128 1129int 1130xdr_explist_brief(XDR *xdrsp, caddr_t cp) 1131{ 1132 1133 return xdr_explist_common(xdrsp, cp, 1); 1134} 1135 1136char *line; 1137int linesize; 1138FILE *exp_file; 1139 1140/* 1141 * Get the export list from one, currently open file 1142 */ 1143static void 1144get_exportlist_one(void) 1145{ 1146 struct exportlist *ep, *ep2; 1147 struct grouplist *grp, *tgrp; 1148 struct exportlist **epp; 1149 struct dirlist *dirhead; 1150 struct statfs fsb; 1151 struct xucred anon; 1152 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1153 int len, has_host, exflags, got_nondir, dirplen, netgrp; 1154 1155 v4root_phase = 0; 1156 dirhead = (struct dirlist *)NULL; 1157 while (get_line()) { 1158 if (debug) 1159 warnx("got line %s", line); 1160 cp = line; 1161 nextfield(&cp, &endcp); 1162 if (*cp == '#') 1163 goto nextline; 1164 1165 /* 1166 * Set defaults. 1167 */ 1168 has_host = FALSE; 1169 anon = def_anon; 1170 exflags = MNT_EXPORTED; 1171 got_nondir = 0; 1172 opt_flags = 0; 1173 ep = (struct exportlist *)NULL; 1174 dirp = NULL; 1175 1176 /* 1177 * Handle the V4 root dir. 1178 */ 1179 if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1180 /* 1181 * V4: just indicates that it is the v4 root point, 1182 * so skip over that and set v4root_phase. 1183 */ 1184 if (v4root_phase > 0) { 1185 syslog(LOG_ERR, "V4:duplicate line, ignored"); 1186 goto nextline; 1187 } 1188 v4root_phase = 1; 1189 cp += 3; 1190 nextfield(&cp, &endcp); 1191 } 1192 1193 /* 1194 * Create new exports list entry 1195 */ 1196 len = endcp-cp; 1197 tgrp = grp = get_grp(); 1198 while (len > 0) { 1199 if (len > MNTNAMLEN) { 1200 getexp_err(ep, tgrp); 1201 goto nextline; 1202 } 1203 if (*cp == '-') { 1204 if (ep == (struct exportlist *)NULL) { 1205 getexp_err(ep, tgrp); 1206 goto nextline; 1207 } 1208 if (debug) 1209 warnx("doing opt %s", cp); 1210 got_nondir = 1; 1211 if (do_opt(&cp, &endcp, ep, grp, &has_host, 1212 &exflags, &anon)) { 1213 getexp_err(ep, tgrp); 1214 goto nextline; 1215 } 1216 } else if (*cp == '/') { 1217 savedc = *endcp; 1218 *endcp = '\0'; 1219 if (v4root_phase > 1) { 1220 if (dirp != NULL) { 1221 syslog(LOG_ERR, "Multiple V4 dirs"); 1222 getexp_err(ep, tgrp); 1223 goto nextline; 1224 } 1225 } 1226 if (check_dirpath(cp) && 1227 statfs(cp, &fsb) >= 0) { 1228 if (got_nondir) { 1229 syslog(LOG_ERR, "dirs must be first"); 1230 getexp_err(ep, tgrp); 1231 goto nextline; 1232 } 1233 if (v4root_phase == 1) { 1234 if (dirp != NULL) { 1235 syslog(LOG_ERR, "Multiple V4 dirs"); 1236 getexp_err(ep, tgrp); 1237 goto nextline; 1238 } 1239 if (strlen(v4root_dirpath) == 0) { 1240 strlcpy(v4root_dirpath, cp, 1241 sizeof (v4root_dirpath)); 1242 } else if (strcmp(v4root_dirpath, cp) 1243 != 0) { 1244 syslog(LOG_ERR, 1245 "different V4 dirpath %s", cp); 1246 getexp_err(ep, tgrp); 1247 goto nextline; 1248 } 1249 dirp = cp; 1250 v4root_phase = 2; 1251 got_nondir = 1; 1252 ep = get_exp(); 1253 } else { 1254 if (ep) { 1255 if (ep->ex_fs.val[0] != 1256 fsb.f_fsid.val[0] || 1257 ep->ex_fs.val[1] != 1258 fsb.f_fsid.val[1]) { 1259 getexp_err(ep, tgrp); 1260 goto nextline; 1261 } 1262 } else { 1263 /* 1264 * See if this directory is already 1265 * in the list. 1266 */ 1267 ep = ex_search(&fsb.f_fsid); 1268 if (ep == (struct exportlist *)NULL) { 1269 ep = get_exp(); 1270 ep->ex_fs = fsb.f_fsid; 1271 ep->ex_fsdir = (char *)malloc 1272 (strlen(fsb.f_mntonname) + 1); 1273 if (ep->ex_fsdir) 1274 strcpy(ep->ex_fsdir, 1275 fsb.f_mntonname); 1276 else 1277 out_of_mem(); 1278 if (debug) 1279 warnx( 1280 "making new ep fs=0x%x,0x%x", 1281 fsb.f_fsid.val[0], 1282 fsb.f_fsid.val[1]); 1283 } else if (debug) 1284 warnx("found ep fs=0x%x,0x%x", 1285 fsb.f_fsid.val[0], 1286 fsb.f_fsid.val[1]); 1287 } 1288 1289 /* 1290 * Add dirpath to export mount point. 1291 */ 1292 dirp = add_expdir(&dirhead, cp, len); 1293 dirplen = len; 1294 } 1295 } else { 1296 getexp_err(ep, tgrp); 1297 goto nextline; 1298 } 1299 *endcp = savedc; 1300 } else { 1301 savedc = *endcp; 1302 *endcp = '\0'; 1303 got_nondir = 1; 1304 if (ep == (struct exportlist *)NULL) { 1305 getexp_err(ep, tgrp); 1306 goto nextline; 1307 } 1308 1309 /* 1310 * Get the host or netgroup. 1311 */ 1312 setnetgrent(cp); 1313 netgrp = getnetgrent(&hst, &usr, &dom); 1314 do { 1315 if (has_host) { 1316 grp->gr_next = get_grp(); 1317 grp = grp->gr_next; 1318 } 1319 if (netgrp) { 1320 if (hst == 0) { 1321 syslog(LOG_ERR, 1322 "null hostname in netgroup %s, skipping", cp); 1323 grp->gr_type = GT_IGNORE; 1324 } else if (get_host(hst, grp, tgrp)) { 1325 syslog(LOG_ERR, 1326 "bad host %s in netgroup %s, skipping", hst, cp); 1327 grp->gr_type = GT_IGNORE; 1328 } 1329 } else if (get_host(cp, grp, tgrp)) { 1330 syslog(LOG_ERR, "bad host %s, skipping", cp); 1331 grp->gr_type = GT_IGNORE; 1332 } 1333 has_host = TRUE; 1334 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 1335 endnetgrent(); 1336 *endcp = savedc; 1337 } 1338 cp = endcp; 1339 nextfield(&cp, &endcp); 1340 len = endcp - cp; 1341 } 1342 if (check_options(dirhead)) { 1343 getexp_err(ep, tgrp); 1344 goto nextline; 1345 } 1346 if (!has_host) { 1347 grp->gr_type = GT_DEFAULT; 1348 if (debug) 1349 warnx("adding a default entry"); 1350 1351 /* 1352 * Don't allow a network export coincide with a list of 1353 * host(s) on the same line. 1354 */ 1355 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1356 syslog(LOG_ERR, "network/host conflict"); 1357 getexp_err(ep, tgrp); 1358 goto nextline; 1359 1360 /* 1361 * If an export list was specified on this line, make sure 1362 * that we have at least one valid entry, otherwise skip it. 1363 */ 1364 } else { 1365 grp = tgrp; 1366 while (grp && grp->gr_type == GT_IGNORE) 1367 grp = grp->gr_next; 1368 if (! grp) { 1369 getexp_err(ep, tgrp); 1370 goto nextline; 1371 } 1372 } 1373 1374 if (v4root_phase == 1) { 1375 syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1376 getexp_err(ep, tgrp); 1377 goto nextline; 1378 } 1379 1380 /* 1381 * Loop through hosts, pushing the exports into the kernel. 1382 * After loop, tgrp points to the start of the list and 1383 * grp points to the last entry in the list. 1384 */ 1385 grp = tgrp; 1386 do { 1387 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 1388 &fsb)) { 1389 getexp_err(ep, tgrp); 1390 goto nextline; 1391 } 1392 } while (grp->gr_next && (grp = grp->gr_next)); 1393 1394 /* 1395 * For V4: don't enter in mount lists. 1396 */ 1397 if (v4root_phase > 0 && v4root_phase <= 2) { 1398 /* 1399 * Since these structures aren't used by mountd, 1400 * free them up now. 1401 */ 1402 if (ep != NULL) 1403 free_exp(ep); 1404 while (tgrp != NULL) { 1405 grp = tgrp; 1406 tgrp = tgrp->gr_next; 1407 free_grp(grp); 1408 } 1409 goto nextline; 1410 } 1411 1412 /* 1413 * Success. Update the data structures. 1414 */ 1415 if (has_host) { 1416 hang_dirp(dirhead, tgrp, ep, opt_flags); 1417 grp->gr_next = grphead; 1418 grphead = tgrp; 1419 } else { 1420 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1421 opt_flags); 1422 free_grp(grp); 1423 } 1424 dirhead = (struct dirlist *)NULL; 1425 if ((ep->ex_flag & EX_LINKED) == 0) { 1426 ep2 = exphead; 1427 epp = &exphead; 1428 1429 /* 1430 * Insert in the list in alphabetical order. 1431 */ 1432 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1433 epp = &ep2->ex_next; 1434 ep2 = ep2->ex_next; 1435 } 1436 if (ep2) 1437 ep->ex_next = ep2; 1438 *epp = ep; 1439 ep->ex_flag |= EX_LINKED; 1440 } 1441nextline: 1442 v4root_phase = 0; 1443 if (dirhead) { 1444 free_dir(dirhead); 1445 dirhead = (struct dirlist *)NULL; 1446 } 1447 } 1448} 1449 1450/* 1451 * Get the export list from all specified files 1452 */ 1453void 1454get_exportlist(void) 1455{ 1456 struct exportlist *ep, *ep2; 1457 struct grouplist *grp, *tgrp; 1458 struct export_args export; 1459 struct iovec *iov; 1460 struct statfs *fsp, *mntbufp; 1461 struct xvfsconf vfc; 1462 char *dirp; 1463 char errmsg[255]; 1464 int dirplen, num, i; 1465 int iovlen; 1466 int done; 1467 struct nfsex_args eargs; 1468 1469 v4root_dirpath[0] = '\0'; 1470 bzero(&export, sizeof(export)); 1471 export.ex_flags = MNT_DELEXPORT; 1472 dirp = NULL; 1473 dirplen = 0; 1474 iov = NULL; 1475 iovlen = 0; 1476 bzero(errmsg, sizeof(errmsg)); 1477 1478 /* 1479 * First, get rid of the old list 1480 */ 1481 ep = exphead; 1482 while (ep) { 1483 ep2 = ep; 1484 ep = ep->ex_next; 1485 free_exp(ep2); 1486 } 1487 exphead = (struct exportlist *)NULL; 1488 1489 grp = grphead; 1490 while (grp) { 1491 tgrp = grp; 1492 grp = grp->gr_next; 1493 free_grp(tgrp); 1494 } 1495 grphead = (struct grouplist *)NULL; 1496 1497 /* 1498 * and the old V4 root dir. 1499 */ 1500 bzero(&eargs, sizeof (eargs)); 1501 eargs.export.ex_flags = MNT_DELEXPORT; 1502 if (run_v4server > 0 && 1503 nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1504 errno != ENOENT) 1505 syslog(LOG_ERR, "Can't delete exports for V4:"); 1506 1507 /* 1508 * and clear flag that notes if a public fh has been exported. 1509 */ 1510 has_publicfh = 0; 1511 1512 /* 1513 * And delete exports that are in the kernel for all local 1514 * filesystems. 1515 * XXX: Should know how to handle all local exportable filesystems. 1516 */ 1517 num = getmntinfo(&mntbufp, MNT_NOWAIT); 1518 1519 if (num > 0) { 1520 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1521 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1522 build_iovec(&iov, &iovlen, "from", NULL, 0); 1523 build_iovec(&iov, &iovlen, "update", NULL, 0); 1524 build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1525 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1526 } 1527 1528 for (i = 0; i < num; i++) { 1529 fsp = &mntbufp[i]; 1530 if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1531 syslog(LOG_ERR, "getvfsbyname() failed for %s", 1532 fsp->f_fstypename); 1533 continue; 1534 } 1535 1536 /* 1537 * Do not delete export for network filesystem by 1538 * passing "export" arg to nmount(). 1539 * It only makes sense to do this for local filesystems. 1540 */ 1541 if (vfc.vfc_flags & VFCF_NETWORK) 1542 continue; 1543 1544 iov[1].iov_base = fsp->f_fstypename; 1545 iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1546 iov[3].iov_base = fsp->f_mntonname; 1547 iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1548 iov[5].iov_base = fsp->f_mntfromname; 1549 iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1550 1551 if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1552 errno != ENOENT && errno != ENOTSUP) { 1553 syslog(LOG_ERR, 1554 "can't delete exports for %s: %m %s", 1555 fsp->f_mntonname, errmsg); 1556 } 1557 } 1558 1559 if (iov != NULL) { 1560 /* Free strings allocated by strdup() in getmntopts.c */ 1561 free(iov[0].iov_base); /* fstype */ 1562 free(iov[2].iov_base); /* fspath */ 1563 free(iov[4].iov_base); /* from */ 1564 free(iov[6].iov_base); /* update */ 1565 free(iov[8].iov_base); /* export */ 1566 free(iov[10].iov_base); /* errmsg */ 1567 1568 /* free iov, allocated by realloc() */ 1569 free(iov); 1570 iovlen = 0; 1571 } 1572 1573 /* 1574 * Read in the exports file and build the list, calling 1575 * nmount() as we go along to push the export rules into the kernel. 1576 */ 1577 done = 0; 1578 for (i = 0; exnames[i] != NULL; i++) { 1579 if (debug) 1580 warnx("reading exports from %s", exnames[i]); 1581 if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1582 syslog(LOG_WARNING, "can't open %s", exnames[i]); 1583 continue; 1584 } 1585 get_exportlist_one(); 1586 fclose(exp_file); 1587 done++; 1588 } 1589 if (done == 0) { 1590 syslog(LOG_ERR, "can't open any exports file"); 1591 exit(2); 1592 } 1593 1594 /* 1595 * If there was no public fh, clear any previous one set. 1596 */ 1597 if (run_v4server > 0 && has_publicfh == 0) 1598 (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1599} 1600 1601/* 1602 * Allocate an export list element 1603 */ 1604struct exportlist * 1605get_exp(void) 1606{ 1607 struct exportlist *ep; 1608 1609 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1610 if (ep == (struct exportlist *)NULL) 1611 out_of_mem(); 1612 memset(ep, 0, sizeof(struct exportlist)); 1613 return (ep); 1614} 1615 1616/* 1617 * Allocate a group list element 1618 */ 1619struct grouplist * 1620get_grp(void) 1621{ 1622 struct grouplist *gp; 1623 1624 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1625 if (gp == (struct grouplist *)NULL) 1626 out_of_mem(); 1627 memset(gp, 0, sizeof(struct grouplist)); 1628 return (gp); 1629} 1630 1631/* 1632 * Clean up upon an error in get_exportlist(). 1633 */ 1634void 1635getexp_err(struct exportlist *ep, struct grouplist *grp) 1636{ 1637 struct grouplist *tgrp; 1638 1639 if (!(opt_flags & OP_QUIET)) 1640 syslog(LOG_ERR, "bad exports list line %s", line); 1641 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1642 free_exp(ep); 1643 while (grp) { 1644 tgrp = grp; 1645 grp = grp->gr_next; 1646 free_grp(tgrp); 1647 } 1648} 1649 1650/* 1651 * Search the export list for a matching fs. 1652 */ 1653struct exportlist * 1654ex_search(fsid_t *fsid) 1655{ 1656 struct exportlist *ep; 1657 1658 ep = exphead; 1659 while (ep) { 1660 if (ep->ex_fs.val[0] == fsid->val[0] && 1661 ep->ex_fs.val[1] == fsid->val[1]) 1662 return (ep); 1663 ep = ep->ex_next; 1664 } 1665 return (ep); 1666} 1667 1668/* 1669 * Add a directory path to the list. 1670 */ 1671char * 1672add_expdir(struct dirlist **dpp, char *cp, int len) 1673{ 1674 struct dirlist *dp; 1675 1676 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1677 if (dp == (struct dirlist *)NULL) 1678 out_of_mem(); 1679 dp->dp_left = *dpp; 1680 dp->dp_right = (struct dirlist *)NULL; 1681 dp->dp_flag = 0; 1682 dp->dp_hosts = (struct hostlist *)NULL; 1683 strcpy(dp->dp_dirp, cp); 1684 *dpp = dp; 1685 return (dp->dp_dirp); 1686} 1687 1688/* 1689 * Hang the dir list element off the dirpath binary tree as required 1690 * and update the entry for host. 1691 */ 1692void 1693hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, 1694 int flags) 1695{ 1696 struct hostlist *hp; 1697 struct dirlist *dp2; 1698 1699 if (flags & OP_ALLDIRS) { 1700 if (ep->ex_defdir) 1701 free((caddr_t)dp); 1702 else 1703 ep->ex_defdir = dp; 1704 if (grp == (struct grouplist *)NULL) { 1705 ep->ex_defdir->dp_flag |= DP_DEFSET; 1706 } else while (grp) { 1707 hp = get_ht(); 1708 hp->ht_grp = grp; 1709 hp->ht_next = ep->ex_defdir->dp_hosts; 1710 ep->ex_defdir->dp_hosts = hp; 1711 grp = grp->gr_next; 1712 } 1713 } else { 1714 1715 /* 1716 * Loop through the directories adding them to the tree. 1717 */ 1718 while (dp) { 1719 dp2 = dp->dp_left; 1720 add_dlist(&ep->ex_dirl, dp, grp, flags); 1721 dp = dp2; 1722 } 1723 } 1724} 1725 1726/* 1727 * Traverse the binary tree either updating a node that is already there 1728 * for the new directory or adding the new node. 1729 */ 1730void 1731add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, 1732 int flags) 1733{ 1734 struct dirlist *dp; 1735 struct hostlist *hp; 1736 int cmp; 1737 1738 dp = *dpp; 1739 if (dp) { 1740 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1741 if (cmp > 0) { 1742 add_dlist(&dp->dp_left, newdp, grp, flags); 1743 return; 1744 } else if (cmp < 0) { 1745 add_dlist(&dp->dp_right, newdp, grp, flags); 1746 return; 1747 } else 1748 free((caddr_t)newdp); 1749 } else { 1750 dp = newdp; 1751 dp->dp_left = (struct dirlist *)NULL; 1752 *dpp = dp; 1753 } 1754 if (grp) { 1755 1756 /* 1757 * Hang all of the host(s) off of the directory point. 1758 */ 1759 do { 1760 hp = get_ht(); 1761 hp->ht_grp = grp; 1762 hp->ht_next = dp->dp_hosts; 1763 dp->dp_hosts = hp; 1764 grp = grp->gr_next; 1765 } while (grp); 1766 } else { 1767 dp->dp_flag |= DP_DEFSET; 1768 } 1769} 1770 1771/* 1772 * Search for a dirpath on the export point. 1773 */ 1774struct dirlist * 1775dirp_search(struct dirlist *dp, char *dirp) 1776{ 1777 int cmp; 1778 1779 if (dp) { 1780 cmp = strcmp(dp->dp_dirp, dirp); 1781 if (cmp > 0) 1782 return (dirp_search(dp->dp_left, dirp)); 1783 else if (cmp < 0) 1784 return (dirp_search(dp->dp_right, dirp)); 1785 else 1786 return (dp); 1787 } 1788 return (dp); 1789} 1790 1791/* 1792 * Scan for a host match in a directory tree. 1793 */ 1794int 1795chk_host(struct dirlist *dp, struct sockaddr *saddr, int *defsetp, 1796 int *hostsetp) 1797{ 1798 struct hostlist *hp; 1799 struct grouplist *grp; 1800 struct addrinfo *ai; 1801 1802 if (dp) { 1803 if (dp->dp_flag & DP_DEFSET) 1804 *defsetp = dp->dp_flag; 1805 hp = dp->dp_hosts; 1806 while (hp) { 1807 grp = hp->ht_grp; 1808 switch (grp->gr_type) { 1809 case GT_HOST: 1810 ai = grp->gr_ptr.gt_addrinfo; 1811 for (; ai; ai = ai->ai_next) { 1812 if (!sacmp(ai->ai_addr, saddr, NULL)) { 1813 *hostsetp = 1814 (hp->ht_flag | DP_HOSTSET); 1815 return (1); 1816 } 1817 } 1818 break; 1819 case GT_NET: 1820 if (!sacmp(saddr, (struct sockaddr *) 1821 &grp->gr_ptr.gt_net.nt_net, 1822 (struct sockaddr *) 1823 &grp->gr_ptr.gt_net.nt_mask)) { 1824 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1825 return (1); 1826 } 1827 break; 1828 } 1829 hp = hp->ht_next; 1830 } 1831 } 1832 return (0); 1833} 1834 1835/* 1836 * Scan tree for a host that matches the address. 1837 */ 1838int 1839scan_tree(struct dirlist *dp, struct sockaddr *saddr) 1840{ 1841 int defset, hostset; 1842 1843 if (dp) { 1844 if (scan_tree(dp->dp_left, saddr)) 1845 return (1); 1846 if (chk_host(dp, saddr, &defset, &hostset)) 1847 return (1); 1848 if (scan_tree(dp->dp_right, saddr)) 1849 return (1); 1850 } 1851 return (0); 1852} 1853 1854/* 1855 * Traverse the dirlist tree and free it up. 1856 */ 1857void 1858free_dir(struct dirlist *dp) 1859{ 1860 1861 if (dp) { 1862 free_dir(dp->dp_left); 1863 free_dir(dp->dp_right); 1864 free_host(dp->dp_hosts); 1865 free((caddr_t)dp); 1866 } 1867} 1868 1869/* 1870 * Parse a colon separated list of security flavors 1871 */ 1872int 1873parsesec(char *seclist, struct exportlist *ep) 1874{ 1875 char *cp, savedc; 1876 int flavor; 1877 1878 ep->ex_numsecflavors = 0; 1879 for (;;) { 1880 cp = strchr(seclist, ':'); 1881 if (cp) { 1882 savedc = *cp; 1883 *cp = '\0'; 1884 } 1885 1886 if (!strcmp(seclist, "sys")) 1887 flavor = AUTH_SYS; 1888 else if (!strcmp(seclist, "krb5")) 1889 flavor = RPCSEC_GSS_KRB5; 1890 else if (!strcmp(seclist, "krb5i")) 1891 flavor = RPCSEC_GSS_KRB5I; 1892 else if (!strcmp(seclist, "krb5p")) 1893 flavor = RPCSEC_GSS_KRB5P; 1894 else { 1895 if (cp) 1896 *cp = savedc; 1897 syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1898 return (1); 1899 } 1900 if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1901 if (cp) 1902 *cp = savedc; 1903 syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1904 return (1); 1905 } 1906 ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1907 ep->ex_numsecflavors++; 1908 if (cp) { 1909 *cp = savedc; 1910 seclist = cp + 1; 1911 } else { 1912 break; 1913 } 1914 } 1915 return (0); 1916} 1917 1918/* 1919 * Parse the option string and update fields. 1920 * Option arguments may either be -<option>=<value> or 1921 * -<option> <value> 1922 */ 1923int 1924do_opt(char **cpp, char **endcpp, struct exportlist *ep, struct grouplist *grp, 1925 int *has_hostp, int *exflagsp, struct xucred *cr) 1926{ 1927 char *cpoptarg, *cpoptend; 1928 char *cp, *endcp, *cpopt, savedc, savedc2; 1929 int allflag, usedarg; 1930 1931 savedc2 = '\0'; 1932 cpopt = *cpp; 1933 cpopt++; 1934 cp = *endcpp; 1935 savedc = *cp; 1936 *cp = '\0'; 1937 while (cpopt && *cpopt) { 1938 allflag = 1; 1939 usedarg = -2; 1940 if ((cpoptend = strchr(cpopt, ','))) { 1941 *cpoptend++ = '\0'; 1942 if ((cpoptarg = strchr(cpopt, '='))) 1943 *cpoptarg++ = '\0'; 1944 } else { 1945 if ((cpoptarg = strchr(cpopt, '='))) 1946 *cpoptarg++ = '\0'; 1947 else { 1948 *cp = savedc; 1949 nextfield(&cp, &endcp); 1950 **endcpp = '\0'; 1951 if (endcp > cp && *cp != '-') { 1952 cpoptarg = cp; 1953 savedc2 = *endcp; 1954 *endcp = '\0'; 1955 usedarg = 0; 1956 } 1957 } 1958 } 1959 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1960 *exflagsp |= MNT_EXRDONLY; 1961 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1962 !(allflag = strcmp(cpopt, "mapall")) || 1963 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1964 usedarg++; 1965 parsecred(cpoptarg, cr); 1966 if (allflag == 0) { 1967 *exflagsp |= MNT_EXPORTANON; 1968 opt_flags |= OP_MAPALL; 1969 } else 1970 opt_flags |= OP_MAPROOT; 1971 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1972 !strcmp(cpopt, "m"))) { 1973 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1974 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1975 return (1); 1976 } 1977 usedarg++; 1978 opt_flags |= OP_MASK; 1979 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1980 !strcmp(cpopt, "n"))) { 1981 if (strchr(cpoptarg, '/') != NULL) { 1982 if (debug) 1983 fprintf(stderr, "setting OP_MASKLEN\n"); 1984 opt_flags |= OP_MASKLEN; 1985 } 1986 if (grp->gr_type != GT_NULL) { 1987 syslog(LOG_ERR, "network/host conflict"); 1988 return (1); 1989 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1990 syslog(LOG_ERR, "bad net: %s", cpoptarg); 1991 return (1); 1992 } 1993 grp->gr_type = GT_NET; 1994 *has_hostp = 1; 1995 usedarg++; 1996 opt_flags |= OP_NET; 1997 } else if (!strcmp(cpopt, "alldirs")) { 1998 opt_flags |= OP_ALLDIRS; 1999 } else if (!strcmp(cpopt, "public")) { 2000 *exflagsp |= MNT_EXPUBLIC; 2001 } else if (!strcmp(cpopt, "webnfs")) { 2002 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2003 opt_flags |= OP_MAPALL; 2004 } else if (cpoptarg && !strcmp(cpopt, "index")) { 2005 ep->ex_indexfile = strdup(cpoptarg); 2006 } else if (!strcmp(cpopt, "quiet")) { 2007 opt_flags |= OP_QUIET; 2008 } else if (!strcmp(cpopt, "sec")) { 2009 if (parsesec(cpoptarg, ep)) 2010 return (1); 2011 opt_flags |= OP_SEC; 2012 usedarg++; 2013 } else { 2014 syslog(LOG_ERR, "bad opt %s", cpopt); 2015 return (1); 2016 } 2017 if (usedarg >= 0) { 2018 *endcp = savedc2; 2019 **endcpp = savedc; 2020 if (usedarg > 0) { 2021 *cpp = cp; 2022 *endcpp = endcp; 2023 } 2024 return (0); 2025 } 2026 cpopt = cpoptend; 2027 } 2028 **endcpp = savedc; 2029 return (0); 2030} 2031 2032/* 2033 * Translate a character string to the corresponding list of network 2034 * addresses for a hostname. 2035 */ 2036int 2037get_host(char *cp, struct grouplist *grp, struct grouplist *tgrp) 2038{ 2039 struct grouplist *checkgrp; 2040 struct addrinfo *ai, *tai, hints; 2041 int ecode; 2042 char host[NI_MAXHOST]; 2043 2044 if (grp->gr_type != GT_NULL) { 2045 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 2046 return (1); 2047 } 2048 memset(&hints, 0, sizeof hints); 2049 hints.ai_flags = AI_CANONNAME; 2050 hints.ai_protocol = IPPROTO_UDP; 2051 ecode = getaddrinfo(cp, NULL, &hints, &ai); 2052 if (ecode != 0) { 2053 syslog(LOG_ERR,"can't get address info for host %s", cp); 2054 return 1; 2055 } 2056 grp->gr_ptr.gt_addrinfo = ai; 2057 while (ai != NULL) { 2058 if (ai->ai_canonname == NULL) { 2059 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2060 sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 2061 strlcpy(host, "?", sizeof(host)); 2062 ai->ai_canonname = strdup(host); 2063 ai->ai_flags |= AI_CANONNAME; 2064 } 2065 if (debug) 2066 fprintf(stderr, "got host %s\n", ai->ai_canonname); 2067 /* 2068 * Sanity check: make sure we don't already have an entry 2069 * for this host in the grouplist. 2070 */ 2071 for (checkgrp = tgrp; checkgrp != NULL; 2072 checkgrp = checkgrp->gr_next) { 2073 if (checkgrp->gr_type != GT_HOST) 2074 continue; 2075 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 2076 tai = tai->ai_next) { 2077 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 2078 continue; 2079 if (debug) 2080 fprintf(stderr, 2081 "ignoring duplicate host %s\n", 2082 ai->ai_canonname); 2083 grp->gr_type = GT_IGNORE; 2084 return (0); 2085 } 2086 } 2087 ai = ai->ai_next; 2088 } 2089 grp->gr_type = GT_HOST; 2090 return (0); 2091} 2092 2093/* 2094 * Free up an exports list component 2095 */ 2096void 2097free_exp(struct exportlist *ep) 2098{ 2099 2100 if (ep->ex_defdir) { 2101 free_host(ep->ex_defdir->dp_hosts); 2102 free((caddr_t)ep->ex_defdir); 2103 } 2104 if (ep->ex_fsdir) 2105 free(ep->ex_fsdir); 2106 if (ep->ex_indexfile) 2107 free(ep->ex_indexfile); 2108 free_dir(ep->ex_dirl); 2109 free((caddr_t)ep); 2110} 2111 2112/* 2113 * Free hosts. 2114 */ 2115void 2116free_host(struct hostlist *hp) 2117{ 2118 struct hostlist *hp2; 2119 2120 while (hp) { 2121 hp2 = hp; 2122 hp = hp->ht_next; 2123 free((caddr_t)hp2); 2124 } 2125} 2126 2127struct hostlist * 2128get_ht(void) 2129{ 2130 struct hostlist *hp; 2131 2132 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 2133 if (hp == (struct hostlist *)NULL) 2134 out_of_mem(); 2135 hp->ht_next = (struct hostlist *)NULL; 2136 hp->ht_flag = 0; 2137 return (hp); 2138} 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++ = (u_char)~0 << (CHAR_BIT - bits); 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