Print this page
NEX-6532 allow specifying individual IP addresses without @ prefix in NFS access lists
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
NEX-6673 possible NULL pointer dereference in mountd`mount
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Alex Deiter <alex.deiter@nexenta.com>
NEX-4116 mountd: The IP to name translation is usually not needed in nfsauth_access()
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-4603 mountd: Compile warnings cleanup
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-2614 Add non-interactive mode for ypinit
NEX-2394 mountd() door services are sub-optimal in large... (redux)
NEX-1974 Support for more than 16 groups with AUTH_SYS
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-2394 mountd() door services are sub-optimal in large scale deployments
NEX-2526 mountd consumes an inordinate amount of memory
NEX-2502 4.0.3 RC4 Unable to mount NFS shares
Revert "NEX-2394 mountd() door services are sub-optimal in large scale deployments".
This reverts commit c6e1673e3a4b8ba866c77dee7b8f03f858be07d6.
The fix for NEX-2394 worked fine when putting the mountd binary in 4.0.2,
but needs additional work in a 4.0.3 environment
NEX-2394 mountd() door services are sub-optimal in large scale deployments
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Ryuji Masuda <ryuji.masuda@nexenta.com>
Reviewed by: Kirill Davydychev <kirill.davydychev@nexenta.com>
NEX-1128 NFS server: Generic uid and gid remapping for AUTH_SYS
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
OS-141 mountd(1m) needs to be able to set listen backlog
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
OS-134 mountd(1m): Remove limit of FDs in RPC server
Reviewed by: Michael Tsymbalyuk <michael.tsymbalyuk@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
OS-133 mountd: Busy do_logging_queue() eats memory
Reviewed by: Michael Tsymbalyuk <michael.tsymbalyuk@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
OS-131 mountd(1m) leaks nd_hostservlist in do_logging_queue()
Reviewed by: Ilya Usvyatsky <ilya.usvyatsky@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
OS-20 share_nfs(1m) charset handling is unreliable
OS-22 Page fault at nfscmd_dropped_entrysize+0x1e()
OS-23 NFSv2/3/4: READDIR responses are inconsistent when charset conversion fails
OS-24 rfs3_readdir(): Issues related to nfscmd_convdirent()
Reviewed by: Jan Kryl <jan.kryl@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>


   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>
  46 #include <netconfig.h>
  47 #include <netdir.h>
  48 #include <sys/file.h>
  49 #include <sys/time.h>
  50 #include <sys/errno.h>
  51 #include <rpcsvc/mount.h>
  52 #include <sys/pathconf.h>
  53 #include <sys/systeminfo.h>
  54 #include <sys/utsname.h>
  55 #include <sys/wait.h>
  56 #include <sys/resource.h>
  57 #include <signal.h>
  58 #include <locale.h>
  59 #include <unistd.h>
  60 #include <errno.h>
  61 #include <sys/socket.h>
  62 #include <netinet/in.h>
  63 #include <arpa/inet.h>
  64 #include <netdb.h>
  65 #include <thread.h>

  66 #include <assert.h>
  67 #include <priv_utils.h>
  68 #include <nfs/auth.h>
  69 #include <nfs/nfssys.h>
  70 #include <nfs/nfs.h>
  71 #include <nfs/nfs_sec.h>
  72 #include <rpcsvc/daemon_utils.h>
  73 #include <deflt.h>
  74 #include "../../fslib.h"
  75 #include <sharefs/share.h>
  76 #include <sharefs/sharetab.h>
  77 #include "../lib/sharetab.h"
  78 #include "mountd.h"
  79 #include <tsol/label.h>
  80 #include <sys/tsol/label_macro.h>
  81 #include <libtsnet.h>
  82 #include <sys/sdt.h>
  83 #include <libscf.h>
  84 #include <limits.h>
  85 #include <sys/nvpair.h>
  86 #include <attr.h>
  87 #include "smfcfg.h"
  88 #include <pwd.h>
  89 #include <grp.h>
  90 #include <alloca.h>

  91 
  92 extern int daemonize_init(void);
  93 extern void daemonize_fini(int);
  94 
  95 extern int _nfssys(int, void *);
  96 
  97 struct sh_list *share_list;
  98 
  99 rwlock_t sharetab_lock;         /* lock to protect the cached sharetab */
 100 static mutex_t mnttab_lock;     /* prevent concurrent mnttab readers */
 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,


 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 

















 147 /*
 148  * Our copy of some system variables obtained using sysconf(3c)
 149  */
 150 static long ngroups_max;        /* _SC_NGROUPS_MAX */
 151 static long pw_size;            /* _SC_GETPW_R_SIZE_MAX */
 152 












































































































































 153 /* ARGSUSED */
 154 static void *
 155 nfsauth_svc(void *arg)
 156 {
 157         int     doorfd = -1;
 158         uint_t  darg;

 159 #ifdef DEBUG
 160         int     dfd;
 161 #endif
 162 
 163         if ((doorfd = door_create(nfsauth_func, NULL,
 164             DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
 165                 syslog(LOG_ERR, "Unable to create door: %m\n");




 166                 exit(10);
 167         }
 168 
 169 #ifdef DEBUG
 170         /*
 171          * Create a file system path for the door
 172          */
 173         if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
 174             S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
 175                 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
 176                 (void) close(doorfd);
 177                 exit(11);
 178         }
 179 
 180         /*
 181          * Clean up any stale namespace associations
 182          */
 183         (void) fdetach(MOUNTD_DOOR);
 184 
 185         /*
 186          * Register in namespace to pass to the kernel to door_ki_open
 187          */
 188         if (fattach(doorfd, MOUNTD_DOOR) == -1) {
 189                 syslog(LOG_ERR, "Unable to fattach door: %m\n");
 190                 (void) close(dfd);
 191                 (void) close(doorfd);
 192                 exit(12);
 193         }
 194         (void) close(dfd);
 195 #endif
 196 
 197         /*
 198          * Must pass the doorfd down to the kernel.
 199          */
 200         darg = doorfd;
 201         (void) _nfssys(MOUNTD_ARGS, &darg);
 202 
 203         /*







 204          * Wait for incoming calls
 205          */
 206         /*CONSTCOND*/
 207         for (;;)
 208                 (void) pause();
 209 
 210         /*NOTREACHED*/
 211         syslog(LOG_ERR, gettext("Door server exited"));
 212         return (NULL);
 213 }
 214 
 215 /*
 216  * NFS command service thread code for setup and handling of the
 217  * nfs_cmd requests for character set conversion and other future
 218  * events.
 219  */
 220 
 221 static void *
 222 cmd_svc(void *arg)
 223 {
 224         int     doorfd = -1;
 225         uint_t  darg;

 226 
 227         if ((doorfd = door_create(nfscmd_func, NULL,
 228             DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {




 229                 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
 230                 exit(10);
 231         }
 232 
 233         /*
 234          * Must pass the doorfd down to the kernel.
 235          */
 236         darg = doorfd;
 237         (void) _nfssys(NFSCMD_ARGS, &darg);
 238 
 239         /*







 240          * Wait for incoming calls
 241          */
 242         /*CONSTCOND*/
 243         for (;;)
 244                 (void) pause();
 245 
 246         /*NOTREACHED*/
 247         syslog(LOG_ERR, gettext("Cmd door server exited"));
 248         return (NULL);
 249 }
 250 
 251 static void
 252 free_logging_data(logging_data *lq)
 253 {


 254         if (lq != NULL) {
 255                 free(lq->ld_host);
 256                 free(lq->ld_netid);
 257 
 258                 if (lq->ld_nb != NULL) {
 259                         free(lq->ld_nb->buf);
 260                         free(lq->ld_nb);
 261                 }
 262 
 263                 free(lq->ld_path);
 264                 free(lq->ld_rpath);
 265 
 266                 free(lq);
 267         }
 268 }
 269 
 270 static logging_data *
 271 remove_head_of_queue(void)
 272 {
 273         logging_data    *lq;
 274 


 275         /*
 276          * Pull it off the queue.
 277          */
 278         lq = logging_head;
 279         if (lq) {
 280                 logging_head = lq->ld_next;
 281 
 282                 /*
 283                  * Drained it.
 284                  */
 285                 if (logging_head == NULL) {
 286                         logging_tail = NULL;
 287                 }
 288         }
 289 
 290         return (lq);
 291 }
 292 
 293 static void
 294 do_logging_queue(logging_data *lq)
 295 {
 296         int             cleared = 0;
 297         char            *host;
 298 


 299         while (lq) {
 300                 struct cln cln;
 301 
 302                 if (lq->ld_host == NULL) {
 303                         DTRACE_PROBE(mountd, name_by_lazy);
 304                         cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
 305                         host = cln_gethost(&cln);
 306                 } else
 307                         host = lq->ld_host;
 308 
 309                 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
 310 
 311                 /* add entry to mount list */
 312                 if (lq->ld_rpath)
 313                         mntlist_new(host, lq->ld_rpath);
 314 
 315                 if (lq->ld_host == NULL)
 316                         cln_fini(&cln);
 317 
 318                 free_logging_data(lq);
 319                 cleared++;
 320 
 321                 (void) mutex_lock(&logging_queue_lock);
 322                 lq = remove_head_of_queue();
 323                 (void) mutex_unlock(&logging_queue_lock);
 324         }
 325 
 326         DTRACE_PROBE1(mountd, logging_cleared, cleared);
 327 }
 328 
 329 static void *
 330 logging_svc(void *arg)
 331 {
 332         logging_data    *lq;
 333 


 334         for (;;) {
 335                 (void) mutex_lock(&logging_queue_lock);
 336                 while (logging_head == NULL) {
 337                         (void) cond_wait(&logging_queue_cv,
 338                             &logging_queue_lock);
 339                 }
 340 
 341                 lq = remove_head_of_queue();
 342                 (void) mutex_unlock(&logging_queue_lock);
 343 
 344                 do_logging_queue(lq);
 345         }
 346 
 347         /*NOTREACHED*/
 348         syslog(LOG_ERR, gettext("Logging server exited"));
 349         return (NULL);
 350 }
 351 
 352 static int
 353 convert_int(int *val, char *str)


 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,


 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 


 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 

 644         audit_mountd_setup();   /* BSM */
 645 
 646         /*
 647          * Get required system variables
 648          */
 649         if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
 650                 syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
 651                 exit(1);
 652         }
 653         if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
 654                 syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
 655                 exit(1);
 656         }
 657 
 658         /*
 659          * Set number of file descriptors to unlimited
 660          */
 661         if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
 662                 syslog(LOG_INFO, "unable to set number of FDs to unlimited");
 663         }


 684          * from being hijacked by a bind to a more specific addr.
 685          */
 686         if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
 687                 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
 688         }
 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 
 734         /*
 735          * Create the cmd service thread with same signal disposition
 736          * as the main thread. We need to create a separate thread
 737          * since mountd() will be both an RPC server (for remote
 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 


 835                         mnt_pathconf(rqstp);
 836                 else
 837                         svcerr_noproc(transp);
 838                 return;
 839 
 840         default:
 841                 svcerr_noproc(transp);
 842                 return;
 843         }
 844 }
 845 
 846 void
 847 log_cant_reply_cln(struct cln *cln)
 848 {
 849         int saverrno;
 850         char *host;
 851 
 852         saverrno = errno;       /* save error code */
 853 
 854         host = cln_gethost(cln);
 855         if (host == NULL)
 856                 return;
 857 
 858         errno = saverrno;
 859         if (errno == 0)
 860                 syslog(LOG_ERR, "couldn't send reply to %s", host);
 861         else
 862                 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
 863 }
 864 
 865 void
 866 log_cant_reply(SVCXPRT *transp)
 867 {
 868         int saverrno;
 869         struct cln cln;
 870 
 871         saverrno = errno;       /* save error code */
 872         cln_init(&cln, transp);
 873         errno = saverrno;
 874 
 875         log_cant_reply_cln(&cln);
 876 


1061         }
1062 
1063         if (sh)
1064                 sharefree(sh);
1065         free(checkpath);
1066         return (reply_error);
1067 }
1068 
1069 /*
1070  * We need to inform the caller whether or not we were
1071  * able to add a node to the queue. If we are not, then
1072  * it is up to the caller to go ahead and log the data.
1073  */
1074 static int
1075 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1076     char *rpath, int status, int error)
1077 {
1078         logging_data    *lq;
1079         struct netbuf   *nb;
1080 


1081         lq = (logging_data *)calloc(1, sizeof (logging_data));
1082         if (lq == NULL)
1083                 goto cleanup;
1084 
1085         /*
1086          * We might not yet have the host...
1087          */
1088         if (host) {
1089                 DTRACE_PROBE1(mountd, log_host, host);
1090                 lq->ld_host = strdup(host);
1091                 if (lq->ld_host == NULL)
1092                         goto cleanup;
1093         } else {
1094                 DTRACE_PROBE(mountd, log_no_host);
1095 
1096                 lq->ld_netid = strdup(transp->xp_netid);
1097                 if (lq->ld_netid == NULL)
1098                         goto cleanup;
1099 
1100                 lq->ld_nb = calloc(1, sizeof (struct netbuf));


1138         if (logging_tail == NULL) {
1139                 logging_tail = logging_head = lq;
1140         } else {
1141                 logging_tail->ld_next = lq;
1142                 logging_tail = lq;
1143         }
1144         (void) cond_signal(&logging_queue_cv);
1145         (void) mutex_unlock(&logging_queue_lock);
1146 
1147         return (TRUE);
1148 
1149 cleanup:
1150 
1151         free_logging_data(lq);
1152 
1153         return (FALSE);
1154 }
1155 
1156 
1157 #define CLN_CLNAMES     (1 << 0)
1158 #define CLN_HOST        (1 << 1)
1159 
1160 static void
1161 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1162     struct netbuf *nbuf)
1163 {
1164         if ((cln->transp = transp) != NULL) {
1165                 assert(netid == NULL && nbuf == NULL);
1166                 cln->netid = transp->xp_netid;
1167                 cln->nbuf = svc_getrpccaller(transp);
1168         } else {
1169                 cln->netid = netid;
1170                 cln->nbuf = nbuf;
1171         }
1172 
1173         cln->nconf = NULL;
1174         cln->clnames = NULL;
1175         cln->host = NULL;
1176 
1177         cln->flags = 0;






















1178 }
1179 
1180 void
1181 cln_init(struct cln *cln, SVCXPRT *transp)
1182 {
1183         cln_init_common(cln, transp, NULL, NULL);
1184 }
1185 
1186 void
1187 cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1188 {
1189         cln_init_common(cln, NULL, netid, nbuf);
1190 }
1191 
1192 void
1193 cln_fini(struct cln *cln)
1194 {
1195         if (cln->nconf != NULL)
1196                 freenetconfigent(cln->nconf);
1197 
1198         if (cln->clnames != NULL)
1199                 netdir_free(cln->clnames, ND_HOSTSERVLIST);
1200 
1201         free(cln->host);
1202 }
1203 
1204 struct netbuf *
1205 cln_getnbuf(struct cln *cln)
1206 {
1207         return (cln->nbuf);
1208 }
1209 
1210 struct nd_hostservlist *
1211 cln_getclientsnames(struct cln *cln)
1212 {
1213         if ((cln->flags & CLN_CLNAMES) == 0) {
1214                 /*
1215                  * nconf is not needed if we do not have nbuf (see
1216                  * cln_gethost() too), so we check for nbuf and in a case it is
1217                  * NULL we do not try to get nconf.
1218                  */
1219                 if (cln->netid != NULL && cln->nbuf != NULL) {
1220                         cln->nconf = getnetconfigent(cln->netid);
1221                         if (cln->nconf == NULL)
1222                                 syslog(LOG_ERR, "%s: getnetconfigent failed",
1223                                     cln->netid);
1224                 }
1225 
1226                 if (cln->nconf != NULL && cln->nbuf != NULL)
1227                         (void) __netdir_getbyaddr_nosrv(cln->nconf,
1228                             &cln->clnames, cln->nbuf);
1229 
1230                 cln->flags |= CLN_CLNAMES;
1231         }
1232 
1233         return (cln->clnames);
1234 }
1235 
1236 /*
1237  * Return B_TRUE if the host is already available at no cost
1238  */
1239 boolean_t
1240 cln_havehost(struct cln *cln)
1241 {
1242         return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1243 }
1244 
1245 char *
1246 cln_gethost(struct cln *cln)
1247 {
1248         if (cln_getclientsnames(cln) != NULL)
1249                 return (cln->clnames->h_hostservs[0].h_host);
1250 
1251         if ((cln->flags & CLN_HOST) == 0) {
1252                 if (cln->nconf == NULL || cln->nbuf == NULL) {
1253                         cln->host = strdup("(anon)");
1254                 } else {
1255                         char host[MAXIPADDRLEN];
1256 
1257                         if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1258                                 struct sockaddr_in *sa;
1259 
1260                                 /* LINTED pointer alignment */
1261                                 sa = (struct sockaddr_in *)(cln->nbuf->buf);
1262                                 (void) inet_ntoa_r(sa->sin_addr, host);
1263 
1264                                 cln->host = strdup(host);
1265                         } else if (strcmp(cln->nconf->nc_protofmly,
1266                             NC_INET6) == 0) {
1267                                 struct sockaddr_in6 *sa;
1268 
1269                                 /* LINTED pointer alignment */
1270                                 sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1271                                 (void) inet_ntop(AF_INET6,
1272                                     sa->sin6_addr.s6_addr,
1273                                     host, INET6_ADDRSTRLEN);
1274 
1275                                 cln->host = strdup(host);
1276                         } else {
1277                                 syslog(LOG_ERR, gettext("Client's address is "
1278                                     "neither IPv4 nor IPv6"));
1279 
1280                                 cln->host = strdup("(anon)");
1281                         }
1282                 }
1283 
1284                 cln->flags |= CLN_HOST;
1285         }
1286 
1287         return (cln->host);
1288 }
1289 
1290 /*
1291  * Check mount requests, add to mounted list if ok
1292  */
1293 static int
1294 mount(struct svc_req *rqstp)
1295 {
1296         SVCXPRT *transp;
1297         int version, vers;
1298         struct fhstatus fhs;
1299         struct mountres3 mountres3;
1300         char fh[FHSIZE3];
1301         int len = FHSIZE3;
1302         char *path, rpath[MAXPATHLEN];
1303         share_t *sh = NULL;
1304         struct cln cln;
1305         char *host = NULL;
1306         int error = 0, lofs_tried = 0, enqueued;


1313         transp = rqstp->rq_xprt;
1314         version = rqstp->rq_vers;
1315         path = NULL;
1316 
1317         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1318                 svcerr_decode(transp);
1319                 return (EACCES);
1320         }
1321 
1322         cln_init(&cln, transp);
1323 
1324         /*
1325          * Put off getting the name for the client until we
1326          * need it. This is a performance gain. If we are logging,
1327          * then we don't care about performance and might as well
1328          * get the host name now in case we need to spit out an
1329          * error message.
1330          */
1331         if (verbose) {
1332                 DTRACE_PROBE(mountd, name_by_verbose);
1333                 if ((host = cln_gethost(&cln)) == NULL) {
1334                         /*
1335                          * We failed to get a name for the client, even
1336                          * 'anon', probably because we ran out of memory.
1337                          * In this situation it doesn't make sense to
1338                          * allow the mount to succeed.
1339                          */
1340                         error = EACCES;
1341                         goto reply;
1342                 }
1343         }
1344 
1345         /*
1346          * If the version being used is less than the minimum version,
1347          * the filehandle translation should not be provided to the
1348          * client.
1349          */
1350         if (rejecting || version < mount_vers_min) {
1351                 if (verbose)
1352                         syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1353                             host, path);
1354                 error = EACCES;
1355                 goto reply;
1356         }
1357 
1358         /*
1359          * Trusted Extension doesn't support nfsv2. nfsv2 client
1360          * uses MOUNT protocol v1 and v2. To prevent circumventing
1361          * TX label policy via using nfsv2 client, reject a mount
1362          * request with version less than 3 and log an error.
1363          */


1528                 break;
1529 
1530         case MOUNTVERS3:
1531                 if (!error) {
1532                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1533                     flavor_list;
1534                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1535                     flavor_count;
1536 
1537                 } else if (error == ENAMETOOLONG)
1538                         error = MNT3ERR_NAMETOOLONG;
1539 
1540                 mountres3.fhs_status = error;
1541                 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1542                         log_cant_reply_cln(&cln);
1543 
1544                 audit_status = mountres3.fhs_status;
1545                 break;
1546         }
1547 
1548         if (cln_havehost(&cln))
1549                 host = cln_gethost(&cln);
1550 
1551         if (verbose)
1552                 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1553                     (host == NULL) ? "unknown host" : host,
1554                     error ? "denied" : "mounted", path);
1555 

1556         /*
1557          * If we can not create a queue entry, go ahead and do it
1558          * in the context of this thread.
1559          */
1560         enqueued = enqueue_logging_data(host, transp, path, rpath,
1561             audit_status, error);
1562         if (enqueued == FALSE) {
1563                 if (host == NULL) {
1564                         DTRACE_PROBE(mountd, name_by_in_thread);
1565                         host = cln_gethost(&cln);
1566                 }
1567 

1568                 DTRACE_PROBE(mountd, logged_in_thread);
1569                 audit_mountd_mount(host, path, audit_status); /* BSM */
1570                 if (!error)
1571                         mntlist_new(host, rpath); /* add entry to mount list */
1572         }

1573 





1574         if (path != NULL)
1575                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1576 
1577         if (sh)
1578                 sharefree(sh);
1579 
1580         cln_fini(&cln);
1581 
1582         return (error);
1583 }
1584 
1585 /*
1586  * Determine whether two paths are within the same file system.
1587  * Returns nonzero (true) if paths are the same, zero (false) if
1588  * they are different.  If an error occurs, return false.
1589  *
1590  * Use the actual FSID if it's available (via getattrat()); otherwise,
1591  * fall back on st_dev.
1592  *
1593  * With ZFS snapshots, st_dev differs from the regular file system


1958                                         }
1959                                 }
1960                         } else {
1961                                 ret = inet_matchaddr(pnb->buf, gr);
1962                                 if (ret == -1) {
1963                                         if (errno == EINVAL) {
1964                                                 syslog(LOG_WARNING,
1965                                                     "invalid access list "
1966                                                     "entry: %s", gr);
1967                                         }
1968                                         return (-1);
1969                                 } else if (ret == 1) {
1970                                         return (response);
1971                                 }
1972                         }
1973 
1974                         goto next;
1975                 }
1976 
1977                 /*







1978                  * No other checks can be performed if client address
1979                  * can't be resolved.
1980                  */
1981                 if ((clnames = cln_getclientsnames(cln)) == NULL)
1982                         goto next;
1983 
1984                 /* Otherwise loop through all client hostname aliases */
1985                 for (i = 0; i < clnames->h_cnt; i++) {
1986                         char *host = clnames->h_hostservs[i].h_host;
1987 
1988                         /*
1989                          * If the list name begins with a dot then
1990                          * do a domain name suffix comparison.
1991                          * A single dot matches any name with no
1992                          * suffix.
1993                          */
1994                         if (*gr == '.') {
1995                                 if (*(gr + 1) == '\0') {  /* single dot */
1996                                         if (strchr(host, '.') == NULL)
1997                                                 return (response);


3208 {
3209         char *host, *path, *remove_path;
3210         char rpath[MAXPATHLEN];
3211         SVCXPRT *transp;
3212         struct cln cln;
3213 
3214         transp = rqstp->rq_xprt;
3215         path = NULL;
3216         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3217                 svcerr_decode(transp);
3218                 return;
3219         }
3220 
3221         cln_init(&cln, transp);
3222 
3223         errno = 0;
3224         if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3225                 log_cant_reply_cln(&cln);
3226 
3227         host = cln_gethost(&cln);
3228         if (host == NULL) {
3229                 /*
3230                  * Without the hostname we can't do audit or delete
3231                  * this host from the mount entries.
3232                  */
3233                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3234                 return;
3235         }
3236 
3237         if (verbose)
3238                 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3239 

3240         audit_mountd_umount(host, path);
3241 
3242         remove_path = rpath;    /* assume we will use the cannonical path */
3243         if (realpath(path, rpath) == NULL) {
3244                 if (verbose)
3245                         syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3246                 remove_path = path;     /* use path provided instead */
3247         }
3248 
3249         mntlist_delete(host, remove_path);      /* remove from mount list */
3250 
3251         cln_fini(&cln);
3252 
3253         svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3254 }
3255 
3256 /*
3257  * Remove all entries for one machine from mounted list
3258  */
3259 static void


3262         SVCXPRT *transp;
3263         char *host;
3264         struct cln cln;
3265 
3266         transp = rqstp->rq_xprt;
3267         if (!svc_getargs(transp, xdr_void, NULL)) {
3268                 svcerr_decode(transp);
3269                 return;
3270         }
3271         /*
3272          * We assume that this call is asynchronous and made via rpcbind
3273          * callit routine.  Therefore return control immediately. The error
3274          * causes rpcbind to remain silent, as opposed to every machine
3275          * on the net blasting the requester with a response.
3276          */
3277         svcerr_systemerr(transp);
3278 
3279         cln_init(&cln, transp);
3280 
3281         host = cln_gethost(&cln);
3282         if (host == NULL) {
3283                 /* Can't do anything without the name of the client */
3284                 return;
3285         }
3286 
3287         /*
3288          * Remove all hosts entries from mount list
3289          */
3290         mntlist_delete_all(host);
3291 
3292         if (verbose)
3293                 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3294 
3295         cln_fini(&cln);
3296 }
3297 
3298 void *
3299 exmalloc(size_t size)
3300 {
3301         void *ret;
3302 
3303         if ((ret = malloc(size)) == NULL) {
3304                 syslog(LOG_ERR, "Out of memory");
3305                 exit(1);




   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 2016 Nexenta Systems, Inc.
  25  * Copyright (c) 2012, 2016 by Delphix. 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>
  46 #include <netconfig.h>
  47 #include <netdir.h>
  48 #include <sys/file.h>
  49 #include <sys/time.h>
  50 #include <sys/errno.h>
  51 #include <rpcsvc/mount.h>
  52 #include <sys/pathconf.h>
  53 #include <sys/systeminfo.h>
  54 #include <sys/utsname.h>
  55 #include <sys/wait.h>
  56 #include <sys/resource.h>
  57 #include <signal.h>
  58 #include <locale.h>
  59 #include <unistd.h>
  60 #include <errno.h>
  61 #include <sys/socket.h>
  62 #include <netinet/in.h>
  63 #include <arpa/inet.h>
  64 #include <netdb.h>
  65 #include <thread.h>
  66 #include <pthread.h>
  67 #include <assert.h>
  68 #include <priv_utils.h>
  69 #include <nfs/auth.h>
  70 #include <nfs/nfssys.h>
  71 #include <nfs/nfs.h>
  72 #include <nfs/nfs_sec.h>
  73 #include <rpcsvc/daemon_utils.h>
  74 #include <deflt.h>
  75 #include "../../fslib.h"
  76 #include <sharefs/share.h>
  77 #include <sharefs/sharetab.h>
  78 #include "../lib/sharetab.h"
  79 #include "mountd.h"
  80 #include <tsol/label.h>
  81 #include <sys/tsol/label_macro.h>
  82 #include <libtsnet.h>
  83 #include <sys/sdt.h>
  84 #include <libscf.h>
  85 #include <limits.h>
  86 #include <sys/nvpair.h>
  87 #include <attr.h>
  88 #include "smfcfg.h"
  89 #include <pwd.h>
  90 #include <grp.h>
  91 #include <alloca.h>
  92 #include <atomic.h>
  93 
  94 extern int daemonize_init(void);
  95 extern void daemonize_fini(int);
  96 
  97 extern int _nfssys(int, void *);
  98 
  99 struct sh_list *share_list;
 100 
 101 rwlock_t sharetab_lock;         /* lock to protect the cached sharetab */
 102 static mutex_t mnttab_lock;     /* prevent concurrent mnttab readers */
 103 
 104 static mutex_t logging_queue_lock;
 105 static cond_t logging_queue_cv;
 106 
 107 static share_t *find_lofsentry(char *, int *);
 108 static int getclientsflavors_old(share_t *, struct cln *, int *);
 109 static int getclientsflavors_new(share_t *, struct cln *, int *);
 110 static int check_client_old(share_t *, struct cln *, int, uid_t, gid_t, uint_t,
 111     gid_t *, uid_t *, gid_t *, uint_t *, gid_t **);
 112 static int check_client_new(share_t *, struct cln *, int, uid_t, gid_t, uint_t,


 114 static void mnt(struct svc_req *, SVCXPRT *);
 115 static void mnt_pathconf(struct svc_req *);
 116 static int mount(struct svc_req *r);
 117 static void sh_free(struct sh_list *);
 118 static void umount(struct svc_req *);
 119 static void umountall(struct svc_req *);
 120 static int newopts(char *);
 121 static tsol_tpent_t *get_client_template(struct sockaddr *);
 122 
 123 static int debug;
 124 static int verbose;
 125 static int rejecting;
 126 static int mount_vers_min = MOUNTVERS;
 127 static int mount_vers_max = MOUNTVERS3;
 128 static int mountd_port = 0;
 129 
 130 extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
 131 
 132 thread_t        nfsauth_thread;
 133 thread_t        cmd_thread;

 134 
 135 /*
 136  * The following logging and BSM related data structs
 137  * are only used when mountd_bsm_audit is TRUE; this
 138  * is done by specifying the undocumented -A flag to
 139  * mountd(1m).
 140  */
 141 static bool_t   mountd_bsm_audit = FALSE;
 142 
 143 typedef struct logging_data {
 144         char                    *ld_host;
 145         char                    *ld_path;
 146         char                    *ld_rpath;
 147         int                     ld_status;
 148         char                    *ld_netid;
 149         struct netbuf           *ld_nb;
 150         struct logging_data     *ld_next;
 151 } logging_data;
 152 
 153 static logging_data *logging_head = NULL;
 154 static logging_data *logging_tail = NULL;
 155 
 156 #define MOUNTD_STKSZ    (16 * 1024)     /* 16KB Stacks */
 157 static  uint32_t        nm_thrds = 0;
 158 static  uint32_t        mx_thrds = 2;   /* fallback default: see main() */
 159 
 160 static  thread_key_t    door_key;
 161 static  mutex_t         door_lock;
 162 static  int             cmd_door = -1;
 163 static  cond_t          cdoor_cv;
 164 static  int             auth_door = -1;
 165 static  cond_t          adoor_cv;
 166 
 167 typedef enum {
 168         UNKNOWN_FUNC    = 0,
 169         NFSAUTH_FUNC    = 1,
 170         NFSCMD_FUNC     = 2
 171 } dr_cmd_t;
 172 
 173 /*
 174  * Our copy of some system variables obtained using sysconf(3c)
 175  */
 176 static long ngroups_max;        /* _SC_NGROUPS_MAX */
 177 static long pw_size;            /* _SC_GETPW_R_SIZE_MAX */
 178 
 179 static char *
 180 cmd2str(dr_cmd_t t)
 181 {
 182         switch (t) {
 183         case NFSAUTH_FUNC:
 184                 return ("NFSAUTH_FUNC");
 185 
 186         case NFSCMD_FUNC:
 187                 return ("NFSCMD_FUNC");
 188 
 189         case UNKNOWN_FUNC:
 190         default:
 191                 return ("UNKNOWN_FUNC");
 192         }
 193 }
 194 
 195 void *
 196 mntd_thr_start(void *arg)
 197 {
 198         dr_cmd_t        *cp = (dr_cmd_t *)arg;
 199         dr_cmd_t         cmd = *cp;
 200         static void     *value;
 201         int              dfd = 0;
 202 
 203         value = (nm_thrds >= mx_thrds) ? (void *)1 : (void *)0;
 204         (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 205         (void) thr_setspecific(door_key, value);
 206 
 207         switch (cmd) {
 208         case NFSAUTH_FUNC:
 209                 (void) mutex_lock(&door_lock);
 210                 while (auth_door == -1)
 211                         cond_wait(&adoor_cv, &door_lock);
 212                 dfd = auth_door;
 213                 (void) mutex_unlock(&door_lock);
 214                 break;
 215 
 216         case NFSCMD_FUNC:
 217                 (void) mutex_lock(&door_lock);
 218                 while (cmd_door == -1)
 219                         cond_wait(&cdoor_cv, &door_lock);
 220                 dfd = cmd_door;
 221                 (void) mutex_unlock(&door_lock);
 222                 break;
 223 
 224         default:
 225                 syslog(LOG_NOTICE, "mntd_thr_start: %s", cmd2str(cmd));
 226                 free(cp);
 227                 thr_exit(NULL);
 228         }
 229 
 230         if (door_bind(dfd) < 0) {
 231                 syslog(LOG_ERR, "Unable to bind door for %s: %m", cmd2str(cmd));
 232                 exit(20);
 233         }
 234 #ifdef  DEBUG
 235         syslog(LOG_NOTICE, "%s Door Bound Successfully", cmd2str(cmd));
 236 #endif
 237         free(cp);
 238         door_return(NULL, 0, NULL, 0);
 239 
 240         /* NOTREACHED */
 241         return (NULL);
 242 }
 243 
 244 /*
 245  * Manages stacksize and threadpool
 246  */
 247 static void
 248 mntd_thr_create(door_info_t *dp)
 249 {
 250         thread_t         tid;
 251         int              num = 0;
 252         int              rc = 0;
 253         size_t           stksz = MOUNTD_STKSZ;
 254         long             flags = THR_DETACHED;
 255         void            *proc;
 256         dr_cmd_t        *cp;
 257 #ifdef  DEBUG
 258         char             func[1024] = {0};
 259 #endif
 260 
 261         if (dp == NULL) {
 262                 syslog(LOG_NOTICE, "mntd_thr_create: dp == NULL");
 263                 return;
 264         }
 265         proc = (void *)(uintptr_t)dp->di_proc;
 266 
 267         if ((cp = (dr_cmd_t *)malloc(sizeof (dr_cmd_t))) == (dr_cmd_t *)NULL) {
 268                 syslog(LOG_ERR, "mntd_thr_create: %m");
 269                 return;
 270         }
 271 
 272 #ifdef  DEBUG
 273         (void) addrtosymstr(proc, func, sizeof (func));
 274         syslog(LOG_NOTICE, "mntd_thr_create: func = %s", func);
 275 #endif
 276 
 277         if (proc == (void *)nfsauth_func)
 278                 *cp = NFSAUTH_FUNC;
 279         else if (proc == (void *)nfscmd_func)
 280                 *cp = NFSCMD_FUNC;
 281         else {
 282                 free(cp);
 283                 return;
 284         }
 285 
 286         if ((num = atomic_inc_32_nv(&nm_thrds)) > mx_thrds) {
 287                 atomic_dec_32(&nm_thrds);
 288                 num -= 1;
 289 #ifdef  DEBUG
 290                 syslog(LOG_ERR,
 291                     "mntd_thr_create: %d threads already active", num);
 292 #endif
 293                 free(cp);
 294                 return;
 295         }
 296 
 297         rc = thr_create(NULL, stksz, mntd_thr_start, (void *)cp, flags, &tid);
 298         if (rc != 0) {
 299                 atomic_dec_32(&nm_thrds);
 300                 syslog(LOG_ERR, "mntd_thr_create: %m");
 301                 free(cp);
 302                 return;
 303         }
 304 #ifdef  DEBUG
 305         syslog(LOG_NOTICE,
 306             "mntd_thr_create: tid %d created (nm_thrds = %d)", tid, nm_thrds);
 307 #endif
 308 }
 309 
 310 static void
 311 mntd_thr_destroy(void *arg)
 312 {
 313         atomic_dec_32(&nm_thrds);
 314 #ifdef  DEBUG
 315         syslog(LOG_NOTICE, "mntd_thr_destroy: (nm_thrds = %d)", nm_thrds);
 316 #endif
 317 }
 318 
 319 /* ARGSUSED */
 320 static void *
 321 nfsauth_svc(void *arg)
 322 {

 323         uint_t  darg;
 324         uint_t  flags = (DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_REFUSE_DESC);
 325 #ifdef DEBUG
 326         int     dfd;
 327 #endif
 328 
 329         /* register 'nfsauth_func' as the new door service */
 330         (void) mutex_lock(&door_lock);
 331         auth_door = door_create(nfsauth_func, NULL, flags);
 332         (void) mutex_unlock(&door_lock);
 333 
 334         if (auth_door < 0) {
 335                 syslog(LOG_ERR, "nfsauth_svc: %m");
 336                 exit(10);
 337         }
 338 
 339 #ifdef DEBUG
 340         /*
 341          * Create a file system path for the door
 342          */
 343         if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
 344             S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
 345                 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
 346                 (void) close(auth_door);
 347                 exit(11);
 348         }
 349 
 350         /*
 351          * Clean up any stale namespace associations
 352          */
 353         (void) fdetach(MOUNTD_DOOR);
 354 
 355         /*
 356          * Register in namespace to pass to the kernel to door_ki_open
 357          */
 358         if (fattach(auth_door, MOUNTD_DOOR) == -1) {
 359                 syslog(LOG_ERR, "Unable to fattach door: %m\n");
 360                 (void) close(dfd);
 361                 (void) close(auth_door);
 362                 exit(12);
 363         }
 364         (void) close(dfd);
 365 #endif
 366 
 367         /*
 368          * Must pass the doorfd down to the kernel.
 369          */
 370         darg = auth_door;
 371         (void) _nfssys(MOUNTD_ARGS, &darg);
 372 
 373         /*
 374          * Signal thread that kernel has door descriptor
 375          */
 376         (void) mutex_lock(&door_lock);
 377         cond_signal(&adoor_cv);
 378         (void) mutex_unlock(&door_lock);
 379 
 380         /*
 381          * Wait for incoming calls
 382          */
 383         /*CONSTCOND*/
 384         for (;;)
 385                 (void) pause();
 386 
 387         /*NOTREACHED*/
 388         syslog(LOG_ERR, gettext("Door server exited"));
 389         return (NULL);
 390 }
 391 
 392 /*
 393  * NFS command service thread code for setup and handling of the
 394  * nfs_cmd requests for character set conversion and other future
 395  * events.
 396  */

 397 static void *
 398 cmd_svc(void *arg)
 399 {

 400         uint_t  darg;
 401         uint_t  flags = (DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_REFUSE_DESC);
 402 
 403         /* register 'nfscmd_func' as the new door service */
 404         (void) mutex_lock(&door_lock);
 405         cmd_door = door_create(nfscmd_func, NULL, flags);
 406         (void) mutex_unlock(&door_lock);
 407 
 408         if (cmd_door < 0) {
 409                 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
 410                 exit(10);
 411         }
 412 
 413         /*
 414          * Must pass the cmd_door down to the kernel.
 415          */
 416         darg = cmd_door;
 417         (void) _nfssys(NFSCMD_ARGS, &darg);
 418 
 419         /*
 420          * Signal thread that kernel has door descriptor
 421          */
 422         (void) mutex_lock(&door_lock);
 423         cond_signal(&cdoor_cv);
 424         (void) mutex_unlock(&door_lock);
 425 
 426         /*
 427          * Wait for incoming calls
 428          */
 429         /*CONSTCOND*/
 430         for (;;)
 431                 (void) pause();
 432 
 433         /*NOTREACHED*/
 434         syslog(LOG_ERR, gettext("Cmd door server exited"));
 435         return (NULL);
 436 }
 437 
 438 static void
 439 free_logging_data(logging_data *lq)
 440 {
 441         assert(mountd_bsm_audit == TRUE);
 442 
 443         if (lq != NULL) {
 444                 free(lq->ld_host);
 445                 free(lq->ld_netid);
 446 
 447                 if (lq->ld_nb != NULL) {
 448                         free(lq->ld_nb->buf);
 449                         free(lq->ld_nb);
 450                 }
 451 
 452                 free(lq->ld_path);
 453                 free(lq->ld_rpath);
 454 
 455                 free(lq);
 456         }
 457 }
 458 
 459 static logging_data *
 460 remove_head_of_queue(void)
 461 {
 462         logging_data    *lq;
 463 
 464         assert(mountd_bsm_audit == TRUE);
 465 
 466         /*
 467          * Pull it off the queue.
 468          */
 469         lq = logging_head;
 470         if (lq) {
 471                 logging_head = lq->ld_next;
 472 
 473                 /*
 474                  * Drained it.
 475                  */
 476                 if (logging_head == NULL) {
 477                         logging_tail = NULL;
 478                 }
 479         }
 480 
 481         return (lq);
 482 }
 483 
 484 static void
 485 do_logging_queue(logging_data *lq)
 486 {
 487         int             cleared = 0;
 488         char            *host;
 489 
 490         assert(mountd_bsm_audit == TRUE);
 491 
 492         while (lq) {
 493                 struct cln cln;
 494 
 495                 if (lq->ld_host == NULL) {
 496                         DTRACE_PROBE(mountd, name_by_lazy);
 497                         cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
 498                         host = cln_gethost(&cln);
 499                 } else
 500                         host = lq->ld_host;
 501 
 502                 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
 503 
 504                 /* add entry to mount list */
 505                 if (lq->ld_rpath)
 506                         mntlist_new(host, lq->ld_rpath);
 507 
 508                 if (lq->ld_host == NULL)
 509                         cln_fini(&cln);
 510 
 511                 free_logging_data(lq);
 512                 cleared++;
 513 
 514                 (void) mutex_lock(&logging_queue_lock);
 515                 lq = remove_head_of_queue();
 516                 (void) mutex_unlock(&logging_queue_lock);
 517         }
 518 
 519         DTRACE_PROBE1(mountd, logging_cleared, cleared);
 520 }
 521 
 522 static void *
 523 logging_svc(void *arg)
 524 {
 525         logging_data    *lq;
 526 
 527         assert(mountd_bsm_audit == TRUE);
 528 
 529         for (;;) {
 530                 (void) mutex_lock(&logging_queue_lock);
 531                 while (logging_head == NULL) {
 532                         (void) cond_wait(&logging_queue_cv,
 533                             &logging_queue_lock);
 534                 }
 535 
 536                 lq = remove_head_of_queue();
 537                 (void) mutex_unlock(&logging_queue_lock);
 538 
 539                 do_logging_queue(lq);
 540         }
 541 
 542         /*NOTREACHED*/
 543         syslog(LOG_ERR, gettext("Logging server exited"));
 544         return (NULL);
 545 }
 546 
 547 static int
 548 convert_int(int *val, char *str)


 689                 if (setrlimit(RLIMIT_NOFILE, &rl) != 0)
 690                         syslog(LOG_ERR, "setrlimit failed");
 691         }
 692 
 693         (void) enable_extended_FILE_stdio(-1, -1);
 694 
 695         ret = nfs_smf_get_iprop("mountd_max_threads", &max_threads,
 696             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 697         if (ret != SA_OK) {
 698                 syslog(LOG_ERR, "Reading of mountd_max_threads from SMF "
 699                     "failed, using default value");
 700         }
 701 
 702         ret = nfs_smf_get_iprop("mountd_port", &mountd_port,
 703             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 704         if (ret != SA_OK) {
 705                 syslog(LOG_ERR, "Reading of mountd_port from SMF "
 706                     "failed, using default value");
 707         }
 708 
 709         while ((c = getopt(argc, argv, "dvrm:p:A")) != EOF) {
 710                 switch (c) {
 711                 case 'd':
 712                         debug++;
 713                         break;
 714                 case 'v':
 715                         verbose++;
 716                         break;
 717                 case 'r':
 718                         rejecting = 1;
 719                         break;
 720                 case 'm':
 721                         if (convert_int(&tmp, optarg) != 0 || tmp < 1) {
 722                                 (void) fprintf(stderr, "%s: invalid "
 723                                     "max_threads option, using defaults\n",
 724                                     argv[0]);
 725                                 break;
 726                         }
 727                         max_threads = tmp;
 728                         break;
 729                 case 'A':
 730                         mountd_bsm_audit = TRUE;
 731                 case 'p':
 732                         if (convert_int(&tmp, optarg) != 0 || tmp < 1 ||
 733                             tmp > UINT16_MAX) {
 734                                 (void) fprintf(stderr, "%s: invalid port "
 735                                     "number\n", argv[0]);
 736                                 break;
 737                         }
 738                         mountd_port = tmp;
 739                         break;
 740                 default:
 741                         fprintf(stderr, "usage: mountd [-v] [-r]\n");
 742                         exit(1);
 743                 }
 744         }
 745 
 746         /*
 747          * Read in the NFS version values from config file.
 748          */
 749         bufsz = 4;
 750         ret = nfs_smf_get_prop("server_versmin", defval, DEFAULT_INSTANCE,


 778             DEFAULT_INSTANCE, SCF_TYPE_INTEGER, NFSD);
 779         if (ret != SA_OK) {
 780                 syslog(LOG_ERR, "Reading of mountd_listen_backlog from SMF "
 781                     "failed, using default value");
 782         }
 783 
 784         /*
 785          * Sanity check versions,
 786          * even though we may get versions > MOUNTVERS3, we still need
 787          * to start nfsauth service, so continue on regardless of values.
 788          */
 789         if (mount_vers_max > MOUNTVERS3)
 790                 mount_vers_max = MOUNTVERS3;
 791         if (mount_vers_min > mount_vers_max) {
 792                 fprintf(stderr, "server_versmin > server_versmax\n");
 793                 mount_vers_max = mount_vers_min;
 794         }
 795         (void) setlocale(LC_ALL, "");
 796         (void) rwlock_init(&sharetab_lock, USYNC_THREAD, NULL);
 797         (void) mutex_init(&mnttab_lock, USYNC_THREAD, NULL);
 798         if (mountd_bsm_audit) {
 799                 (void) mutex_init(&logging_queue_lock, USYNC_THREAD, NULL);
 800                 (void) cond_init(&logging_queue_cv, USYNC_THREAD, NULL);
 801         }
 802 
 803         netgroup_init();
 804 
 805 #if !defined(TEXT_DOMAIN)
 806 #define TEXT_DOMAIN "SYS_TEST"
 807 #endif
 808         (void) textdomain(TEXT_DOMAIN);
 809 
 810         /* Don't drop core if the NFS module isn't loaded. */
 811         (void) signal(SIGSYS, SIG_IGN);
 812 
 813         if (!debug)
 814                 pipe_fd = daemonize_init();
 815 
 816         /*
 817          * If we coredump it'll be in /core
 818          */
 819         if (chdir("/") < 0)
 820                 fprintf(stderr, "chdir /: %s\n", strerror(errno));
 821 


 823                 openlog("mountd", LOG_PID, LOG_DAEMON);
 824 
 825         /*
 826          * establish our lock on the lock file and write our pid to it.
 827          * exit if some other process holds the lock, or if there's any
 828          * error in writing/locking the file.
 829          */
 830         pid = _enter_daemon_lock(MOUNTD);
 831         switch (pid) {
 832         case 0:
 833                 break;
 834         case -1:
 835                 fprintf(stderr, "error locking for %s: %s\n", MOUNTD,
 836                     strerror(errno));
 837                 exit(2);
 838         default:
 839                 /* daemon was already running */
 840                 exit(0);
 841         }
 842 
 843         if (mountd_bsm_audit)
 844                 audit_mountd_setup();   /* BSM */
 845 
 846         /*
 847          * Get required system variables
 848          */
 849         if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
 850                 syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
 851                 exit(1);
 852         }
 853         if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
 854                 syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
 855                 exit(1);
 856         }
 857 
 858         /*
 859          * Set number of file descriptors to unlimited
 860          */
 861         if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
 862                 syslog(LOG_INFO, "unable to set number of FDs to unlimited");
 863         }


 884          * from being hijacked by a bind to a more specific addr.
 885          */
 886         if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
 887                 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
 888         }
 889 
 890         /*
 891          * Set the maximum number of outstanding connection
 892          * indications (listen backlog) to the value specified.
 893          */
 894         if (listen_backlog > 0 && !rpc_control(__RPC_SVC_LSTNBKLOG_SET,
 895             &listen_backlog)) {
 896                 fprintf(stderr, "unable to set listen backlog\n");
 897                 exit(1);
 898         }
 899 
 900         /*
 901          * If max_threads was specified, then set the
 902          * maximum number of threads to the value specified.
 903          */
 904         if (max_threads > 0) {
 905                 if (!rpc_control(RPC_SVC_THRMAX_SET, &max_threads)) {
 906                         fprintf(stderr, "unable to set max_threads\n");
 907                         exit(1);
 908                 }
 909                 /* Default to one fourth of all threads */
 910                 mx_thrds = (uint32_t)(max_threads / 4);
 911         }
 912 
 913         if (mountd_port < 0 || mountd_port > UINT16_MAX) {
 914                 fprintf(stderr, "unable to use specified port\n");
 915                 exit(1);
 916         }
 917 
 918         /*
 919          * Make sure to unregister any previous versions in case the
 920          * user is reconfiguring the server in interesting ways.
 921          */
 922         svc_unreg(MOUNTPROG, MOUNTVERS);
 923         svc_unreg(MOUNTPROG, MOUNTVERS_POSIX);
 924         svc_unreg(MOUNTPROG, MOUNTVERS3);
 925 
 926         (void) mutex_init(&door_lock, USYNC_THREAD, NULL);
 927         (void) cond_init(&adoor_cv, USYNC_THREAD, NULL);
 928         (void) cond_init(&cdoor_cv, USYNC_THREAD, NULL);
 929 
 930         /* server function to create/optimize door threads */
 931         (void) door_server_create(mntd_thr_create);
 932         if (thr_keycreate(&door_key, mntd_thr_destroy) != 0) {
 933                 fprintf(stderr, "thr_keycreate (server thread): %s\n",
 934                     strerror(errno));
 935                 exit(3);
 936         }
 937 
 938         /*
 939          * Create the nfsauth thread with same signal disposition
 940          * as the main thread. We need to create a separate thread
 941          * since mountd() will be both an RPC server (for remote
 942          * traffic) _and_ a doors server (for kernel upcalls).
 943          */
 944         if (thr_create(NULL, 0, nfsauth_svc, 0, thr_flags, &nfsauth_thread)) {
 945                 fprintf(stderr,
 946                     gettext("Failed to create NFSAUTH svc thread\n"));
 947                 exit(2);
 948         }
 949 
 950         /*
 951          * Create the cmd service thread with same signal disposition
 952          * as the main thread. We need to create a separate thread
 953          * since mountd() will be both an RPC server (for remote
 954          * traffic) _and_ a doors server (for kernel upcalls).
 955          */
 956         if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
 957                 syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
 958                 exit(2);
 959         }
 960 
 961         /*
 962          * Create an additional thread to service the rmtab and
 963          * audit_mountd_mount logging for mount requests. Use the same
 964          * signal disposition as the main thread. We create
 965          * a separate thread to allow the mount request threads to
 966          * clear as soon as possible.
 967          */
 968         if (mountd_bsm_audit) {
 969                 if (thr_create(NULL, 0, logging_svc, 0, thr_flags, NULL)) {
 970                         syslog(LOG_ERR,
 971                             gettext("Failed to create LOGGING svc thread"));
 972                         exit(2);
 973                 }
 974         }
 975 
 976         /*
 977          * Enumerate network transports and create service listeners
 978          * as appropriate for each.
 979          */
 980         if ((nc = setnetconfig()) == NULL) {
 981                 syslog(LOG_ERR, "setnetconfig failed: %m");
 982                 return (-1);
 983         }
 984         while ((nconf = getnetconfig(nc)) != NULL) {
 985                 /*
 986                  * Skip things like tpi_raw, invisible...
 987                  */
 988                 if ((nconf->nc_flag & NC_VISIBLE) == 0)
 989                         continue;
 990                 if (nconf->nc_semantics != NC_TPI_CLTS &&
 991                     nconf->nc_semantics != NC_TPI_COTS &&
 992                     nconf->nc_semantics != NC_TPI_COTS_ORD)
 993                         continue;
 994 


1054                         mnt_pathconf(rqstp);
1055                 else
1056                         svcerr_noproc(transp);
1057                 return;
1058 
1059         default:
1060                 svcerr_noproc(transp);
1061                 return;
1062         }
1063 }
1064 
1065 void
1066 log_cant_reply_cln(struct cln *cln)
1067 {
1068         int saverrno;
1069         char *host;
1070 
1071         saverrno = errno;       /* save error code */
1072 
1073         host = cln_gethost(cln);


1074 
1075         errno = saverrno;
1076         if (errno == 0)
1077                 syslog(LOG_ERR, "couldn't send reply to %s", host);
1078         else
1079                 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
1080 }
1081 
1082 void
1083 log_cant_reply(SVCXPRT *transp)
1084 {
1085         int saverrno;
1086         struct cln cln;
1087 
1088         saverrno = errno;       /* save error code */
1089         cln_init(&cln, transp);
1090         errno = saverrno;
1091 
1092         log_cant_reply_cln(&cln);
1093 


1278         }
1279 
1280         if (sh)
1281                 sharefree(sh);
1282         free(checkpath);
1283         return (reply_error);
1284 }
1285 
1286 /*
1287  * We need to inform the caller whether or not we were
1288  * able to add a node to the queue. If we are not, then
1289  * it is up to the caller to go ahead and log the data.
1290  */
1291 static int
1292 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
1293     char *rpath, int status, int error)
1294 {
1295         logging_data    *lq;
1296         struct netbuf   *nb;
1297 
1298         assert(mountd_bsm_audit == TRUE);
1299 
1300         lq = (logging_data *)calloc(1, sizeof (logging_data));
1301         if (lq == NULL)
1302                 goto cleanup;
1303 
1304         /*
1305          * We might not yet have the host...
1306          */
1307         if (host) {
1308                 DTRACE_PROBE1(mountd, log_host, host);
1309                 lq->ld_host = strdup(host);
1310                 if (lq->ld_host == NULL)
1311                         goto cleanup;
1312         } else {
1313                 DTRACE_PROBE(mountd, log_no_host);
1314 
1315                 lq->ld_netid = strdup(transp->xp_netid);
1316                 if (lq->ld_netid == NULL)
1317                         goto cleanup;
1318 
1319                 lq->ld_nb = calloc(1, sizeof (struct netbuf));


1357         if (logging_tail == NULL) {
1358                 logging_tail = logging_head = lq;
1359         } else {
1360                 logging_tail->ld_next = lq;
1361                 logging_tail = lq;
1362         }
1363         (void) cond_signal(&logging_queue_cv);
1364         (void) mutex_unlock(&logging_queue_lock);
1365 
1366         return (TRUE);
1367 
1368 cleanup:
1369 
1370         free_logging_data(lq);
1371 
1372         return (FALSE);
1373 }
1374 
1375 
1376 #define CLN_CLNAMES     (1 << 0)

1377 
1378 static void
1379 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1380     struct netbuf *nbuf)
1381 {
1382         if ((cln->transp = transp) != NULL) {
1383                 assert(netid == NULL && nbuf == NULL);
1384                 cln->netid = transp->xp_netid;
1385                 cln->nbuf = svc_getrpccaller(transp);
1386         } else {
1387                 cln->netid = netid;
1388                 cln->nbuf = nbuf;
1389         }
1390 

1391         cln->clnames = NULL;


1392         cln->flags = 0;
1393 
1394         bzero(cln->host, sizeof (cln->host));
1395 
1396         if (cln->netid != NULL && cln->nbuf != NULL &&
1397             (cln->nconf = getnetconfigent(cln->netid)) != NULL) {
1398                 if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1399                         struct sockaddr_in *sa;
1400                         /* LINTED pointer alignment */
1401                         sa = (struct sockaddr_in *)(cln->nbuf->buf);
1402                         (void) inet_ntop(AF_INET, &sa->sin_addr.s_addr,
1403                             cln->host, sizeof (cln->host));
1404                 } else if (strcmp(cln->nconf->nc_protofmly, NC_INET6) == 0) {
1405                         struct sockaddr_in6 *sa;
1406                         /* LINTED pointer alignment */
1407                         sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1408                         (void) inet_ntop(AF_INET6, &sa->sin6_addr.s6_addr,
1409                             cln->host, sizeof (cln->host));
1410                 }
1411         }
1412 
1413         if (strlen(cln->host) == 0)
1414                 (void) strlcpy(cln->host, "(unknown)", sizeof (cln->host));
1415 }
1416 
1417 void
1418 cln_init(struct cln *cln, SVCXPRT *transp)
1419 {
1420         cln_init_common(cln, transp, NULL, NULL);
1421 }
1422 
1423 void
1424 cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1425 {
1426         cln_init_common(cln, NULL, netid, nbuf);
1427 }
1428 
1429 void
1430 cln_fini(struct cln *cln)
1431 {
1432         if (cln->nconf != NULL)
1433                 freenetconfigent(cln->nconf);
1434 
1435         if (cln->clnames != NULL)
1436                 netdir_free(cln->clnames, ND_HOSTSERVLIST);


1437 }
1438 
1439 struct netbuf *
1440 cln_getnbuf(struct cln *cln)
1441 {
1442         return (cln->nbuf);
1443 }
1444 
1445 struct nd_hostservlist *
1446 cln_getclientsnames(struct cln *cln)
1447 {
1448         if ((cln->flags & CLN_CLNAMES) == 0) {
1449                 if (cln->nconf != NULL && cln->nbuf != NULL) {












1450                         (void) __netdir_getbyaddr_nosrv(cln->nconf,
1451                             &cln->clnames, cln->nbuf);
1452                 }
1453                 cln->flags |= CLN_CLNAMES;
1454         }
1455 
1456         return (cln->clnames);
1457 }
1458 









1459 char *
1460 cln_gethost(struct cln *cln)
1461 {
1462         if (cln_getclientsnames(cln) != NULL)
1463                 return (cln->clnames->h_hostservs[0].h_host);
1464 




































1465         return (cln->host);
1466 }
1467 
1468 /*
1469  * Check mount requests, add to mounted list if ok
1470  */
1471 static int
1472 mount(struct svc_req *rqstp)
1473 {
1474         SVCXPRT *transp;
1475         int version, vers;
1476         struct fhstatus fhs;
1477         struct mountres3 mountres3;
1478         char fh[FHSIZE3];
1479         int len = FHSIZE3;
1480         char *path, rpath[MAXPATHLEN];
1481         share_t *sh = NULL;
1482         struct cln cln;
1483         char *host = NULL;
1484         int error = 0, lofs_tried = 0, enqueued;


1491         transp = rqstp->rq_xprt;
1492         version = rqstp->rq_vers;
1493         path = NULL;
1494 
1495         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1496                 svcerr_decode(transp);
1497                 return (EACCES);
1498         }
1499 
1500         cln_init(&cln, transp);
1501 
1502         /*
1503          * Put off getting the name for the client until we
1504          * need it. This is a performance gain. If we are logging,
1505          * then we don't care about performance and might as well
1506          * get the host name now in case we need to spit out an
1507          * error message.
1508          */
1509         if (verbose) {
1510                 DTRACE_PROBE(mountd, name_by_verbose);
1511                 host = cln_gethost(&cln);








1512         }

1513 
1514         /*
1515          * If the version being used is less than the minimum version,
1516          * the filehandle translation should not be provided to the
1517          * client.
1518          */
1519         if (rejecting || version < mount_vers_min) {
1520                 if (verbose)
1521                         syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1522                             host, path);
1523                 error = EACCES;
1524                 goto reply;
1525         }
1526 
1527         /*
1528          * Trusted Extension doesn't support nfsv2. nfsv2 client
1529          * uses MOUNT protocol v1 and v2. To prevent circumventing
1530          * TX label policy via using nfsv2 client, reject a mount
1531          * request with version less than 3 and log an error.
1532          */


1697                 break;
1698 
1699         case MOUNTVERS3:
1700                 if (!error) {
1701                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1702                     flavor_list;
1703                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1704                     flavor_count;
1705 
1706                 } else if (error == ENAMETOOLONG)
1707                         error = MNT3ERR_NAMETOOLONG;
1708 
1709                 mountres3.fhs_status = error;
1710                 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1711                         log_cant_reply_cln(&cln);
1712 
1713                 audit_status = mountres3.fhs_status;
1714                 break;
1715         }
1716 
1717         if (host == NULL)
1718                 host = cln_gethost(&cln);
1719 
1720         if (verbose)
1721                 syslog(LOG_NOTICE, "MOUNT: %s %s %s", host,

1722                     error ? "denied" : "mounted", path);
1723 
1724         if (mountd_bsm_audit) {
1725                 /*
1726                  * If we can not create a queue entry, go ahead and do it
1727                  * in the context of this thread.
1728                  */
1729                 enqueued = enqueue_logging_data(host, transp, path, rpath,
1730                     audit_status, error);





1731 
1732                 if (enqueued == FALSE) {
1733                         DTRACE_PROBE(mountd, logged_in_thread);
1734                         audit_mountd_mount(host, path, audit_status); /* BSM */


1735                 }
1736         }
1737 
1738         if (enqueued == FALSE && !error) {
1739                 /* Add entry to mount list */
1740                 mntlist_new(host, rpath);
1741         }
1742 
1743         if (path != NULL)
1744                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1745 
1746         if (sh)
1747                 sharefree(sh);
1748 
1749         cln_fini(&cln);
1750 
1751         return (error);
1752 }
1753 
1754 /*
1755  * Determine whether two paths are within the same file system.
1756  * Returns nonzero (true) if paths are the same, zero (false) if
1757  * they are different.  If an error occurs, return false.
1758  *
1759  * Use the actual FSID if it's available (via getattrat()); otherwise,
1760  * fall back on st_dev.
1761  *
1762  * With ZFS snapshots, st_dev differs from the regular file system


2127                                         }
2128                                 }
2129                         } else {
2130                                 ret = inet_matchaddr(pnb->buf, gr);
2131                                 if (ret == -1) {
2132                                         if (errno == EINVAL) {
2133                                                 syslog(LOG_WARNING,
2134                                                     "invalid access list "
2135                                                     "entry: %s", gr);
2136                                         }
2137                                         return (-1);
2138                                 } else if (ret == 1) {
2139                                         return (response);
2140                                 }
2141                         }
2142 
2143                         goto next;
2144                 }
2145 
2146                 /*
2147                  * Before doing clients names lookup, check if it's individual
2148                  * IP address specified without @ prefix.
2149                  */
2150                 if (strcmp(gr, cln->host) == 0)
2151                         return (response);
2152 
2153                 /*
2154                  * No other checks can be performed if client address
2155                  * can't be resolved.
2156                  */
2157                 if ((clnames = cln_getclientsnames(cln)) == NULL)
2158                         goto next;
2159 
2160                 /* Otherwise loop through all client hostname aliases */
2161                 for (i = 0; i < clnames->h_cnt; i++) {
2162                         char *host = clnames->h_hostservs[i].h_host;
2163 
2164                         /*
2165                          * If the list name begins with a dot then
2166                          * do a domain name suffix comparison.
2167                          * A single dot matches any name with no
2168                          * suffix.
2169                          */
2170                         if (*gr == '.') {
2171                                 if (*(gr + 1) == '\0') {  /* single dot */
2172                                         if (strchr(host, '.') == NULL)
2173                                                 return (response);


3384 {
3385         char *host, *path, *remove_path;
3386         char rpath[MAXPATHLEN];
3387         SVCXPRT *transp;
3388         struct cln cln;
3389 
3390         transp = rqstp->rq_xprt;
3391         path = NULL;
3392         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3393                 svcerr_decode(transp);
3394                 return;
3395         }
3396 
3397         cln_init(&cln, transp);
3398 
3399         errno = 0;
3400         if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3401                 log_cant_reply_cln(&cln);
3402 
3403         host = cln_gethost(&cln);








3404 
3405         if (verbose)
3406                 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3407 
3408         if (mountd_bsm_audit)
3409                 audit_mountd_umount(host, path);
3410 
3411         remove_path = rpath;    /* assume we will use the cannonical path */
3412         if (realpath(path, rpath) == NULL) {
3413                 if (verbose)
3414                         syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3415                 remove_path = path;     /* use path provided instead */
3416         }
3417 
3418         mntlist_delete(host, remove_path);      /* remove from mount list */
3419 
3420         cln_fini(&cln);
3421 
3422         svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3423 }
3424 
3425 /*
3426  * Remove all entries for one machine from mounted list
3427  */
3428 static void


3431         SVCXPRT *transp;
3432         char *host;
3433         struct cln cln;
3434 
3435         transp = rqstp->rq_xprt;
3436         if (!svc_getargs(transp, xdr_void, NULL)) {
3437                 svcerr_decode(transp);
3438                 return;
3439         }
3440         /*
3441          * We assume that this call is asynchronous and made via rpcbind
3442          * callit routine.  Therefore return control immediately. The error
3443          * causes rpcbind to remain silent, as opposed to every machine
3444          * on the net blasting the requester with a response.
3445          */
3446         svcerr_systemerr(transp);
3447 
3448         cln_init(&cln, transp);
3449 
3450         host = cln_gethost(&cln);




3451 
3452         /*
3453          * Remove all hosts entries from mount list
3454          */
3455         mntlist_delete_all(host);
3456 
3457         if (verbose)
3458                 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3459 
3460         cln_fini(&cln);
3461 }
3462 
3463 void *
3464 exmalloc(size_t size)
3465 {
3466         void *ret;
3467 
3468         if ((ret = malloc(size)) == NULL) {
3469                 syslog(LOG_ERR, "Out of memory");
3470                 exit(1);