Print this page
7577 mountd support to run on a fixed port
Portions contributed by: Paul Dagnelie <pcd@delphix.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/fs.d/nfs/mountd/mountd.c
          +++ new/usr/src/cmd/fs.d/nfs/mountd/mountd.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   23   * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
       25 + * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  25   26   */
  26   27  
  27   28  /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T     */
  28   29  /*        All Rights Reserved   */
  29   30  
  30   31  /*
  31   32   * Portions of this source code were derived from Berkeley 4.3 BSD
  32   33   * under license from the Regents of the University of California.
  33   34   */
  34   35  
↓ open down ↓ 75 lines elided ↑ open up ↑
 110  111      gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
 111  112  static void mnt(struct svc_req *, SVCXPRT *);
 112  113  static void mnt_pathconf(struct svc_req *);
 113  114  static int mount(struct svc_req *r);
 114  115  static void sh_free(struct sh_list *);
 115  116  static void umount(struct svc_req *);
 116  117  static void umountall(struct svc_req *);
 117  118  static int newopts(char *);
 118  119  static tsol_tpent_t *get_client_template(struct sockaddr *);
 119  120  
      121 +static int debug;
 120  122  static int verbose;
 121  123  static int rejecting;
 122  124  static int mount_vers_min = MOUNTVERS;
 123  125  static int mount_vers_max = MOUNTVERS3;
      126 +static int mountd_port = 0;
 124  127  
 125  128  extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
 126  129  
 127  130  thread_t        nfsauth_thread;
 128  131  thread_t        cmd_thread;
 129  132  thread_t        logging_thread;
 130  133  
 131  134  typedef struct logging_data {
 132  135          char                    *ld_host;
 133  136          char                    *ld_path;
↓ open down ↓ 221 lines elided ↑ open up ↑
 355  358                  return (-1);
 356  359  
 357  360          lval = strtol(str, &str, 10);
 358  361          if (*str != '\0' || lval > INT_MAX)
 359  362                  return (-2);
 360  363  
 361  364          *val = (int)lval;
 362  365          return (0);
 363  366  }
 364  367  
      368 +/*
      369 + * This function is called for each configured network type to
      370 + * bind and register our RPC service programs.
      371 + *
      372 + * On TCP or UDP, we may want to bind MOUNTPROG on a specific port
      373 + * (when mountd_port is specified) in which case we'll use the
      374 + * variant of svc_tp_create() that lets us pass a bind address.
      375 + */
      376 +static void
      377 +md_svc_tp_create(struct netconfig *nconf)
      378 +{
      379 +        char port_str[8];
      380 +        struct nd_hostserv hs;
      381 +        struct nd_addrlist *al = NULL;
      382 +        SVCXPRT *xprt = NULL;
      383 +        rpcvers_t vers;
      384 +
      385 +        vers = mount_vers_max;
      386 +
      387 +        /*
      388 +         * If mountd_port is set and this is an inet transport,
      389 +         * bind this service on the specified port.  The TLI way
      390 +         * to create such a bind address is netdir_getbyname()
      391 +         * with the special "host" HOST_SELF_BIND.  This builds
      392 +         * an all-zeros IP address with the specified port.
      393 +         */
      394 +        if (mountd_port != 0 &&
      395 +            (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
      396 +            strcmp(nconf->nc_protofmly, NC_INET6) == 0)) {
      397 +                int err;
      398 +
      399 +                snprintf(port_str, sizeof (port_str), "%u",
      400 +                    (unsigned short)mountd_port);
      401 +
      402 +                hs.h_host = HOST_SELF_BIND;
      403 +                hs.h_serv = port_str;
      404 +                err = netdir_getbyname((struct netconfig *)nconf, &hs, &al);
      405 +                if (err == 0 && al != NULL) {
      406 +                        xprt = svc_tp_create_addr(mnt, MOUNTPROG, vers,
      407 +                            nconf, al->n_addrs);
      408 +                        netdir_free(al, ND_ADDRLIST);
      409 +                }
      410 +                if (xprt == NULL) {
      411 +                        syslog(LOG_ERR, "mountd: unable to create "
      412 +                            "(MOUNTD,%d) on transport %s (port %d)",
      413 +                            vers, nconf->nc_netid, mountd_port);
      414 +                }
      415 +                /* fall-back to default bind */
      416 +        }
      417 +        if (xprt == NULL) {
      418 +                /*
      419 +                 * Had mountd_port=0, or non-inet transport,
      420 +                 * or the bind to a specific port failed.
      421 +                 * Do a default bind.
      422 +                 */
      423 +                xprt = svc_tp_create(mnt, MOUNTPROG, vers, nconf);
      424 +        }
      425 +        if (xprt == NULL) {
      426 +                syslog(LOG_ERR, "mountd: unable to create "
      427 +                    "(MOUNTD,%d) on transport %s",
      428 +                    vers, nconf->nc_netid);
      429 +                return;
      430 +        }
      431 +
      432 +        /*
      433 +         * Register additional versions on this transport.
      434 +         */
      435 +        while (--vers >= mount_vers_min) {
      436 +                if (!svc_reg(xprt, MOUNTPROG, vers, mnt, nconf)) {
      437 +                        (void) syslog(LOG_ERR, "mountd: "
      438 +                            "failed to register vers %d on %s",
      439 +                            vers, nconf->nc_netid);
      440 +                }
      441 +        }
      442 +}
      443 +
 365  444  int
 366  445  main(int argc, char *argv[])
 367  446  {
 368  447          int     pid;
 369  448          int     c;
 370  449          int     rpc_svc_fdunlim = 1;
 371  450          int     rpc_svc_mode = RPC_SVC_MT_AUTO;
 372  451          int     maxrecsz = RPC_MAXDATASIZE;
 373  452          bool_t  exclbind = TRUE;
 374  453          bool_t  can_do_mlp;
 375  454          long    thr_flags = (THR_NEW_LWP|THR_DAEMON);
 376  455          char defval[4];
 377  456          int defvers, ret, bufsz;
 378  457          struct rlimit rl;
 379  458          int listen_backlog = 0;
 380  459          int max_threads = 0;
 381  460          int tmp;
      461 +        struct netconfig *nconf;
      462 +        NCONF_HANDLE *nc;
 382  463  
 383  464          int     pipe_fd = -1;
 384  465  
 385  466          /*
 386  467           * Mountd requires uid 0 for:
 387  468           *      /etc/rmtab updates (we could chown it to daemon)
 388  469           *      /etc/dfs/dfstab reading (it wants to lock out share which
 389  470           *              doesn't do any locking before first truncate;
 390  471           *              NFS share does; should use fcntl locking instead)
 391  472           *      Needed privileges:
 392  473           *              auditing
 393  474           *              nfs syscall
 394  475           *              file dac search (so it can stat all files)
 395  476           *      Optional privileges:
 396  477           *              MLP
 397  478           */
 398  479          can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 399  480          if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
 400  481              PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
      482 +            PRIV_NET_PRIVADDR,
 401  483              can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 402  484                  (void) fprintf(stderr,
 403  485                      "%s: must be run with sufficient privileges\n",
 404  486                      argv[0]);
 405  487                  exit(1);
 406  488          }
 407  489  
 408  490          if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
 409  491                  syslog(LOG_ERR, "getrlimit failed");
 410  492          } else {
↓ open down ↓ 4 lines elided ↑ open up ↑
 415  497  
 416  498          (void) enable_extended_FILE_stdio(-1, -1);
 417  499  
 418  500          ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
 419  501              DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 420  502          if (ret != SA_OK) {
 421  503                  syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
 422  504                      "failed, using default value");
 423  505          }
 424  506  
 425      -        while ((c = getopt(argc, argv, "vrm:")) != EOF) {
      507 +        ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
      508 +            DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
      509 +        if (ret != SA_OK) {
      510 +                syslog(LOG_ERR, "Reading of mountd_port from SMF "
      511 +                    "failed, using default value");
      512 +        }
      513 +
      514 +        while ((c = getopt(argc, argv, "dvrm:p:")) != EOF) {
 426  515                  switch (c) {
      516 +                case 'd':
      517 +                        debug++;
      518 +                        break;
 427  519                  case 'v':
 428  520                          verbose++;
 429  521                          break;
 430  522                  case 'r':
 431  523                          rejecting = 1;
 432  524                          break;
 433  525                  case 'm':
 434  526                          if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
 435  527                                  (void) fprintf(stderr, "%s: invalid "
 436  528                                      "max_threads option, using defaults\n",
 437  529                                      argv[0]);
 438  530                                  break;
 439  531                          }
 440  532                          max_threads = tmp;
 441  533                          break;
      534 +                case 'p':
      535 +                        if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
      536 +                            tmp > UINT16_MAX) {
      537 +                                (void) fprintf(stderr, "%s: invalid port "
      538 +                                    "number\n", argv[0]);
      539 +                                break;
      540 +                        }
      541 +                        mountd_port = tmp;
      542 +                        break;
 442  543                  default:
 443  544                          fprintf(stderr, "usage: mountd [-v] [-r]\n");
 444  545                          exit(1);
 445  546                  }
 446  547          }
 447  548  
 448  549          /*
 449  550           * Read in the NFS version values from config file.
 450  551           */
 451  552          bufsz = 4;
