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>


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.


  25  */
  26 
  27 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * Portions of this source code were derived from Berkeley 4.3 BSD
  32  * under license from the Regents of the University of California.
  33  */
  34 
  35 #include <stdio.h>
  36 #include <stdio_ext.h>
  37 #include <stdlib.h>
  38 #include <ctype.h>
  39 #include <sys/types.h>
  40 #include <string.h>
  41 #include <syslog.h>
  42 #include <sys/param.h>
  43 #include <rpc/rpc.h>
  44 #include <sys/stat.h>


 100 
 101 static mutex_t logging_queue_lock;
 102 static cond_t logging_queue_cv;
 103 
 104 static share_t *find_lofsentry(char *, int *);
 105 static int getclientsflavors_old(share_t *, struct cln *, int *);
 106 static int getclientsflavors_new(share_t *, struct cln *, int *);
 107 static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
 108     gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
 109 static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
 110     gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
 111 static void mnt(struct svc_req *, SVCXPRT *);
 112 static void mnt_pathconf(struct svc_req *);
 113 static int mount(struct svc_req *r);
 114 static void sh_free(struct sh_list *);
 115 static void umount(struct svc_req *);
 116 static void umountall(struct svc_req *);
 117 static int newopts(char *);
 118 static tsol_tpent_t *get_client_template(struct sockaddr *);
 119 

 120 static int verbose;
 121 static int rejecting;
 122 static int mount_vers_min = MOUNTVERS;
 123 static int mount_vers_max = MOUNTVERS3;

 124 
 125 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
 126 
 127 thread_t        nfsauth_thread;
 128 thread_t        cmd_thread;
 129 thread_t        logging_thread;
 130 
 131 typedef struct logging_data {
 132         char                    *ld_host;
 133         char                    *ld_path;
 134         char                    *ld_rpath;
 135         int                     ld_status;
 136         char                    *ld_netid;
 137         struct netbuf           *ld_nb;
 138         struct logging_data     *ld_next;
 139 } logging_data;
 140 
 141 static logging_data *logging_head = NULL;
 142 static logging_data *logging_tail = NULL;
 143 


 345         syslog(LOG_ERR, gettext("Logging server exited"));
 346         return (NULL);
 347 }
 348 
 349 static int
 350 convert_int(int *val, char *str)
 351 {
 352         long lval;
 353 
 354         if (str == NULL || !isdigit(*str))
 355                 return (-1);
 356 
 357         lval = strtol(str, &str, 10);
 358         if (*str != '\0' || lval > INT_MAX)
 359                 return (-2);
 360 
 361         *val = (int)lval;
 362         return (0);
 363 }
 364 












































































 365 int
 366 main(int argc, char *argv[])
 367 {
 368         int     pid;
 369         int     c;
 370         int     rpc_svc_fdunlim = 1;
 371         int     rpc_svc_mode = RPC_SVC_MT_AUTO;
 372         int     maxrecsz = RPC_MAXDATASIZE;
 373         bool_t  exclbind = TRUE;
 374         bool_t  can_do_mlp;
 375         long    thr_flags = (THR_NEW_LWP|THR_DAEMON);
 376         char defval[4];
 377         int defvers, ret, bufsz;
 378         struct rlimit rl;
 379         int listen_backlog = 0;
 380         int max_threads = 0;
 381         int tmp;


 382 
 383         int     pipe_fd = -1;
 384 
 385         /*
 386          * Mountd requires uid 0 for:
 387          *      /etc/rmtab updates (we could chown it to daemon)
 388          *      /etc/dfs/dfstab reading (it wants to lock out share which
 389          *              doesn't do any locking before first truncate;
 390          *              NFS share does; should use fcntl locking instead)
 391          *      Needed privileges:
 392          *              auditing
 393          *              nfs syscall
 394          *              file dac search (so it can stat all files)
 395          *      Optional privileges:
 396          *              MLP
 397          */
 398         can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 399         if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
 400             PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,

 401             can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 402                 (void) fprintf(stderr,
 403                     "%s: must be run with sufficient privileges\n",
 404                     argv[0]);
 405                 exit(1);
 406         }
 407 
 408         if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
 409                 syslog(LOG_ERR, "getrlimit failed");
 410         } else {
 411                 rl.rlim_cur = rl.rlim_max;
 412                 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
 413                         syslog(LOG_ERR, "setrlimit failed");
 414         }
 415 
 416         (void) enable_extended_FILE_stdio(-1, -1);
 417 
 418         ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
 419             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 420         if (ret != SA_OK) {
 421                 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
 422                     "failed, using default value");
 423         }
 424 
 425         while ((c = getopt(argc, argv, "vrm:")) != EOF) {







 426                 switch (c) {



 427                 case 'v':
 428                         verbose++;
 429                         break;
 430                 case 'r':
 431                         rejecting = 1;
 432                         break;
 433                 case 'm':
 434                         if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
 435                                 (void) fprintf(stderr, "%s: invalid "
 436                                     "max_threads option, using defaults\n",
 437                                     argv[0]);
 438                                 break;
 439                         }
 440                         max_threads = tmp;
 441                         break;









 442                 default:
 443                         fprintf(stderr, "usage: mountd [-v] [-r]\n");
 444                         exit(1);
 445                 }
 446         }
 447 
 448         /*
 449          * Read in the NFS version values from config file.
 450          */
 451         bufsz = 4;
 452         ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
 453             SCF_TYPE_INTEGER, NFSD, &bufsz);
 454         if (ret == SA_OK) {
 455                 errno = 0;
 456                 defvers = strtol(defval, (char **)NULL, 10);
 457                 if (errno == 0) {
 458                         mount_vers_min = defvers;
 459                         /*
 460                          * special because NFSv2 is
 461                          * supported by mount v1 & v2


 471         if (ret == SA_OK) {
 472                 errno = 0;
 473                 defvers = strtol(defval, (char **)NULL, 10);
 474                 if (errno == 0) {
 475                         mount_vers_max = defvers;
 476                 }
 477         }
 478 
 479         ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
 480             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 481         if (ret != SA_OK) {
 482                 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
 483                     "failed, using default value");
 484         }
 485 
 486         /*
 487          * Sanity check versions,
 488          * even though we may get versions > MOUNTVERS3, we still need
 489          * to start nfsauth service, so continue on regardless of values.
 490          */


 491         if (mount_vers_min > mount_vers_max) {
 492                 fprintf(stderr, "server_versmin > server_versmax\n");
 493                 mount_vers_max = mount_vers_min;
 494         }
 495         (void) setlocale(LC_ALL, "");
 496         (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
 497         (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
 498         (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
 499         (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
 500 
 501         netgroup_init();
 502 
 503 #if !defined(TEXT_DOMAIN)
 504 #define TEXT_DOMAIN "SYS_TEST"
 505 #endif
 506         (void) textdomain(TEXT_DOMAIN);
 507 
 508         /* Don't drop core if the NFS module isn't loaded. */
 509         (void) signal(SIGSYS, SIG_IGN);
 510 

 511         pipe_fd = daemonize_init();
 512 
 513         /*
 514          * If we coredump it'll be in /core
 515          */
 516         if (chdir("/") < 0)
 517                 fprintf(stderr, "chdir /: %s\n", strerror(errno));
 518 

 519         openlog("mountd", LOG_PID, LOG_DAEMON);
 520 
 521         /*
 522          * establish our lock on the lock file and write our pid to it.
 523          * exit if some other process holds the lock, or if there's any
 524          * error in writing/locking the file.
 525          */
 526         pid = _enter_daemon_lock(MOUNTD);
 527         switch (pid) {
 528         case 0:
 529                 break;
 530         case -1:
 531                 fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
 532                     strerror(errno));
 533                 exit(2);
 534         default:
 535                 /* daemon was already running */
 536                 exit(0);
 537         }
 538 


 584 
 585         /*
 586          * Set the maximum number of outstanding connection
 587          * indications (listen backlog) to the value specified.
 588          */
 589         if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
 590             &listen_backlog)) {
 591                 fprintf(stderr, "unable to set listen backlog\n");
 592                 exit(1);
 593         }
 594 
 595         /*
 596          * If max_threads was specified, then set the
 597          * maximum number of threads to the value specified.
 598          */
 599         if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
 600                 fprintf(stderr, "unable to set max_threads\n");
 601                 exit(1);
 602         }
 603 





 604         /*
 605          * Make sure to unregister any previous versions in case the
 606          * user is reconfiguring the server in interesting ways.
 607          */
 608         svc_unreg(MOUNTPROG, MOUNTVERS);
 609         svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
 610         svc_unreg(MOUNTPROG, MOUNTVERS3);
 611 
 612         /*
 613          * Create the nfsauth thread with same signal disposition
 614          * as the main thread. We need to create a separate thread
 615          * since mountd() will be both an RPC server (for remote
 616          * traffic) _and_ a doors server (for kernel upcalls).
 617          */
 618         if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
 619                 fprintf(stderr,
 620                     gettext("Failed to create NFSAUTH svc thread\n"));
 621                 exit(2);
 622         }
 623 


 628          * traffic) _and_ a doors server (for kernel upcalls).
 629          */
 630         if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
 631                 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
 632                 exit(2);
 633         }
 634 
 635         /*
 636          * Create an additional thread to service the rmtab and
 637          * audit_mountd_mount logging for mount requests. Use the same
 638          * signal disposition as the main thread. We create
 639          * a separate thread to allow the mount request threads to
 640          * clear as soon as possible.
 641          */
 642         if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
 643                 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
 644                 exit(2);
 645         }
 646 
 647         /*
 648          * Create datagram and connection oriented services

 649          */
 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                 }
 661         }




 662 
 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                 }
 676         }
 677 
 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         /*
 692          * Start serving
 693          */
 694         rmtab_load();
 695 
 696         daemonize_fini(pipe_fd);
 697 
 698         /* Get rid of the most dangerous basic privileges. */
 699         __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
 700             (char *)NULL);
 701 
 702         svc_run();
 703         syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
 704         abort();
 705 
 706         /* NOTREACHED */
 707         return (0);
 708 }
 709 
 710 /*




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*

  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.
  26  */
  27 
  28 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  29 /*        All Rights Reserved   */
  30 
  31 /*
  32  * Portions of this source code were derived from Berkeley 4.3 BSD
  33  * under license from the Regents of the University of California.
  34  */
  35 
  36 #include <stdio.h>
  37 #include <stdio_ext.h>
  38 #include <stdlib.h>
  39 #include <ctype.h>
  40 #include <sys/types.h>
  41 #include <string.h>
  42 #include <syslog.h>
  43 #include <sys/param.h>
  44 #include <rpc/rpc.h>
  45 #include <sys/stat.h>


 101 
 102 static mutex_t logging_queue_lock;
 103 static cond_t logging_queue_cv;
 104 
 105 static share_t *find_lofsentry(char *, int *);
 106 static int getclientsflavors_old(share_t *, struct cln *, int *);
 107 static int getclientsflavors_new(share_t *, struct cln *, int *);
 108 static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
 109     gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
 110 static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
 111     gid_t *, uid_t *, gid_t *i, uint_t *, gid_t **);
 112 static void mnt(struct svc_req *, SVCXPRT *);
 113 static void mnt_pathconf(struct svc_req *);
 114 static int mount(struct svc_req *r);
 115 static void sh_free(struct sh_list *);
 116 static void umount(struct svc_req *);
 117 static void umountall(struct svc_req *);
 118 static int newopts(char *);
 119 static tsol_tpent_t *get_client_template(struct sockaddr *);
 120 
 121 static int debug;
 122 static int verbose;
 123 static int rejecting;
 124 static int mount_vers_min = MOUNTVERS;
 125 static int mount_vers_max = MOUNTVERS3;
 126 static int mountd_port = 0;
 127 
 128 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
 129 
 130 thread_t        nfsauth_thread;
 131 thread_t        cmd_thread;
 132 thread_t        logging_thread;
 133 
 134 typedef struct logging_data {
 135         char                    *ld_host;
 136         char                    *ld_path;
 137         char                    *ld_rpath;
 138         int                     ld_status;
 139         char                    *ld_netid;
 140         struct netbuf           *ld_nb;
 141         struct logging_data     *ld_next;
 142 } logging_data;
 143 
 144 static logging_data *logging_head = NULL;
 145 static logging_data *logging_tail = NULL;
 146 


 348         syslog(LOG_ERR, gettext("Logging server exited"));
 349         return (NULL);
 350 }
 351 
 352 static int
 353 convert_int(int *val, char *str)
 354 {
 355         long lval;
 356 
 357         if (str == NULL || !isdigit(*str))
 358                 return (-1);
 359 
 360         lval = strtol(str, &str, 10);
 361         if (*str != '\0' || lval > INT_MAX)
 362                 return (-2);
 363 
 364         *val = (int)lval;
 365         return (0);
 366 }
 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 
 444 int
 445 main(int argc, char *argv[])
 446 {
 447         int     pid;
 448         int     c;
 449         int     rpc_svc_fdunlim = 1;
 450         int     rpc_svc_mode = RPC_SVC_MT_AUTO;
 451         int     maxrecsz = RPC_MAXDATASIZE;
 452         bool_t  exclbind = TRUE;
 453         bool_t  can_do_mlp;
 454         long    thr_flags = (THR_NEW_LWP|THR_DAEMON);
 455         char defval[4];
 456         int defvers, ret, bufsz;
 457         struct rlimit rl;
 458         int listen_backlog = 0;
 459         int max_threads = 0;
 460         int tmp;
 461         struct netconfig *nconf;
 462         NCONF_HANDLE *nc;
 463 
 464         int     pipe_fd = -1;
 465 
 466         /*
 467          * Mountd requires uid 0 for:
 468          *      /etc/rmtab updates (we could chown it to daemon)
 469          *      /etc/dfs/dfstab reading (it wants to lock out share which
 470          *              doesn't do any locking before first truncate;
 471          *              NFS share does; should use fcntl locking instead)
 472          *      Needed privileges:
 473          *              auditing
 474          *              nfs syscall
 475          *              file dac search (so it can stat all files)
 476          *      Optional privileges:
 477          *              MLP
 478          */
 479         can_do_mlp = priv_ineffect(PRIV_NET_BINDMLP);
 480         if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, -1, -1,
 481             PRIV_SYS_NFS, PRIV_PROC_AUDIT, PRIV_FILE_DAC_SEARCH,
 482             PRIV_NET_PRIVADDR,
 483             can_do_mlp ? PRIV_NET_BINDMLP : NULL, NULL) == -1) {
 484                 (void) fprintf(stderr,
 485                     "%s: must be run with sufficient privileges\n",
 486                     argv[0]);
 487                 exit(1);
 488         }
 489 
 490         if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
 491                 syslog(LOG_ERR, "getrlimit failed");
 492         } else {
 493                 rl.rlim_cur = rl.rlim_max;
 494                 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
 495                         syslog(LOG_ERR, "setrlimit failed");
 496         }
 497 
 498         (void) enable_extended_FILE_stdio(-1, -1);
 499 
 500         ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
 501             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 502         if (ret != SA_OK) {
 503                 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
 504                     "failed, using default value");
 505         }
 506 
 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) {
 515                 switch (c) {
 516                 case 'd':
 517                         debug++;
 518                         break;
 519                 case 'v':
 520                         verbose++;
 521                         break;
 522                 case 'r':
 523                         rejecting = 1;
 524                         break;
 525                 case 'm':
 526                         if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
 527                                 (void) fprintf(stderr, "%s: invalid "
 528                                     "max_threads option, using defaults\n",
 529                                     argv[0]);
 530                                 break;
 531                         }
 532                         max_threads = tmp;
 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;
 543                 default:
 544                         fprintf(stderr, "usage: mountd [-v] [-r]\n");
 545                         exit(1);
 546                 }
 547         }
 548 
 549         /*
 550          * Read in the NFS version values from config file.
 551          */
 552         bufsz = 4;
 553         ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,
 554             SCF_TYPE_INTEGER, NFSD, &bufsz);
 555         if (ret == SA_OK) {
 556                 errno = 0;
 557                 defvers = strtol(defval, (char **)NULL, 10);
 558                 if (errno == 0) {
 559                         mount_vers_min = defvers;
 560                         /*
 561                          * special because NFSv2 is
 562                          * supported by mount v1 & v2


 572         if (ret == SA_OK) {
 573                 errno = 0;
 574                 defvers = strtol(defval, (char **)NULL, 10);
 575                 if (errno == 0) {
 576                         mount_vers_max = defvers;
 577                 }
 578         }
 579 
 580         ret = nfs_smf_get_iprop("mountd_listen_backlog", &listen_backlog,
 581             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 582         if (ret != SA_OK) {
 583                 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
 584                     "failed, using default value");
 585         }
 586 
 587         /*
 588          * Sanity check versions,
 589          * even though we may get versions > MOUNTVERS3, we still need
 590          * to start nfsauth service, so continue on regardless of values.
 591          */
 592         if (mount_vers_max > MOUNTVERS3)
 593                 mount_vers_max = MOUNTVERS3;
 594         if (mount_vers_min > mount_vers_max) {
 595                 fprintf(stderr, "server_versmin > server_versmax\n");
 596                 mount_vers_max = mount_vers_min;
 597         }
 598         (void) setlocale(LC_ALL, "");
 599         (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
 600         (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
 601         (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
 602         (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
 603 
 604         netgroup_init();
 605 
 606 #if !defined(TEXT_DOMAIN)
 607 #define TEXT_DOMAIN "SYS_TEST"
 608 #endif
 609         (void) textdomain(TEXT_DOMAIN);
 610 
 611         /* Don't drop core if the NFS module isn't loaded. */
 612         (void) signal(SIGSYS, SIG_IGN);
 613 
 614         if (!debug)
 615                 pipe_fd = daemonize_init();
 616 
 617         /*
 618          * If we coredump it'll be in /core
 619          */
 620         if (chdir("/") < 0)
 621                 fprintf(stderr, "chdir /: %s\n", strerror(errno));
 622 
 623         if (!debug)
 624                 openlog("mountd", LOG_PID, LOG_DAEMON);
 625 
 626         /*
 627          * establish our lock on the lock file and write our pid to it.
 628          * exit if some other process holds the lock, or if there's any
 629          * error in writing/locking the file.
 630          */
 631         pid = _enter_daemon_lock(MOUNTD);
 632         switch (pid) {
 633         case 0:
 634                 break;
 635         case -1:
 636                 fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
 637                     strerror(errno));
 638                 exit(2);
 639         default:
 640                 /* daemon was already running */
 641                 exit(0);
 642         }
 643 


 689 
 690         /*
 691          * Set the maximum number of outstanding connection
 692          * indications (listen backlog) to the value specified.
 693          */
 694         if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
 695             &listen_backlog)) {
 696                 fprintf(stderr, "unable to set listen backlog\n");
 697                 exit(1);
 698         }
 699 
 700         /*
 701          * If max_threads was specified, then set the
 702          * maximum number of threads to the value specified.
 703          */
 704         if (max_threads > 0 && !rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
 705                 fprintf(stderr, "unable to set max_threads\n");
 706                 exit(1);
 707         }
 708 
 709         if (mountd_port < 0 || mountd_port > UINT16_MAX) {
 710                 fprintf(stderr, "unable to use specified port\n");
 711                 exit(1);
 712         }
 713 
 714         /*
 715          * Make sure to unregister any previous versions in case the
 716          * user is reconfiguring the server in interesting ways.
 717          */
 718         svc_unreg(MOUNTPROG, MOUNTVERS);
 719         svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
 720         svc_unreg(MOUNTPROG, MOUNTVERS3);
 721 
 722         /*
 723          * Create the nfsauth thread with same signal disposition
 724          * as the main thread. We need to create a separate thread
 725          * since mountd() will be both an RPC server (for remote
 726          * traffic) _and_ a doors server (for kernel upcalls).
 727          */
 728         if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
 729                 fprintf(stderr,
 730                     gettext("Failed to create NFSAUTH svc thread\n"));
 731                 exit(2);
 732         }
 733 


 738          * traffic) _and_ a doors server (for kernel upcalls).
 739          */
 740         if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
 741                 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
 742                 exit(2);
 743         }
 744 
 745         /*
 746          * Create an additional thread to service the rmtab and
 747          * audit_mountd_mount logging for mount requests. Use the same
 748          * signal disposition as the main thread. We create
 749          * a separate thread to allow the mount request threads to
 750          * clear as soon as possible.
 751          */
 752         if (thr_create(NULL, 0, logging_svc, 0, thr_flags, &logging_thread)) {
 753                 syslog(LOG_ERR, gettext("Failed to create LOGGING svc thread"));
 754                 exit(2);
 755         }
 756 
 757         /*
 758          * Enumerate network transports and create service listeners
 759          * as appropriate for each.
 760          */
 761         if ((nc = setnetconfig()) == NULL) {
 762                 syslog(LOG_ERR, "setnetconfig failed: %m");
 763                 return (-1);


 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;
 775 
 776                 md_svc_tp_create(nconf);





 777         }
 778         (void) endnetconfig(nc);






 779 













 780         /*
 781          * Start serving
 782          */
 783         rmtab_load();
 784 
 785         daemonize_fini(pipe_fd);
 786 
 787         /* Get rid of the most dangerous basic privileges. */
 788         __fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_INFO, PRIV_PROC_SESSION,
 789             (char *)NULL);
 790 
 791         svc_run();
 792         syslog(LOG_ERR, "Error: svc_run shouldn't have returned");
 793         abort();
 794 
 795         /* NOTREACHED */
 796         return (0);
 797 }
 798 
 799 /*