↓ open down ↓ 29 lines elided ↑ open up ↑
 481  582          if (ret != SA_OK) {
 482  583                  syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
 483  584                      "failed, using default value");
 484  585          }
 485  586  
 486  587          /*
 487  588           * Sanity check versions,
 488  589           * even though we may get versions > MOUNTVERS3, we still need
 489  590           * to start nfsauth service, so continue on regardless of values.
 490  591           */
      592 +        if (mount_vers_max > MOUNTVERS3)
      593 +                mount_vers_max = MOUNTVERS3;
 491  594          if (mount_vers_min > mount_vers_max) {
 492  595                  fprintf(stderr, "server_versmin > server_versmax\n");
 493  596                  mount_vers_max = mount_vers_min;
 494  597          }
 495  598          (void) setlocale(LC_ALL, "");
 496  599          (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
 497  600          (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
 498  601          (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
 499  602          (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
 500  603  
 501  604          netgroup_init();
 502  605  
 503  606  #if !defined(TEXT_DOMAIN)
 504  607  #define TEXT_DOMAIN "SYS_TEST"
 505  608  #endif
 506  609          (void) textdomain(TEXT_DOMAIN);
 507  610  
 508  611          /* Don't drop core if the NFS module isn't loaded. */
 509  612          (void) signal(SIGSYS, SIG_IGN);
 510  613  
 511      -        pipe_fd = daemonize_init();
      614 +        if (!debug)
      615 +                pipe_fd = daemonize_init();
 512  616  
 513  617          /*
 514  618           * If we coredump it'll be in /core
 515  619           */
 516  620          if (chdir("/") < 0)
 517  621                  fprintf(stderr, "chdir /: %s\n", strerror(errno));
 518  622  
 519      -        openlog("mountd", LOG_PID, LOG_DAEMON);
      623 +        if (!debug)
      624 +                openlog("mountd", LOG_PID, LOG_DAEMON);
 520  625  
 521  626          /*
 522  627           * establish our lock on the lock file and write our pid to it.
 523  628           * exit if some other process holds the lock, or if there's any
 524  629           * error in writing/locking the file.
 525  630           */
 526  631          pid = _enter_daemon_lock(MOUNTD);
 527  632          switch (pid) {
 528  633          case 0:
 529  634                  break;
↓ open down ↓ 64 lines elided ↑ open up ↑
 594  699  
 595  700          /*
 596  701           * If max_threads was specified, then set the
 597  702           * maximum number of threads to the value specified.
 598  703           */
 599  704          if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
 600  705                  fprintf(stderr, "unable to set max_threads\n");
 601  706                  exit(1);
 602  707          }
 603  708  
      709 +        if (mountd_port < 0 || mountd_port > UINT16_MAX) {
      710 +                fprintf(stderr, "unable to use specified port\n");
      711 +                exit(1);
      712 +        }
      713 +
 604  714          /*
 605  715           * Make sure to unregister any previous versions in case the
 606  716           * user is reconfiguring the server in interesting ways.
 607  717           */
 608  718          svc_unreg(MOUNTPROG, MOUNTVERS);
 609  719          svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
 610  720          svc_unreg(MOUNTPROG, MOUNTVERS3);
 611  721  
 612  722          /*
 613  723           * Create the nfsauth thread with same signal disposition
↓ open down ↓ 24 lines elided ↑ open up ↑
 638  748           * signal disposition as the main thread. We create
 639  749           * a separate thread to allow the mount request threads to
 640  750           * clear as soon as possible.
 641  751           */
 642  752          if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
 643  753                  syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
 644  754                  exit(2);
 645  755          }
 646  756  
 647  757          /*
 648      -         * Create datagram and connection oriented services
      758 +         * Enumerate network transports and create service listeners
      759 +         * as appropriate for each.
 649  760           */
 650      -        if (mount_vers_max >= MOUNTVERS) {
 651      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "datagram_v") == 0) {
 652      -                        fprintf(stderr,
 653      -                            "couldn't register datagram_v MOUNTVERS\n");
 654      -                        exit(1);
 655      -                }
 656      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS, "circuit_v") == 0) {
 657      -                        fprintf(stderr,
 658      -                            "couldn't register circuit_v MOUNTVERS\n");
 659      -                        exit(1);
 660      -                }
      761 +        if ((nc = setnetconfig()) == NULL) {
      762 +                syslog(LOG_ERR, "setnetconfig failed: %m");
      763 +                return (-1);
 661  764          }
      765 +        while ((nconf = getnetconfig(nc)) != NULL) {
      766 +                /*
      767 +                 * Skip things like tpi_raw, invisible...
      768 +                 */
      769 +                if ((nconf->nc_flag & NC_VISIBLE) == 0)
      770 +                        continue;
      771 +                if (nconf->nc_semantics != NC_TPI_CLTS &&
      772 +                    nconf->nc_semantics != NC_TPI_COTS &&
      773 +                    nconf->nc_semantics != NC_TPI_COTS_ORD)
      774 +                        continue;
 662  775  
 663      -        if (mount_vers_max >= MOUNTVERS_POSIX) {
 664      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
 665      -                    "datagram_v") == 0) {
 666      -                        fprintf(stderr,
 667      -                            "couldn't register datagram_v MOUNTVERS_POSIX\n");
 668      -                        exit(1);
 669      -                }
 670      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS_POSIX,
 671      -                    "circuit_v") == 0) {
 672      -                        fprintf(stderr,
 673      -                            "couldn't register circuit_v MOUNTVERS_POSIX\n");
 674      -                        exit(1);
 675      -                }
      776 +                md_svc_tp_create(nconf);
 676  777          }
      778 +        (void) endnetconfig(nc);
 677  779  
 678      -        if (mount_vers_max >= MOUNTVERS3) {
 679      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "datagram_v") == 0) {
 680      -                        fprintf(stderr,
 681      -                            "couldn't register datagram_v MOUNTVERS3\n");
 682      -                        exit(1);
 683      -                }
 684      -                if (svc_create(mnt, MOUNTPROG, MOUNTVERS3, "circuit_v") == 0) {
 685      -                        fprintf(stderr,
 686      -                            "couldn't register circuit_v MOUNTVERS3\n");
 687      -                        exit(1);
 688      -                }
 689      -        }
 690      -
 691  780          /*
 692  781           * Start serving
 693  782           */
 694  783          rmtab_load();
 695  784  
 696  785          daemonize_fini(pipe_fd);
 697  786  
 698  787          /* Get rid of the most dangerous basic privileges. */
 699  788          __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
 700  789              (char *)NULL);
↓ open down ↓ 2560 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX