1 /*
   2  * CDDL HEADER START
   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>
  45 #include <netconfig.h>
  46 #include <netdir.h>
  47 #include <sys/file.h>
  48 #include <sys/time.h>
  49 #include <sys/errno.h>
  50 #include <rpcsvc/mount.h>
  51 #include <sys/pathconf.h>
  52 #include <sys/systeminfo.h>
  53 #include <sys/utsname.h>
  54 #include <sys/wait.h>
  55 #include <sys/resource.h>
  56 #include <signal.h>
  57 #include <locale.h>
  58 #include <unistd.h>
  59 #include <errno.h>
  60 #include <sys/socket.h>
  61 #include <netinet/in.h>
  62 #include <arpa/inet.h>
  63 #include <netdb.h>
  64 #include <thread.h>
  65 #include <assert.h>
  66 #include <priv_utils.h>
  67 #include <nfs/auth.h>
  68 #include <nfs/nfssys.h>
  69 #include <nfs/nfs.h>
  70 #include <nfs/nfs_sec.h>
  71 #include <rpcsvc/daemon_utils.h>
  72 #include <deflt.h>
  73 #include "../../fslib.h"
  74 #include <sharefs/share.h>
  75 #include <sharefs/sharetab.h>
  76 #include "../lib/sharetab.h"
  77 #include "mountd.h"
  78 #include <tsol/label.h>
  79 #include <sys/tsol/label_macro.h>
  80 #include <libtsnet.h>
  81 #include <sys/sdt.h>
  82 #include <libscf.h>
  83 #include <limits.h>
  84 #include <sys/nvpair.h>
  85 #include <attr.h>
  86 #include "smfcfg.h"
  87 #include <pwd.h>
  88 #include <grp.h>
  89 #include <alloca.h>
  90 
  91 extern int daemonize_init(void);
  92 extern void daemonize_fini(int);
  93 
  94 extern int _nfssys(int, void *);
  95 
  96 struct sh_list *share_list;
  97 
  98 rwlock_t sharetab_lock;         /* lock to protect the cached sharetab */
  99 static mutex_t mnttab_lock;     /* prevent concurrent mnttab readers */
 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 
 144 /*
 145  * Our copy of some system variables obtained using sysconf(3c)
 146  */
 147 static long ngroups_max;        /* _SC_NGROUPS_MAX */
 148 static long pw_size;            /* _SC_GETPW_R_SIZE_MAX */
 149 
 150 /* ARGSUSED */
 151 static void *
 152 nfsauth_svc(void *arg)
 153 {
 154         int     doorfd = -1;
 155         uint_t  darg;
 156 #ifdef DEBUG
 157         int     dfd;
 158 #endif
 159 
 160         if ((doorfd = door_create(nfsauth_func, NULL,
 161             DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
 162                 syslog(LOG_ERR, "Unable to create door: %m\n");
 163                 exit(10);
 164         }
 165 
 166 #ifdef DEBUG
 167         /*
 168          * Create a file system path for the door
 169          */
 170         if ((dfd = open(MOUNTD_DOOR, O_RDWR|O_CREAT|O_TRUNC,
 171             S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
 172                 syslog(LOG_ERR, "Unable to open %s: %m\n", MOUNTD_DOOR);
 173                 (void) close(doorfd);
 174                 exit(11);
 175         }
 176 
 177         /*
 178          * Clean up any stale namespace associations
 179          */
 180         (void) fdetach(MOUNTD_DOOR);
 181 
 182         /*
 183          * Register in namespace to pass to the kernel to door_ki_open
 184          */
 185         if (fattach(doorfd, MOUNTD_DOOR) == -1) {
 186                 syslog(LOG_ERR, "Unable to fattach door: %m\n");
 187                 (void) close(dfd);
 188                 (void) close(doorfd);
 189                 exit(12);
 190         }
 191         (void) close(dfd);
 192 #endif
 193 
 194         /*
 195          * Must pass the doorfd down to the kernel.
 196          */
 197         darg = doorfd;
 198         (void) _nfssys(MOUNTD_ARGS, &darg);
 199 
 200         /*
 201          * Wait for incoming calls
 202          */
 203         /*CONSTCOND*/
 204         for (;;)
 205                 (void) pause();
 206 
 207         /*NOTREACHED*/
 208         syslog(LOG_ERR, gettext("Door server exited"));
 209         return (NULL);
 210 }
 211 
 212 /*
 213  * NFS command service thread code for setup and handling of the
 214  * nfs_cmd requests for character set conversion and other future
 215  * events.
 216  */
 217 
 218 static void *
 219 cmd_svc(void *arg)
 220 {
 221         int     doorfd = -1;
 222         uint_t  darg;
 223 
 224         if ((doorfd = door_create(nfscmd_func, NULL,
 225             DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
 226                 syslog(LOG_ERR, "Unable to create cmd door: %m\n");
 227                 exit(10);
 228         }
 229 
 230         /*
 231          * Must pass the doorfd down to the kernel.
 232          */
 233         darg = doorfd;
 234         (void) _nfssys(NFSCMD_ARGS, &darg);
 235 
 236         /*
 237          * Wait for incoming calls
 238          */
 239         /*CONSTCOND*/
 240         for (;;)
 241                 (void) pause();
 242 
 243         /*NOTREACHED*/
 244         syslog(LOG_ERR, gettext("Cmd door server exited"));
 245         return (NULL);
 246 }
 247 
 248 static void
 249 free_logging_data(logging_data *lq)
 250 {
 251         if (lq != NULL) {
 252                 free(lq->ld_host);
 253                 free(lq->ld_netid);
 254 
 255                 if (lq->ld_nb != NULL) {
 256                         free(lq->ld_nb->buf);
 257                         free(lq->ld_nb);
 258                 }
 259 
 260                 free(lq->ld_path);
 261                 free(lq->ld_rpath);
 262 
 263                 free(lq);
 264         }
 265 }
 266 
 267 static logging_data *
 268 remove_head_of_queue(void)
 269 {
 270         logging_data    *lq;
 271 
 272         /*
 273          * Pull it off the queue.
 274          */
 275         lq = logging_head;
 276         if (lq) {
 277                 logging_head = lq->ld_next;
 278 
 279                 /*
 280                  * Drained it.
 281                  */
 282                 if (logging_head == NULL) {
 283                         logging_tail = NULL;
 284                 }
 285         }
 286 
 287         return (lq);
 288 }
 289 
 290 static void
 291 do_logging_queue(logging_data *lq)
 292 {
 293         int             cleared = 0;
 294         char            *host;
 295 
 296         while (lq) {
 297                 struct cln cln;
 298 
 299                 if (lq->ld_host == NULL) {
 300                         DTRACE_PROBE(mountd, name_by_lazy);
 301                         cln_init_lazy(&cln, lq->ld_netid, lq->ld_nb);
 302                         host = cln_gethost(&cln);
 303                 } else
 304                         host = lq->ld_host;
 305 
 306                 audit_mountd_mount(host, lq->ld_path, lq->ld_status); /* BSM */
 307 
 308                 /* add entry to mount list */
 309                 if (lq->ld_rpath)
 310                         mntlist_new(host, lq->ld_rpath);
 311 
 312                 if (lq->ld_host == NULL)
 313                         cln_fini(&cln);
 314 
 315                 free_logging_data(lq);
 316                 cleared++;
 317 
 318                 (void) mutex_lock(&logging_queue_lock);
 319                 lq = remove_head_of_queue();
 320                 (void) mutex_unlock(&logging_queue_lock);
 321         }
 322 
 323         DTRACE_PROBE1(mountd, logging_cleared, cleared);
 324 }
 325 
 326 static void *
 327 logging_svc(void *arg)
 328 {
 329         logging_data    *lq;
 330 
 331         for (;;) {
 332                 (void) mutex_lock(&logging_queue_lock);
 333                 while (logging_head == NULL) {
 334                         (void) cond_wait(&logging_queue_cv,
 335                             &logging_queue_lock);
 336                 }
 337 
 338                 lq = remove_head_of_queue();
 339                 (void) mutex_unlock(&logging_queue_lock);
 340 
 341                 do_logging_queue(lq);
 342         }
 343 
 344         /*NOTREACHED*/
 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
 462                          */
 463                         if (defvers == NFS_VERSION)
 464                                 mount_vers_min = MOUNTVERS;
 465                 }
 466         }
 467 
 468         bufsz = 4;
 469         ret = nfs_smf_get_prop("server_versmax", defval, DEFAULT_INSTANCE,
 470             SCF_TYPE_INTEGER, NFSD, &bufsz);
 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 
 539         audit_mountd_setup();   /* BSM */
 540 
 541         /*
 542          * Get required system variables
 543          */
 544         if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) == -1) {
 545                 syslog(LOG_ERR, "Unable to get _SC_NGROUPS_MAX");
 546                 exit(1);
 547         }
 548         if ((pw_size = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) {
 549                 syslog(LOG_ERR, "Unable to get _SC_GETPW_R_SIZE_MAX");
 550                 exit(1);
 551         }
 552 
 553         /*
 554          * Set number of file descriptors to unlimited
 555          */
 556         if (!rpc_control(RPC_SVC_USE_POLLFD, &rpc_svc_fdunlim)) {
 557                 syslog(LOG_INFO, "unable to set number of FDs to unlimited");
 558         }
 559 
 560         /*
 561          * Tell RPC that we want automatic thread mode.
 562          * A new thread will be spawned for each request.
 563          */
 564         if (!rpc_control(RPC_SVC_MTMODE_SET, &rpc_svc_mode)) {
 565                 fprintf(stderr, "unable to set automatic MT mode\n");
 566                 exit(1);
 567         }
 568 
 569         /*
 570          * Enable non-blocking mode and maximum record size checks for
 571          * connection oriented transports.
 572          */
 573         if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
 574                 fprintf(stderr, "unable to set RPC max record size\n");
 575         }
 576 
 577         /*
 578          * Prevent our non-priv udp and tcp ports bound w/wildcard addr
 579          * from being hijacked by a bind to a more specific addr.
 580          */
 581         if (!rpc_control(__RPC_SVC_EXCLBIND_SET, &exclbind)) {
 582                 fprintf(stderr, "warning: unable to set udp/tcp EXCLBIND\n");
 583         }
 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 
 624         /*
 625          * Create the cmd service thread with same signal disposition
 626          * as the main thread. We need to create a separate thread
 627          * since mountd() will be both an RPC server (for remote
 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 /*
 711  * Server procedure switch routine
 712  */
 713 void
 714 mnt(struct svc_req *rqstp, SVCXPRT *transp)
 715 {
 716         switch (rqstp->rq_proc) {
 717         case NULLPROC:
 718                 errno = 0;
 719                 if (!svc_sendreply(transp, xdr_void, (char *)0))
 720                         log_cant_reply(transp);
 721                 return;
 722 
 723         case MOUNTPROC_MNT:
 724                 (void) mount(rqstp);
 725                 return;
 726 
 727         case MOUNTPROC_DUMP:
 728                 mntlist_send(transp);
 729                 return;
 730 
 731         case MOUNTPROC_UMNT:
 732                 umount(rqstp);
 733                 return;
 734 
 735         case MOUNTPROC_UMNTALL:
 736                 umountall(rqstp);
 737                 return;
 738 
 739         case MOUNTPROC_EXPORT:
 740         case MOUNTPROC_EXPORTALL:
 741                 export(rqstp);
 742                 return;
 743 
 744         case MOUNTPROC_PATHCONF:
 745                 if (rqstp->rq_vers == MOUNTVERS_POSIX)
 746                         mnt_pathconf(rqstp);
 747                 else
 748                         svcerr_noproc(transp);
 749                 return;
 750 
 751         default:
 752                 svcerr_noproc(transp);
 753                 return;
 754         }
 755 }
 756 
 757 void
 758 log_cant_reply_cln(struct cln *cln)
 759 {
 760         int saverrno;
 761         char *host;
 762 
 763         saverrno = errno;       /* save error code */
 764 
 765         host = cln_gethost(cln);
 766         if (host == NULL)
 767                 return;
 768 
 769         errno = saverrno;
 770         if (errno == 0)
 771                 syslog(LOG_ERR, "couldn't send reply to %s", host);
 772         else
 773                 syslog(LOG_ERR, "couldn't send reply to %s: %m", host);
 774 }
 775 
 776 void
 777 log_cant_reply(SVCXPRT *transp)
 778 {
 779         int saverrno;
 780         struct cln cln;
 781 
 782         saverrno = errno;       /* save error code */
 783         cln_init(&cln, transp);
 784         errno = saverrno;
 785 
 786         log_cant_reply_cln(&cln);
 787 
 788         cln_fini(&cln);
 789 }
 790 
 791 /*
 792  * Answer pathconf questions for the mount point fs
 793  */
 794 static void
 795 mnt_pathconf(struct svc_req *rqstp)
 796 {
 797         SVCXPRT *transp;
 798         struct pathcnf p;
 799         char *path, rpath[MAXPATHLEN];
 800         struct stat st;
 801 
 802         transp = rqstp->rq_xprt;
 803         path = NULL;
 804         (void) memset((caddr_t)&p, 0, sizeof (p));
 805 
 806         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
 807                 svcerr_decode(transp);
 808                 return;
 809         }
 810         if (lstat(path, &st) < 0) {
 811                 _PC_SET(_PC_ERROR, p.pc_mask);
 812                 goto done;
 813         }
 814         /*
 815          * Get a path without symbolic links.
 816          */
 817         if (realpath(path, rpath) == NULL) {
 818                 syslog(LOG_DEBUG,
 819                     "mount request: realpath failed on %s: %m",
 820                     path);
 821                 _PC_SET(_PC_ERROR, p.pc_mask);
 822                 goto done;
 823         }
 824         (void) memset((caddr_t)&p, 0, sizeof (p));
 825         /*
 826          * can't ask about devices over NFS
 827          */
 828         _PC_SET(_PC_MAX_CANON, p.pc_mask);
 829         _PC_SET(_PC_MAX_INPUT, p.pc_mask);
 830         _PC_SET(_PC_PIPE_BUF, p.pc_mask);
 831         _PC_SET(_PC_VDISABLE, p.pc_mask);
 832 
 833         errno = 0;
 834         p.pc_link_max = pathconf(rpath, _PC_LINK_MAX);
 835         if (errno)
 836                 _PC_SET(_PC_LINK_MAX, p.pc_mask);
 837         p.pc_name_max = pathconf(rpath, _PC_NAME_MAX);
 838         if (errno)
 839                 _PC_SET(_PC_NAME_MAX, p.pc_mask);
 840         p.pc_path_max = pathconf(rpath, _PC_PATH_MAX);
 841         if (errno)
 842                 _PC_SET(_PC_PATH_MAX, p.pc_mask);
 843         if (pathconf(rpath, _PC_NO_TRUNC) == 1)
 844                 _PC_SET(_PC_NO_TRUNC, p.pc_mask);
 845         if (pathconf(rpath, _PC_CHOWN_RESTRICTED) == 1)
 846                 _PC_SET(_PC_CHOWN_RESTRICTED, p.pc_mask);
 847 
 848 done:
 849         errno = 0;
 850         if (!svc_sendreply(transp, xdr_ppathcnf, (char *)&p))
 851                 log_cant_reply(transp);
 852         if (path != NULL)
 853                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
 854 }
 855 
 856 /*
 857  * If the rootmount (export) option is specified, the all mount requests for
 858  * subdirectories return EACCES.
 859  */
 860 static int
 861 checkrootmount(share_t *sh, char *rpath)
 862 {
 863         char *val;
 864 
 865         if ((val = getshareopt(sh->sh_opts, SHOPT_NOSUB)) != NULL) {
 866                 free(val);
 867                 if (strcmp(sh->sh_path, rpath) != 0)
 868                         return (0);
 869                 else
 870                         return (1);
 871         } else
 872                 return (1);
 873 }
 874 
 875 #define MAX_FLAVORS     128
 876 
 877 /*
 878  * Return only EACCES if client does not have access
 879  *  to this directory.
 880  * "If the server exports only /a/b, an attempt to
 881  *  mount a/b/c will fail with ENOENT if the directory
 882  *  does not exist"... However, if the client
 883  *  does not have access to /a/b, an attacker can
 884  *  determine whether the directory exists.
 885  * This routine checks either existence of the file or
 886  * existence of the file name entry in the mount table.
 887  * If the file exists and there is no file name entry,
 888  * the error returned should be EACCES.
 889  * If the file does not exist, it must be determined
 890  * whether the client has access to a parent
 891  * directory.  If the client has access to a parent
 892  * directory, the error returned should be ENOENT,
 893  * otherwise EACCES.
 894  */
 895 static int
 896 mount_enoent_error(struct cln *cln, char *path, char *rpath, int *flavor_list)
 897 {
 898         char *checkpath, *dp;
 899         share_t *sh = NULL;
 900         int realpath_error = ENOENT, reply_error = EACCES, lofs_tried = 0;
 901         int flavor_count;
 902 
 903         checkpath = strdup(path);
 904         if (checkpath == NULL) {
 905                 syslog(LOG_ERR, "mount_enoent: no memory");
 906                 return (EACCES);
 907         }
 908 
 909         /* CONSTCOND */
 910         while (1) {
 911                 if (sh) {
 912                         sharefree(sh);
 913                         sh = NULL;
 914                 }
 915 
 916                 if ((sh = findentry(rpath)) == NULL &&
 917                     (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
 918                         /*
 919                          * There is no file name entry.
 920                          * If the file (with symbolic links resolved) exists,
 921                          * the error returned should be EACCES.
 922                          */
 923                         if (realpath_error == 0)
 924                                 break;
 925                 } else if (checkrootmount(sh, rpath) == 0) {
 926                         /*
 927                          * This is a "nosub" only export, in which case,
 928                          * mounting subdirectories isn't allowed.
 929                          * If the file (with symbolic links resolved) exists,
 930                          * the error returned should be EACCES.
 931                          */
 932                         if (realpath_error == 0)
 933                                 break;
 934                 } else {
 935                         /*
 936                          * Check permissions in mount table.
 937                          */
 938                         if (newopts(sh->sh_opts))
 939                                 flavor_count = getclientsflavors_new(sh, cln,
 940                                     flavor_list);
 941                         else
 942                                 flavor_count = getclientsflavors_old(sh, cln,
 943                                     flavor_list);
 944                         if (flavor_count != 0) {
 945                                 /*
 946                                  * Found entry in table and
 947                                  * client has correct permissions.
 948                                  */
 949                                 reply_error = ENOENT;
 950                                 break;
 951                         }
 952                 }
 953 
 954                 /*
 955                  * Check all parent directories.
 956                  */
 957                 dp = strrchr(checkpath, '/');
 958                 if (dp == NULL)
 959                         break;
 960                 *dp = '\0';
 961                 if (strlen(checkpath) == 0)
 962                         break;
 963                 /*
 964                  * Get the real path (no symbolic links in it)
 965                  */
 966                 if (realpath(checkpath, rpath) == NULL) {
 967                         if (errno != ENOENT)
 968                                 break;
 969                 } else {
 970                         realpath_error = 0;
 971                 }
 972         }
 973 
 974         if (sh)
 975                 sharefree(sh);
 976         free(checkpath);
 977         return (reply_error);
 978 }
 979 
 980 /*
 981  * We need to inform the caller whether or not we were
 982  * able to add a node to the queue. If we are not, then
 983  * it is up to the caller to go ahead and log the data.
 984  */
 985 static int
 986 enqueue_logging_data(char *host, SVCXPRT *transp, char *path,
 987     char *rpath, int status, int error)
 988 {
 989         logging_data    *lq;
 990         struct netbuf   *nb;
 991 
 992         lq = (logging_data *)calloc(1, sizeof (logging_data));
 993         if (lq == NULL)
 994                 goto cleanup;
 995 
 996         /*
 997          * We might not yet have the host...
 998          */
 999         if (host) {
1000                 DTRACE_PROBE1(mountd, log_host, host);
1001                 lq->ld_host = strdup(host);
1002                 if (lq->ld_host == NULL)
1003                         goto cleanup;
1004         } else {
1005                 DTRACE_PROBE(mountd, log_no_host);
1006 
1007                 lq->ld_netid = strdup(transp->xp_netid);
1008                 if (lq->ld_netid == NULL)
1009                         goto cleanup;
1010 
1011                 lq->ld_nb = calloc(1, sizeof (struct netbuf));
1012                 if (lq->ld_nb == NULL)
1013                         goto cleanup;
1014 
1015                 nb = svc_getrpccaller(transp);
1016                 if (nb == NULL) {
1017                         DTRACE_PROBE(mountd, e__nb__enqueue);
1018                         goto cleanup;
1019                 }
1020 
1021                 DTRACE_PROBE(mountd, nb_set_enqueue);
1022 
1023                 lq->ld_nb->maxlen = nb->maxlen;
1024                 lq->ld_nb->len = nb->len;
1025 
1026                 lq->ld_nb->buf = malloc(lq->ld_nb->len);
1027                 if (lq->ld_nb->buf == NULL)
1028                         goto cleanup;
1029 
1030                 bcopy(nb->buf, lq->ld_nb->buf, lq->ld_nb->len);
1031         }
1032 
1033         lq->ld_path = strdup(path);
1034         if (lq->ld_path == NULL)
1035                 goto cleanup;
1036 
1037         if (!error) {
1038                 lq->ld_rpath = strdup(rpath);
1039                 if (lq->ld_rpath == NULL)
1040                         goto cleanup;
1041         }
1042 
1043         lq->ld_status = status;
1044 
1045         /*
1046          * Add to the tail of the logging queue.
1047          */
1048         (void) mutex_lock(&logging_queue_lock);
1049         if (logging_tail == NULL) {
1050                 logging_tail = logging_head = lq;
1051         } else {
1052                 logging_tail->ld_next = lq;
1053                 logging_tail = lq;
1054         }
1055         (void) cond_signal(&logging_queue_cv);
1056         (void) mutex_unlock(&logging_queue_lock);
1057 
1058         return (TRUE);
1059 
1060 cleanup:
1061 
1062         free_logging_data(lq);
1063 
1064         return (FALSE);
1065 }
1066 
1067 
1068 #define CLN_CLNAMES     (1 << 0)
1069 #define CLN_HOST        (1 << 1)
1070 
1071 static void
1072 cln_init_common(struct cln *cln, SVCXPRT *transp, char *netid,
1073     struct netbuf *nbuf)
1074 {
1075         if ((cln->transp = transp) != NULL) {
1076                 assert(netid == NULL && nbuf == NULL);
1077                 cln->netid = transp->xp_netid;
1078                 cln->nbuf = svc_getrpccaller(transp);
1079         } else {
1080                 cln->netid = netid;
1081                 cln->nbuf = nbuf;
1082         }
1083 
1084         cln->nconf = NULL;
1085         cln->clnames = NULL;
1086         cln->host = NULL;
1087 
1088         cln->flags = 0;
1089 }
1090 
1091 void
1092 cln_init(struct cln *cln, SVCXPRT *transp)
1093 {
1094         cln_init_common(cln, transp, NULL, NULL);
1095 }
1096 
1097 void
1098 cln_init_lazy(struct cln *cln, char *netid, struct netbuf *nbuf)
1099 {
1100         cln_init_common(cln, NULL, netid, nbuf);
1101 }
1102 
1103 void
1104 cln_fini(struct cln *cln)
1105 {
1106         if (cln->nconf != NULL)
1107                 freenetconfigent(cln->nconf);
1108 
1109         if (cln->clnames != NULL)
1110                 netdir_free(cln->clnames, ND_HOSTSERVLIST);
1111 
1112         free(cln->host);
1113 }
1114 
1115 struct netbuf *
1116 cln_getnbuf(struct cln *cln)
1117 {
1118         return (cln->nbuf);
1119 }
1120 
1121 struct nd_hostservlist *
1122 cln_getclientsnames(struct cln *cln)
1123 {
1124         if ((cln->flags & CLN_CLNAMES) == 0) {
1125                 /*
1126                  * nconf is not needed if we do not have nbuf (see
1127                  * cln_gethost() too), so we check for nbuf and in a case it is
1128                  * NULL we do not try to get nconf.
1129                  */
1130                 if (cln->netid != NULL && cln->nbuf != NULL) {
1131                         cln->nconf = getnetconfigent(cln->netid);
1132                         if (cln->nconf == NULL)
1133                                 syslog(LOG_ERR, "%s: getnetconfigent failed",
1134                                     cln->netid);
1135                 }
1136 
1137                 if (cln->nconf != NULL && cln->nbuf != NULL)
1138                         (void) __netdir_getbyaddr_nosrv(cln->nconf,
1139                             &cln->clnames, cln->nbuf);
1140 
1141                 cln->flags |= CLN_CLNAMES;
1142         }
1143 
1144         return (cln->clnames);
1145 }
1146 
1147 /*
1148  * Return B_TRUE if the host is already available at no cost
1149  */
1150 boolean_t
1151 cln_havehost(struct cln *cln)
1152 {
1153         return ((cln->flags & (CLN_CLNAMES | CLN_HOST)) != 0);
1154 }
1155 
1156 char *
1157 cln_gethost(struct cln *cln)
1158 {
1159         if (cln_getclientsnames(cln) != NULL)
1160                 return (cln->clnames->h_hostservs[0].h_host);
1161 
1162         if ((cln->flags & CLN_HOST) == 0) {
1163                 if (cln->nconf == NULL || cln->nbuf == NULL) {
1164                         cln->host = strdup("(anon)");
1165                 } else {
1166                         char host[MAXIPADDRLEN];
1167 
1168                         if (strcmp(cln->nconf->nc_protofmly, NC_INET) == 0) {
1169                                 struct sockaddr_in *sa;
1170 
1171                                 /* LINTED pointer alignment */
1172                                 sa = (struct sockaddr_in *)(cln->nbuf->buf);
1173                                 (void) inet_ntoa_r(sa->sin_addr, host);
1174 
1175                                 cln->host = strdup(host);
1176                         } else if (strcmp(cln->nconf->nc_protofmly,
1177                             NC_INET6) == 0) {
1178                                 struct sockaddr_in6 *sa;
1179 
1180                                 /* LINTED pointer alignment */
1181                                 sa = (struct sockaddr_in6 *)(cln->nbuf->buf);
1182                                 (void) inet_ntop(AF_INET6,
1183                                     sa->sin6_addr.s6_addr,
1184                                     host, INET6_ADDRSTRLEN);
1185 
1186                                 cln->host = strdup(host);
1187                         } else {
1188                                 syslog(LOG_ERR, gettext("Client's address is "
1189                                     "neither IPv4 nor IPv6"));
1190 
1191                                 cln->host = strdup("(anon)");
1192                         }
1193                 }
1194 
1195                 cln->flags |= CLN_HOST;
1196         }
1197 
1198         return (cln->host);
1199 }
1200 
1201 /*
1202  * Check mount requests, add to mounted list if ok
1203  */
1204 static int
1205 mount(struct svc_req *rqstp)
1206 {
1207         SVCXPRT *transp;
1208         int version, vers;
1209         struct fhstatus fhs;
1210         struct mountres3 mountres3;
1211         char fh[FHSIZE3];
1212         int len = FHSIZE3;
1213         char *path, rpath[MAXPATHLEN];
1214         share_t *sh = NULL;
1215         struct cln cln;
1216         char *host = NULL;
1217         int error = 0, lofs_tried = 0, enqueued;
1218         int flavor_list[MAX_FLAVORS];
1219         int flavor_count;
1220         ucred_t *uc = NULL;
1221 
1222         int audit_status;
1223 
1224         transp = rqstp->rq_xprt;
1225         version = rqstp->rq_vers;
1226         path = NULL;
1227 
1228         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
1229                 svcerr_decode(transp);
1230                 return (EACCES);
1231         }
1232 
1233         cln_init(&cln, transp);
1234 
1235         /*
1236          * Put off getting the name for the client until we
1237          * need it. This is a performance gain. If we are logging,
1238          * then we don't care about performance and might as well
1239          * get the host name now in case we need to spit out an
1240          * error message.
1241          */
1242         if (verbose) {
1243                 DTRACE_PROBE(mountd, name_by_verbose);
1244                 if ((host = cln_gethost(&cln)) == NULL) {
1245                         /*
1246                          * We failed to get a name for the client, even
1247                          * 'anon', probably because we ran out of memory.
1248                          * In this situation it doesn't make sense to
1249                          * allow the mount to succeed.
1250                          */
1251                         error = EACCES;
1252                         goto reply;
1253                 }
1254         }
1255 
1256         /*
1257          * If the version being used is less than the minimum version,
1258          * the filehandle translation should not be provided to the
1259          * client.
1260          */
1261         if (rejecting || version < mount_vers_min) {
1262                 if (verbose)
1263                         syslog(LOG_NOTICE, "Rejected mount: %s for %s",
1264                             host, path);
1265                 error = EACCES;
1266                 goto reply;
1267         }
1268 
1269         /*
1270          * Trusted Extension doesn't support nfsv2. nfsv2 client
1271          * uses MOUNT protocol v1 and v2. To prevent circumventing
1272          * TX label policy via using nfsv2 client, reject a mount
1273          * request with version less than 3 and log an error.
1274          */
1275         if (is_system_labeled()) {
1276                 if (version < 3) {
1277                         if (verbose)
1278                                 syslog(LOG_ERR,
1279                                     "Rejected mount: TX doesn't support NFSv2");
1280                         error = EACCES;
1281                         goto reply;
1282                 }
1283         }
1284 
1285         /*
1286          * Get the real path (no symbolic links in it)
1287          */
1288         if (realpath(path, rpath) == NULL) {
1289                 error = errno;
1290                 if (verbose)
1291                         syslog(LOG_ERR,
1292                             "mount request: realpath: %s: %m", path);
1293                 if (error == ENOENT)
1294                         error = mount_enoent_error(&cln, path, rpath,
1295                             flavor_list);
1296                 goto reply;
1297         }
1298 
1299         if ((sh = findentry(rpath)) == NULL &&
1300             (sh = find_lofsentry(rpath, &lofs_tried)) == NULL) {
1301                 error = EACCES;
1302                 goto reply;
1303         }
1304 
1305         /*
1306          * Check if this is a "nosub" only export, in which case, mounting
1307          * subdirectories isn't allowed. Bug 1184573.
1308          */
1309         if (checkrootmount(sh, rpath) == 0) {
1310                 error = EACCES;
1311                 goto reply;
1312         }
1313 
1314         if (newopts(sh->sh_opts))
1315                 flavor_count = getclientsflavors_new(sh, &cln, flavor_list);
1316         else
1317                 flavor_count = getclientsflavors_old(sh, &cln, flavor_list);
1318 
1319         if (flavor_count == 0) {
1320                 error = EACCES;
1321                 goto reply;
1322         }
1323 
1324         /*
1325          * Check MAC policy here. The server side policy should be
1326          * consistent with client side mount policy, i.e.
1327          * - we disallow an admin_low unlabeled client to mount
1328          * - we disallow mount from a lower labeled client.
1329          */
1330         if (is_system_labeled()) {
1331                 m_label_t *clabel = NULL;
1332                 m_label_t *slabel = NULL;
1333                 m_label_t admin_low;
1334 
1335                 if (svc_getcallerucred(rqstp->rq_xprt, &uc) != 0) {
1336                         syslog(LOG_ERR,
1337                             "mount request: Failed to get caller's ucred : %m");
1338                         error = EACCES;
1339                         goto reply;
1340                 }
1341                 if ((clabel = ucred_getlabel(uc)) == NULL) {
1342                         syslog(LOG_ERR,
1343                             "mount request: can't get client label from ucred");
1344                         error = EACCES;
1345                         goto reply;
1346                 }
1347 
1348                 bsllow(&admin_low);
1349                 if (blequal(&admin_low, clabel)) {
1350                         struct sockaddr *ca;
1351                         tsol_tpent_t    *tp;
1352 
1353                         ca = (struct sockaddr *)(void *)svc_getrpccaller(
1354                             rqstp->rq_xprt)->buf;
1355                         if (ca == NULL) {
1356                                 error = EACCES;
1357                                 goto reply;
1358                         }
1359                         /*
1360                          * get trusted network template associated
1361                          * with the client.
1362                          */
1363                         tp = get_client_template(ca);
1364                         if (tp == NULL || tp->host_type != SUN_CIPSO) {
1365                                 if (tp != NULL)
1366                                         tsol_freetpent(tp);
1367                                 error = EACCES;
1368                                 goto reply;
1369                         }
1370                         tsol_freetpent(tp);
1371                 } else {
1372                         if ((slabel = m_label_alloc(MAC_LABEL)) == NULL) {
1373                                 error = EACCES;
1374                                 goto reply;
1375                         }
1376 
1377                         if (getlabel(rpath, slabel) != 0) {
1378                                 m_label_free(slabel);
1379                                 error = EACCES;
1380                                 goto reply;
1381                         }
1382 
1383                         if (!bldominates(clabel, slabel)) {
1384                                 m_label_free(slabel);
1385                                 error = EACCES;
1386                                 goto reply;
1387                         }
1388                         m_label_free(slabel);
1389                 }
1390         }
1391 
1392         /*
1393          * Now get the filehandle.
1394          *
1395          * NFS V2 clients get a 32 byte filehandle.
1396          * NFS V3 clients get a 32 or 64 byte filehandle, depending on
1397          * the embedded FIDs.
1398          */
1399         vers = (version == MOUNTVERS3) ? NFS_V3 : NFS_VERSION;
1400 
1401         /* LINTED pointer alignment */
1402         while (nfs_getfh(rpath, vers, &len, fh) < 0) {
1403                 if (errno == EINVAL &&
1404                     (sh = find_lofsentry(rpath, &lofs_tried)) != NULL) {
1405                         errno = 0;
1406                         continue;
1407                 }
1408                 error = errno == EINVAL ? EACCES : errno;
1409                 syslog(LOG_DEBUG, "mount request: getfh failed on %s: %m",
1410                     path);
1411                 break;
1412         }
1413 
1414         if (version == MOUNTVERS3) {
1415                 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_len = len;
1416                 mountres3.mountres3_u.mountinfo.fhandle.fhandle3_val = fh;
1417         } else {
1418                 bcopy(fh, &fhs.fhstatus_u.fhs_fhandle, NFS_FHSIZE);
1419         }
1420 
1421 reply:
1422         if (uc != NULL)
1423                 ucred_free(uc);
1424 
1425         switch (version) {
1426         case MOUNTVERS:
1427         case MOUNTVERS_POSIX:
1428                 if (error == EINVAL)
1429                         fhs.fhs_status = NFSERR_ACCES;
1430                 else if (error == EREMOTE)
1431                         fhs.fhs_status = NFSERR_REMOTE;
1432                 else
1433                         fhs.fhs_status = error;
1434 
1435                 if (!svc_sendreply(transp, xdr_fhstatus, (char *)&fhs))
1436                         log_cant_reply_cln(&cln);
1437 
1438                 audit_status = fhs.fhs_status;
1439                 break;
1440 
1441         case MOUNTVERS3:
1442                 if (!error) {
1443                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
1444                     flavor_list;
1445                 mountres3.mountres3_u.mountinfo.auth_flavors.auth_flavors_len =
1446                     flavor_count;
1447 
1448                 } else if (error == ENAMETOOLONG)
1449                         error = MNT3ERR_NAMETOOLONG;
1450 
1451                 mountres3.fhs_status = error;
1452                 if (!svc_sendreply(transp, xdr_mountres3, (char *)&mountres3))
1453                         log_cant_reply_cln(&cln);
1454 
1455                 audit_status = mountres3.fhs_status;
1456                 break;
1457         }
1458 
1459         if (cln_havehost(&cln))
1460                 host = cln_gethost(&cln);
1461 
1462         if (verbose)
1463                 syslog(LOG_NOTICE, "MOUNT: %s %s %s",
1464                     (host == NULL) ? "unknown host" : host,
1465                     error ? "denied" : "mounted", path);
1466 
1467         /*
1468          * If we can not create a queue entry, go ahead and do it
1469          * in the context of this thread.
1470          */
1471         enqueued = enqueue_logging_data(host, transp, path, rpath,
1472             audit_status, error);
1473         if (enqueued == FALSE) {
1474                 if (host == NULL) {
1475                         DTRACE_PROBE(mountd, name_by_in_thread);
1476                         host = cln_gethost(&cln);
1477                 }
1478 
1479                 DTRACE_PROBE(mountd, logged_in_thread);
1480                 audit_mountd_mount(host, path, audit_status); /* BSM */
1481                 if (!error)
1482                         mntlist_new(host, rpath); /* add entry to mount list */
1483         }
1484 
1485         if (path != NULL)
1486                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
1487 
1488         if (sh)
1489                 sharefree(sh);
1490 
1491         cln_fini(&cln);
1492 
1493         return (error);
1494 }
1495 
1496 /*
1497  * Determine whether two paths are within the same file system.
1498  * Returns nonzero (true) if paths are the same, zero (false) if
1499  * they are different.  If an error occurs, return false.
1500  *
1501  * Use the actual FSID if it's available (via getattrat()); otherwise,
1502  * fall back on st_dev.
1503  *
1504  * With ZFS snapshots, st_dev differs from the regular file system
1505  * versus the snapshot.  But the fsid is the same throughout.  Thus
1506  * the fsid is a better test.
1507  */
1508 static int
1509 same_file_system(const char *path1, const char *path2)
1510 {
1511         uint64_t fsid1, fsid2;
1512         struct stat64 st1, st2;
1513         nvlist_t *nvl1 = NULL;
1514         nvlist_t *nvl2 = NULL;
1515 
1516         if ((getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path1, &nvl1) == 0) &&
1517             (getattrat(AT_FDCWD, XATTR_VIEW_READONLY, path2, &nvl2) == 0) &&
1518             (nvlist_lookup_uint64(nvl1, A_FSID, &fsid1) == 0) &&
1519             (nvlist_lookup_uint64(nvl2, A_FSID, &fsid2) == 0)) {
1520                 nvlist_free(nvl1);
1521                 nvlist_free(nvl2);
1522                 /*
1523                  * We have found fsid's for both paths.
1524                  */
1525 
1526                 if (fsid1 == fsid2)
1527                         return (B_TRUE);
1528 
1529                 return (B_FALSE);
1530         }
1531 
1532         nvlist_free(nvl1);
1533         nvlist_free(nvl2);
1534 
1535         /*
1536          * We were unable to find fsid's for at least one of the paths.
1537          * fall back on st_dev.
1538          */
1539 
1540         if (stat64(path1, &st1) < 0) {
1541                 syslog(LOG_NOTICE, "%s: %m", path1);
1542                 return (B_FALSE);
1543         }
1544         if (stat64(path2, &st2) < 0) {
1545                 syslog(LOG_NOTICE, "%s: %m", path2);
1546                 return (B_FALSE);
1547         }
1548 
1549         if (st1.st_dev == st2.st_dev)
1550                 return (B_TRUE);
1551 
1552         return (B_FALSE);
1553 }
1554 
1555 share_t *
1556 findentry(char *path)
1557 {
1558         share_t *sh = NULL;
1559         struct sh_list *shp;
1560         char *p1, *p2;
1561 
1562         check_sharetab();
1563 
1564         (void) rw_rdlock(&sharetab_lock);
1565 
1566         for (shp = share_list; shp; shp = shp->shl_next) {
1567                 sh = shp->shl_sh;
1568                 for (p1 = sh->sh_path, p2 = path; *p1 == *p2; p1++, p2++)
1569                         if (*p1 == '\0')
1570                                 goto done;      /* exact match */
1571 
1572                 /*
1573                  * Now compare the pathnames for three cases:
1574                  *
1575                  * Parent: /export/foo          (no trailing slash on parent)
1576                  * Child:  /export/foo/bar
1577                  *
1578                  * Parent: /export/foo/         (trailing slash on parent)
1579                  * Child:  /export/foo/bar
1580                  *
1581                  * Parent: /export/foo/         (no trailing slash on child)
1582                  * Child:  /export/foo
1583                  */
1584                 if ((*p1 == '\0' && *p2 == '/') ||
1585                     (*p1 == '\0' && *(p1-1) == '/') ||
1586                     (*p2 == '\0' && *p1 == '/' && *(p1+1) == '\0')) {
1587                         /*
1588                          * We have a subdirectory.  Test whether the
1589                          * subdirectory is in the same file system.
1590                          */
1591                         if (same_file_system(path, sh->sh_path))
1592                                 goto done;
1593                 }
1594         }
1595 done:
1596         sh = shp ? sharedup(sh) : NULL;
1597 
1598         (void) rw_unlock(&sharetab_lock);
1599 
1600         return (sh);
1601 }
1602 
1603 
1604 static int
1605 is_substring(char **mntp, char **path)
1606 {
1607         char *p1 = *mntp, *p2 = *path;
1608 
1609         if (*p1 == '\0' && *p2 == '\0') /* exact match */
1610                 return (1);
1611         else if (*p1 == '\0' && *p2 == '/')
1612                 return (1);
1613         else if (*p1 == '\0' && *(p1-1) == '/') {
1614                 *path = --p2; /* we need the slash in p2 */
1615                 return (1);
1616         } else if (*p2 == '\0') {
1617                 while (*p1 == '/')
1618                         p1++;
1619                 if (*p1 == '\0') /* exact match */
1620                         return (1);
1621         }
1622         return (0);
1623 }
1624 
1625 /*
1626  * find_lofsentry() searches for the real path which this requested LOFS path
1627  * (rpath) shadows. If found, it will return the sharetab entry of
1628  * the real path that corresponds to the LOFS path.
1629  * We first search mnttab to see if the requested path is an automounted
1630  * path. If it is an automounted path, it will trigger the mount by stat()ing
1631  * the requested path. Note that it is important to check that this path is
1632  * actually an automounted path, otherwise we would stat() a path which may
1633  * turn out to be NFS and block indefinitely on a dead server. The automounter
1634  * times-out if the server is dead, so there's no risk of hanging this
1635  * thread waiting for stat().
1636  * After the mount has been triggered (if necessary), we look for a
1637  * mountpoint of type LOFS (by searching /etc/mnttab again) which
1638  * is a substring of the rpath. If found, we construct a new path by
1639  * concatenating the mnt_special and the remaining of rpath, call findentry()
1640  * to make sure the 'real path' is shared.
1641  */
1642 static share_t *
1643 find_lofsentry(char *rpath, int *done_flag)
1644 {
1645         struct stat r_stbuf;
1646         mntlist_t *ml, *mntl, *mntpnt = NULL;
1647         share_t *retcode = NULL;
1648         char tmp_path[MAXPATHLEN];
1649         int mntpnt_len = 0, tmp;
1650         char *p1, *p2;
1651 
1652         if ((*done_flag)++)
1653                 return (retcode);
1654 
1655         /*
1656          * While fsgetmntlist() uses lockf() to
1657          * lock the mnttab before reading it in,
1658          * the lock ignores threads in the same process.
1659          * Read in the mnttab with the protection of a mutex.
1660          */
1661         (void) mutex_lock(&mnttab_lock);
1662         mntl = fsgetmntlist();
1663         (void) mutex_unlock(&mnttab_lock);
1664 
1665         /*
1666          * Obtain the mountpoint for the requested path.
1667          */
1668         for (ml = mntl; ml; ml = ml->mntl_next) {
1669                 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1670                     *p1 == *p2 && *p1; p1++, p2++)
1671                         ;
1672                 if (is_substring(&p1, &p2) &&
1673                     (tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len) {
1674                         mntpnt = ml;
1675                         mntpnt_len = tmp;
1676                 }
1677         }
1678 
1679         /*
1680          * If the path needs to be autoFS mounted, trigger the mount by
1681          * stat()ing it. This is determined by checking whether the
1682          * mountpoint we just found is of type autofs.
1683          */
1684         if (mntpnt != NULL &&
1685             strcmp(mntpnt->mntl_mnt->mnt_fstype, "autofs") == 0) {
1686                 /*
1687                  * The requested path is a substring of an autoFS filesystem.
1688                  * Trigger the mount.
1689                  */
1690                 if (stat(rpath, &r_stbuf) < 0) {
1691                         if (verbose)
1692                                 syslog(LOG_NOTICE, "%s: %m", rpath);
1693                         goto done;
1694                 }
1695                 if ((r_stbuf.st_mode & S_IFMT) == S_IFDIR) {
1696                         /*
1697                          * The requested path is a directory, stat(2) it
1698                          * again with a trailing '.' to force the autoFS
1699                          * module to trigger the mount of indirect
1700                          * automount entries, such as /net/jurassic/.
1701                          */
1702                         if (strlen(rpath) + 2 > MAXPATHLEN) {
1703                                 if (verbose) {
1704                                         syslog(LOG_NOTICE,
1705                                             "%s/.: exceeds MAXPATHLEN %d",
1706                                             rpath, MAXPATHLEN);
1707                                 }
1708                                 goto done;
1709                         }
1710                         (void) strcpy(tmp_path, rpath);
1711                         (void) strcat(tmp_path, "/.");
1712 
1713                         if (stat(tmp_path, &r_stbuf) < 0) {
1714                                 if (verbose)
1715                                         syslog(LOG_NOTICE, "%s: %m", tmp_path);
1716                                 goto done;
1717                         }
1718                 }
1719 
1720                 /*
1721                  * The mount has been triggered, re-read mnttab to pick up
1722                  * the changes made by autoFS.
1723                  */
1724                 fsfreemntlist(mntl);
1725                 (void) mutex_lock(&mnttab_lock);
1726                 mntl = fsgetmntlist();
1727                 (void) mutex_unlock(&mnttab_lock);
1728         }
1729 
1730         /*
1731          * The autoFS mountpoint has been triggered if necessary,
1732          * now search mnttab again to determine if the requested path
1733          * is an LOFS mount of a shared path.
1734          */
1735         mntpnt_len = 0;
1736         for (ml = mntl; ml; ml = ml->mntl_next) {
1737                 if (strcmp(ml->mntl_mnt->mnt_fstype, "lofs"))
1738                         continue;
1739 
1740                 for (p1 = ml->mntl_mnt->mnt_mountp, p2 = rpath;
1741                     *p1 == *p2 && *p1; p1++, p2++)
1742                         ;
1743 
1744                 if (is_substring(&p1, &p2) &&
1745                     ((tmp = strlen(ml->mntl_mnt->mnt_mountp)) >= mntpnt_len)) {
1746                         mntpnt_len = tmp;
1747 
1748                         if ((strlen(ml->mntl_mnt->mnt_special) + strlen(p2)) >
1749                             MAXPATHLEN) {
1750                                 if (verbose) {
1751                                         syslog(LOG_NOTICE, "%s%s: exceeds %d",
1752                                             ml->mntl_mnt->mnt_special, p2,
1753                                             MAXPATHLEN);
1754                                 }
1755                                 if (retcode)
1756                                         sharefree(retcode);
1757                                 retcode = NULL;
1758                                 goto done;
1759                         }
1760 
1761                         (void) strcpy(tmp_path, ml->mntl_mnt->mnt_special);
1762                         (void) strcat(tmp_path, p2);
1763                         if (retcode)
1764                                 sharefree(retcode);
1765                         retcode = findentry(tmp_path);
1766                 }
1767         }
1768 
1769         if (retcode) {
1770                 assert(strlen(tmp_path) > 0);
1771                 (void) strcpy(rpath, tmp_path);
1772         }
1773 
1774 done:
1775         fsfreemntlist(mntl);
1776         return (retcode);
1777 }
1778 
1779 /*
1780  * Determine whether an access list grants rights to a particular host.
1781  * We match on aliases of the hostname as well as on the canonical name.
1782  * Names in the access list may be either hosts or netgroups;  they're
1783  * not distinguished syntactically.  We check for hosts first because
1784  * it's cheaper, then try netgroups.
1785  *
1786  * Return values:
1787  *  1 - access is granted
1788  *  0 - access is denied
1789  * -1 - an error occured
1790  */
1791 int
1792 in_access_list(struct cln *cln,
1793     char *access_list)  /* N.B. we clobber this "input" parameter */
1794 {
1795         char addr[INET_ADDRSTRLEN];
1796         char buff[256];
1797         int nentries = 0;
1798         char *cstr = access_list;
1799         char *gr = access_list;
1800         int i;
1801         int response;
1802         int ret;
1803         struct netbuf *pnb;
1804         struct nd_hostservlist *clnames = NULL;
1805 
1806         /* If no access list - then it's unrestricted */
1807         if (access_list == NULL || *access_list == '\0')
1808                 return (1);
1809 
1810         if ((pnb = cln_getnbuf(cln)) == NULL)
1811                 return (-1);
1812 
1813         for (;;) {
1814                 if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1815                         if (*cstr == ':') {
1816                                 *cstr = '\0';
1817                         } else {
1818                                 assert(*cstr == '[');
1819                                 cstr = strchr(cstr + 1, ']');
1820                                 if (cstr == NULL)
1821                                         return (-1);
1822                                 cstr++;
1823                                 continue;
1824                         }
1825                 }
1826 
1827                 /*
1828                  * If the list name has a '-' prepended then a match of
1829                  * the following name implies failure instead of success.
1830                  */
1831                 if (*gr == '-') {
1832                         response = 0;
1833                         gr++;
1834                 } else {
1835                         response = 1;
1836                 }
1837 
1838                 /*
1839                  * First check if we have '@' entry, as it doesn't
1840                  * require client hostname.
1841                  */
1842                 if (*gr == '@') {
1843                         gr++;
1844 
1845                         /* Netname support */
1846                         if (!isdigit(*gr) && *gr != '[') {
1847                                 struct netent n, *np;
1848 
1849                                 if ((np = getnetbyname_r(gr, &n, buff,
1850                                     sizeof (buff))) != NULL &&
1851                                     np->n_net != 0) {
1852                                         while ((np->n_net & 0xFF000000u) == 0)
1853                                                 np->n_net <<= 8;
1854                                         np->n_net = htonl(np->n_net);
1855                                         if (inet_ntop(AF_INET, &np->n_net, addr,
1856                                             INET_ADDRSTRLEN) == NULL)
1857                                                 break;
1858                                         ret = inet_matchaddr(pnb->buf, addr);
1859                                         if (ret == -1) {
1860                                                 if (errno == EINVAL) {
1861                                                         syslog(LOG_WARNING,
1862                                                             "invalid access "
1863                                                             "list entry: %s",
1864                                                             addr);
1865                                                 }
1866                                                 return (-1);
1867                                         } else if (ret == 1) {
1868                                                 return (response);
1869                                         }
1870                                 }
1871                         } else {
1872                                 ret = inet_matchaddr(pnb->buf, gr);
1873                                 if (ret == -1) {
1874                                         if (errno == EINVAL) {
1875                                                 syslog(LOG_WARNING,
1876                                                     "invalid access list "
1877                                                     "entry: %s", gr);
1878                                         }
1879                                         return (-1);
1880                                 } else if (ret == 1) {
1881                                         return (response);
1882                                 }
1883                         }
1884 
1885                         goto next;
1886                 }
1887 
1888                 /*
1889                  * No other checks can be performed if client address
1890                  * can't be resolved.
1891                  */
1892                 if ((clnames = cln_getclientsnames(cln)) == NULL)
1893                         goto next;
1894 
1895                 /* Otherwise loop through all client hostname aliases */
1896                 for (i = 0; i < clnames->h_cnt; i++) {
1897                         char *host = clnames->h_hostservs[i].h_host;
1898 
1899                         /*
1900                          * If the list name begins with a dot then
1901                          * do a domain name suffix comparison.
1902                          * A single dot matches any name with no
1903                          * suffix.
1904                          */
1905                         if (*gr == '.') {
1906                                 if (*(gr + 1) == '\0') {  /* single dot */
1907                                         if (strchr(host, '.') == NULL)
1908                                                 return (response);
1909                                 } else {
1910                                         int off = strlen(host) - strlen(gr);
1911                                         if (off > 0 &&
1912                                             strcasecmp(host + off, gr) == 0) {
1913                                                 return (response);
1914                                         }
1915                                 }
1916                         } else {
1917                                 /* Just do a hostname match */
1918                                 if (strcasecmp(gr, host) == 0)
1919                                         return (response);
1920                         }
1921                 }
1922 
1923                 nentries++;
1924 
1925 next:
1926                 if (cstr == NULL)
1927                         break;
1928 
1929                 gr = ++cstr;
1930         }
1931 
1932         if (clnames == NULL)
1933                 return (0);
1934 
1935         return (netgroup_check(clnames, access_list, nentries));
1936 }
1937 
1938 
1939 static char *optlist[] = {
1940 #define OPT_RO          0
1941         SHOPT_RO,
1942 #define OPT_RW          1
1943         SHOPT_RW,
1944 #define OPT_ROOT        2
1945         SHOPT_ROOT,
1946 #define OPT_SECURE      3
1947         SHOPT_SECURE,
1948 #define OPT_ANON        4
1949         SHOPT_ANON,
1950 #define OPT_WINDOW      5
1951         SHOPT_WINDOW,
1952 #define OPT_NOSUID      6
1953         SHOPT_NOSUID,
1954 #define OPT_ACLOK       7
1955         SHOPT_ACLOK,
1956 #define OPT_SEC         8
1957         SHOPT_SEC,
1958 #define OPT_NONE        9
1959         SHOPT_NONE,
1960 #define OPT_UIDMAP      10
1961         SHOPT_UIDMAP,
1962 #define OPT_GIDMAP      11
1963         SHOPT_GIDMAP,
1964         NULL
1965 };
1966 
1967 static int
1968 map_flavor(char *str)
1969 {
1970         seconfig_t sec;
1971 
1972         if (nfs_getseconfig_byname(str, &sec))
1973                 return (-1);
1974 
1975         return (sec.sc_nfsnum);
1976 }
1977 
1978 /*
1979  * If the option string contains a "sec="
1980  * option, then use new option syntax.
1981  */
1982 static int
1983 newopts(char *opts)
1984 {
1985         char *head, *p, *val;
1986 
1987         if (!opts || *opts == '\0')
1988                 return (0);
1989 
1990         head = strdup(opts);
1991         if (head == NULL) {
1992                 syslog(LOG_ERR, "opts: no memory");
1993                 return (0);
1994         }
1995 
1996         p = head;
1997         while (*p) {
1998                 if (getsubopt(&p, optlist, &val) == OPT_SEC) {
1999                         free(head);
2000                         return (1);
2001                 }
2002         }
2003 
2004         free(head);
2005         return (0);
2006 }
2007 
2008 /*
2009  * Given an export and the clients hostname(s)
2010  * determine the security flavors that this
2011  * client is permitted to use.
2012  *
2013  * This routine is called only for "old" syntax, i.e.
2014  * only one security flavor is allowed.  So we need
2015  * to determine two things: the particular flavor,
2016  * and whether the client is allowed to use this
2017  * flavor, i.e. is in the access list.
2018  *
2019  * Note that if there is no access list, then the
2020  * default is that access is granted.
2021  */
2022 static int
2023 getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
2024 {
2025         char *opts, *p, *val;
2026         boolean_t ok = B_FALSE;
2027         int defaultaccess = 1;
2028         boolean_t reject = B_FALSE;
2029 
2030         opts = strdup(sh->sh_opts);
2031         if (opts == NULL) {
2032                 syslog(LOG_ERR, "getclientsflavors: no memory");
2033                 return (0);
2034         }
2035 
2036         flavors[0] = AUTH_SYS;
2037         p = opts;
2038 
2039         while (*p) {
2040 
2041                 switch (getsubopt(&p, optlist, &val)) {
2042                 case OPT_SECURE:
2043                         flavors[0] = AUTH_DES;
2044                         break;
2045 
2046                 case OPT_RO:
2047                 case OPT_RW:
2048                         defaultaccess = 0;
2049                         if (in_access_list(cln, val) > 0)
2050                                 ok = B_TRUE;
2051                         break;
2052 
2053                 case OPT_NONE:
2054                         defaultaccess = 0;
2055                         if (in_access_list(cln, val) > 0)
2056                                 reject = B_TRUE;
2057                 }
2058         }
2059 
2060         free(opts);
2061 
2062         /* none takes precedence over everything else */
2063         if (reject)
2064                 ok = B_FALSE;
2065 
2066         return (defaultaccess || ok);
2067 }
2068 
2069 /*
2070  * Given an export and the clients hostname(s)
2071  * determine the security flavors that this
2072  * client is permitted to use.
2073  *
2074  * This is somewhat more complicated than the "old"
2075  * routine because the options may contain multiple
2076  * security flavors (sec=) each with its own access
2077  * lists.  So a client could be granted access based
2078  * on a number of security flavors.  Note that the
2079  * type of access might not always be the same, the
2080  * client may get readonly access with one flavor
2081  * and readwrite with another, however the client
2082  * is not told this detail, it gets only the list
2083  * of flavors, and only if the client is using
2084  * version 3 of the mount protocol.
2085  */
2086 static int
2087 getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
2088 {
2089         char *opts, *p, *val;
2090         char *lasts;
2091         char *f;
2092         boolean_t defaultaccess = B_TRUE;       /* default access is rw */
2093         boolean_t access_ok = B_FALSE;
2094         int count, c;
2095         boolean_t reject = B_FALSE;
2096 
2097         opts = strdup(sh->sh_opts);
2098         if (opts == NULL) {
2099                 syslog(LOG_ERR, "getclientsflavors: no memory");
2100                 return (0);
2101         }
2102 
2103         p = opts;
2104         count = c = 0;
2105 
2106         while (*p) {
2107                 switch (getsubopt(&p, optlist, &val)) {
2108                 case OPT_SEC:
2109                         if (reject)
2110                                 access_ok = B_FALSE;
2111 
2112                         /*
2113                          * Before a new sec=xxx option, check if we need
2114                          * to move the c index back to the previous count.
2115                          */
2116                         if (!defaultaccess && !access_ok) {
2117                                 c = count;
2118                         }
2119 
2120                         /* get all the sec=f1[:f2] flavors */
2121                         while ((f = strtok_r(val, ":", &lasts)) != NULL) {
2122                                 flavors[c++] = map_flavor(f);
2123                                 val = NULL;
2124                         }
2125 
2126                         /* for a new sec=xxx option, default is rw access */
2127                         defaultaccess = B_TRUE;
2128                         access_ok = B_FALSE;
2129                         reject = B_FALSE;
2130                         break;
2131 
2132                 case OPT_RO:
2133                 case OPT_RW:
2134                         defaultaccess = B_FALSE;
2135                         if (in_access_list(cln, val) > 0)
2136                                 access_ok = B_TRUE;
2137                         break;
2138 
2139                 case OPT_NONE:
2140                         defaultaccess = B_FALSE;
2141                         if (in_access_list(cln, val) > 0)
2142                                 reject = B_TRUE; /* none overides rw/ro */
2143                         break;
2144                 }
2145         }
2146 
2147         if (reject)
2148                 access_ok = B_FALSE;
2149 
2150         if (!defaultaccess && !access_ok)
2151                 c = count;
2152 
2153         free(opts);
2154 
2155         return (c);
2156 }
2157 
2158 /*
2159  * This is a tricky piece of code that parses the
2160  * share options looking for a match on the auth
2161  * flavor that the client is using. If it finds
2162  * a match, then the client is given ro, rw, or
2163  * no access depending whether it is in the access
2164  * list.  There is a special case for "secure"
2165  * flavor.  Other flavors are values of the new "sec=" option.
2166  */
2167 int
2168 check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2169     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2170     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2171 {
2172         if (newopts(sh->sh_opts))
2173                 return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2174                     clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2175                     srv_gids));
2176         else
2177                 return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2178                     clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2179                     srv_gids));
2180 }
2181 
2182 extern int _getgroupsbymember(const char *, gid_t[], int, int);
2183 
2184 /*
2185  * Get supplemental groups for uid
2186  */
2187 static int
2188 getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
2189 {
2190         struct passwd pwd;
2191         char *pwbuf = alloca(pw_size);
2192         gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
2193         int tmpngrps;
2194 
2195         if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
2196                 return (-1);
2197 
2198         tmpgrps[0] = pwd.pw_gid;
2199 
2200         tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
2201         if (tmpngrps <= 0) {
2202                 syslog(LOG_WARNING,
2203                     "getusergroups(): Unable to get groups for user %s",
2204                     pwd.pw_name);
2205 
2206                 return (-1);
2207         }
2208 
2209         *grps = malloc(tmpngrps * sizeof (gid_t));
2210         if (*grps == NULL) {
2211                 syslog(LOG_ERR,
2212                     "getusergroups(): Memory allocation failed: %m");
2213 
2214                 return (-1);
2215         }
2216 
2217         *ngrps = tmpngrps;
2218         (void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
2219 
2220         return (0);
2221 }
2222 
2223 /*
2224  * is_a_number(number)
2225  *
2226  * is the string a number in one of the forms we want to use?
2227  */
2228 
2229 static int
2230 is_a_number(char *number)
2231 {
2232         int ret = 1;
2233         int hex = 0;
2234 
2235         if (strncmp(number, "0x", 2) == 0) {
2236                 number += 2;
2237                 hex = 1;
2238         } else if (*number == '-') {
2239                 number++; /* skip the minus */
2240         }
2241         while (ret == 1 && *number != '\0') {
2242                 if (hex) {
2243                         ret = isxdigit(*number++);
2244                 } else {
2245                         ret = isdigit(*number++);
2246                 }
2247         }
2248         return (ret);
2249 }
2250 
2251 static boolean_t
2252 get_uid(char *value, uid_t *uid)
2253 {
2254         if (!is_a_number(value)) {
2255                 struct passwd *pw;
2256                 /*
2257                  * in this case it would have to be a
2258                  * user name
2259                  */
2260                 pw = getpwnam(value);
2261                 if (pw == NULL)
2262                         return (B_FALSE);
2263                 *uid = pw->pw_uid;
2264                 endpwent();
2265         } else {
2266                 uint64_t intval;
2267                 intval = strtoull(value, NULL, 0);
2268                 if (intval > UID_MAX && intval != -1)
2269                         return (B_FALSE);
2270                 *uid = (uid_t)intval;
2271         }
2272 
2273         return (B_TRUE);
2274 }
2275 
2276 static boolean_t
2277 get_gid(char *value, gid_t *gid)
2278 {
2279         if (!is_a_number(value)) {
2280                 struct group *gr;
2281                 /*
2282                  * in this case it would have to be a
2283                  * group name
2284                  */
2285                 gr = getgrnam(value);
2286                 if (gr == NULL)
2287                         return (B_FALSE);
2288                 *gid = gr->gr_gid;
2289                 endgrent();
2290         } else {
2291                 uint64_t intval;
2292                 intval = strtoull(value, NULL, 0);
2293                 if (intval > UID_MAX && intval != -1)
2294                         return (B_FALSE);
2295                 *gid = (gid_t)intval;
2296         }
2297 
2298         return (B_TRUE);
2299 }
2300 
2301 static int
2302 check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2303     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2304     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2305 {
2306         char *opts, *p, *val;
2307         int match;      /* Set when a flavor is matched */
2308         int perm = 0;   /* Set when "ro", "rw" or "root" is matched */
2309         int list = 0;   /* Set when "ro", "rw" is found */
2310         int ro_val = 0; /* Set if ro option is 'ro=' */
2311         int rw_val = 0; /* Set if rw option is 'rw=' */
2312 
2313         boolean_t map_deny = B_FALSE;
2314 
2315         opts = strdup(sh->sh_opts);
2316         if (opts == NULL) {
2317                 syslog(LOG_ERR, "check_client: no memory");
2318                 return (0);
2319         }
2320 
2321         /*
2322          * If client provided 16 supplemental groups with AUTH_SYS, lookup
2323          * locally for all of them
2324          */
2325         if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2326                 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2327                         perm |= NFSAUTH_GROUPS;
2328 
2329         p = opts;
2330         match = AUTH_UNIX;
2331 
2332         while (*p) {
2333                 switch (getsubopt(&p, optlist, &val)) {
2334 
2335                 case OPT_SECURE:
2336                         match = AUTH_DES;
2337 
2338                         if (perm & NFSAUTH_GROUPS) {
2339                                 free(*srv_gids);
2340                                 *srv_ngids = 0;
2341                                 *srv_gids = NULL;
2342                                 perm &= ~NFSAUTH_GROUPS;
2343                         }
2344 
2345                         break;
2346 
2347                 case OPT_RO:
2348                         list++;
2349                         if (val != NULL)
2350                                 ro_val++;
2351                         if (in_access_list(cln, val) > 0)
2352                                 perm |= NFSAUTH_RO;
2353                         break;
2354 
2355                 case OPT_RW:
2356                         list++;
2357                         if (val != NULL)
2358                                 rw_val++;
2359                         if (in_access_list(cln, val) > 0)
2360                                 perm |= NFSAUTH_RW;
2361                         break;
2362 
2363                 case OPT_ROOT:
2364                         /*
2365                          * Check if the client is in
2366                          * the root list. Only valid
2367                          * for AUTH_SYS.
2368                          */
2369                         if (flavor != AUTH_SYS)
2370                                 break;
2371 
2372                         if (val == NULL || *val == '\0')
2373                                 break;
2374 
2375                         if (clnt_uid != 0)
2376                                 break;
2377 
2378                         if (in_access_list(cln, val) > 0) {
2379                                 perm |= NFSAUTH_ROOT;
2380                                 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2381                                 map_deny = B_FALSE;
2382 
2383                                 if (perm & NFSAUTH_GROUPS) {
2384                                         free(*srv_gids);
2385                                         *srv_ngids = 0;
2386                                         *srv_gids = NULL;
2387                                         perm &= ~NFSAUTH_GROUPS;
2388                                 }
2389                         }
2390                         break;
2391 
2392                 case OPT_NONE:
2393                         /*
2394                          * Check if the client should have no access
2395                          * to this share at all. This option behaves
2396                          * more like "root" than either "rw" or "ro".
2397                          */
2398                         if (in_access_list(cln, val) > 0)
2399                                 perm |= NFSAUTH_DENIED;
2400                         break;
2401 
2402                 case OPT_UIDMAP: {
2403                         char *c;
2404                         char *n;
2405 
2406                         /*
2407                          * The uidmap is supported for AUTH_SYS only.
2408                          */
2409                         if (flavor != AUTH_SYS)
2410                                 break;
2411 
2412                         if (perm & NFSAUTH_UIDMAP || map_deny)
2413                                 break;
2414 
2415                         for (c = val; c != NULL; c = n) {
2416                                 char *s;
2417                                 char *al;
2418                                 uid_t srv;
2419 
2420                                 n = strchr(c, '~');
2421                                 if (n != NULL)
2422                                         *n++ = '\0';
2423 
2424                                 s = strchr(c, ':');
2425                                 if (s != NULL) {
2426                                         *s++ = '\0';
2427                                         al = strchr(s, ':');
2428                                         if (al != NULL)
2429                                                 *al++ = '\0';
2430                                 }
2431 
2432                                 if (s == NULL || al == NULL)
2433                                         continue;
2434 
2435                                 if (*c == '\0') {
2436                                         if (clnt_uid != (uid_t)-1)
2437                                                 continue;
2438                                 } else if (strcmp(c, "*") != 0) {
2439                                         uid_t clnt;
2440 
2441                                         if (!get_uid(c, &clnt))
2442                                                 continue;
2443 
2444                                         if (clnt_uid != clnt)
2445                                                 continue;
2446                                 }
2447 
2448                                 if (*s == '\0')
2449                                         srv = UID_NOBODY;
2450                                 else if (!get_uid(s, &srv))
2451                                         continue;
2452                                 else if (srv == (uid_t)-1) {
2453                                         map_deny = B_TRUE;
2454                                         break;
2455                                 }
2456 
2457                                 if (in_access_list(cln, al) > 0) {
2458                                         *srv_uid = srv;
2459                                         perm |= NFSAUTH_UIDMAP;
2460 
2461                                         if (perm & NFSAUTH_GROUPS) {
2462                                                 free(*srv_gids);
2463                                                 *srv_ngids = 0;
2464                                                 *srv_gids = NULL;
2465                                                 perm &= ~NFSAUTH_GROUPS;
2466                                         }
2467 
2468                                         break;
2469                                 }
2470                         }
2471 
2472                         break;
2473                 }
2474 
2475                 case OPT_GIDMAP: {
2476                         char *c;
2477                         char *n;
2478 
2479                         /*
2480                          * The gidmap is supported for AUTH_SYS only.
2481                          */
2482                         if (flavor != AUTH_SYS)
2483                                 break;
2484 
2485                         if (perm & NFSAUTH_GIDMAP || map_deny)
2486                                 break;
2487 
2488                         for (c = val; c != NULL; c = n) {
2489                                 char *s;
2490                                 char *al;
2491                                 gid_t srv;
2492 
2493                                 n = strchr(c, '~');
2494                                 if (n != NULL)
2495                                         *n++ = '\0';
2496 
2497                                 s = strchr(c, ':');
2498                                 if (s != NULL) {
2499                                         *s++ = '\0';
2500                                         al = strchr(s, ':');
2501                                         if (al != NULL)
2502                                                 *al++ = '\0';
2503                                 }
2504 
2505                                 if (s == NULL || al == NULL)
2506                                         break;
2507 
2508                                 if (*c == '\0') {
2509                                         if (clnt_gid != (gid_t)-1)
2510                                                 continue;
2511                                 } else if (strcmp(c, "*") != 0) {
2512                                         gid_t clnt;
2513 
2514                                         if (!get_gid(c, &clnt))
2515                                                 continue;
2516 
2517                                         if (clnt_gid != clnt)
2518                                                 continue;
2519                                 }
2520 
2521                                 if (*s == '\0')
2522                                         srv = UID_NOBODY;
2523                                 else if (!get_gid(s, &srv))
2524                                         continue;
2525                                 else if (srv == (gid_t)-1) {
2526                                         map_deny = B_TRUE;
2527                                         break;
2528                                 }
2529 
2530                                 if (in_access_list(cln, al) > 0) {
2531                                         *srv_gid = srv;
2532                                         perm |= NFSAUTH_GIDMAP;
2533 
2534                                         if (perm & NFSAUTH_GROUPS) {
2535                                                 free(*srv_gids);
2536                                                 *srv_ngids = 0;
2537                                                 *srv_gids = NULL;
2538                                                 perm &= ~NFSAUTH_GROUPS;
2539                                         }
2540 
2541                                         break;
2542                                 }
2543                         }
2544 
2545                         break;
2546                 }
2547 
2548                 default:
2549                         break;
2550                 }
2551         }
2552 
2553         free(opts);
2554 
2555         if (perm & NFSAUTH_ROOT) {
2556                 *srv_uid = 0;
2557                 *srv_gid = 0;
2558         }
2559 
2560         if (map_deny)
2561                 perm |= NFSAUTH_DENIED;
2562 
2563         if (!(perm & NFSAUTH_UIDMAP))
2564                 *srv_uid = clnt_uid;
2565         if (!(perm & NFSAUTH_GIDMAP))
2566                 *srv_gid = clnt_gid;
2567 
2568         if (flavor != match || perm & NFSAUTH_DENIED)
2569                 return (NFSAUTH_DENIED);
2570 
2571         if (list) {
2572                 /*
2573                  * If the client doesn't match an "ro" or "rw"
2574                  * list then set no access.
2575                  */
2576                 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2577                         perm |= NFSAUTH_DENIED;
2578         } else {
2579                 /*
2580                  * The client matched a flavor entry that
2581                  * has no explicit "rw" or "ro" determination.
2582                  * Default it to "rw".
2583                  */
2584                 perm |= NFSAUTH_RW;
2585         }
2586 
2587         /*
2588          * The client may show up in both ro= and rw=
2589          * lists.  If so, then turn off the RO access
2590          * bit leaving RW access.
2591          */
2592         if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2593                 /*
2594                  * Logically cover all permutations of rw=,ro=.
2595                  * In the case where, rw,ro=<host> we would like
2596                  * to remove RW access for the host.  In all other cases
2597                  * RW wins the precedence battle.
2598                  */
2599                 if (!rw_val && ro_val) {
2600                         perm &= ~(NFSAUTH_RW);
2601                 } else {
2602                         perm &= ~(NFSAUTH_RO);
2603                 }
2604         }
2605 
2606         return (perm);
2607 }
2608 
2609 /*
2610  * Check if the client has access by using a flavor different from
2611  * the given "flavor". If "flavor" is not in the flavor list,
2612  * return TRUE to indicate that this "flavor" is a wrong sec.
2613  */
2614 static bool_t
2615 is_wrongsec(share_t *sh, struct cln *cln, int flavor)
2616 {
2617         int flavor_list[MAX_FLAVORS];
2618         int flavor_count, i;
2619 
2620         /* get the flavor list that the client has access with */
2621         flavor_count = getclientsflavors_new(sh, cln, flavor_list);
2622 
2623         if (flavor_count == 0)
2624                 return (FALSE);
2625 
2626         /*
2627          * Check if the given "flavor" is in the flavor_list.
2628          */
2629         for (i = 0; i < flavor_count; i++) {
2630                 if (flavor == flavor_list[i])
2631                         return (FALSE);
2632         }
2633 
2634         /*
2635          * If "flavor" is not in the flavor_list, return TRUE to indicate
2636          * that the client should have access by using a security flavor
2637          * different from this "flavor".
2638          */
2639         return (TRUE);
2640 }
2641 
2642 /*
2643  * Given an export and the client's hostname, we
2644  * check the security options to see whether the
2645  * client is allowed to use the given security flavor.
2646  *
2647  * The strategy is to proceed through the options looking
2648  * for a flavor match, then pay attention to the ro, rw,
2649  * and root options.
2650  *
2651  * Note that an entry may list several flavors in a
2652  * single entry, e.g.
2653  *
2654  *   sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2655  *
2656  */
2657 
2658 static int
2659 check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2660     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2661     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2662 {
2663         char *opts, *p, *val;
2664         char *lasts;
2665         char *f;
2666         int match = 0;  /* Set when a flavor is matched */
2667         int perm = 0;   /* Set when "ro", "rw" or "root" is matched */
2668         int list = 0;   /* Set when "ro", "rw" is found */
2669         int ro_val = 0; /* Set if ro option is 'ro=' */
2670         int rw_val = 0; /* Set if rw option is 'rw=' */
2671 
2672         boolean_t map_deny = B_FALSE;
2673 
2674         opts = strdup(sh->sh_opts);
2675         if (opts == NULL) {
2676                 syslog(LOG_ERR, "check_client: no memory");
2677                 return (0);
2678         }
2679 
2680         /*
2681          * If client provided 16 supplemental groups with AUTH_SYS, lookup
2682          * locally for all of them
2683          */
2684         if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2685                 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2686                         perm |= NFSAUTH_GROUPS;
2687 
2688         p = opts;
2689 
2690         while (*p) {
2691                 switch (getsubopt(&p, optlist, &val)) {
2692 
2693                 case OPT_SEC:
2694                         if (match)
2695                                 goto done;
2696 
2697                         while ((f = strtok_r(val, ":", &lasts))
2698                             != NULL) {
2699                                 if (flavor == map_flavor(f)) {
2700                                         match = 1;
2701                                         break;
2702                                 }
2703                                 val = NULL;
2704                         }
2705                         break;
2706 
2707                 case OPT_RO:
2708                         if (!match)
2709                                 break;
2710 
2711                         list++;
2712                         if (val != NULL)
2713                                 ro_val++;
2714                         if (in_access_list(cln, val) > 0)
2715                                 perm |= NFSAUTH_RO;
2716                         break;
2717 
2718                 case OPT_RW:
2719                         if (!match)
2720                                 break;
2721 
2722                         list++;
2723                         if (val != NULL)
2724                                 rw_val++;
2725                         if (in_access_list(cln, val) > 0)
2726                                 perm |= NFSAUTH_RW;
2727                         break;
2728 
2729                 case OPT_ROOT:
2730                         /*
2731                          * Check if the client is in
2732                          * the root list. Only valid
2733                          * for AUTH_SYS.
2734                          */
2735                         if (flavor != AUTH_SYS)
2736                                 break;
2737 
2738                         if (!match)
2739                                 break;
2740 
2741                         if (val == NULL || *val == '\0')
2742                                 break;
2743 
2744                         if (clnt_uid != 0)
2745                                 break;
2746 
2747                         if (in_access_list(cln, val) > 0) {
2748                                 perm |= NFSAUTH_ROOT;
2749                                 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2750                                 map_deny = B_FALSE;
2751 
2752                                 if (perm & NFSAUTH_GROUPS) {
2753                                         free(*srv_gids);
2754                                         *srv_gids = NULL;
2755                                         *srv_ngids = 0;
2756                                         perm &= ~NFSAUTH_GROUPS;
2757                                 }
2758                         }
2759                         break;
2760 
2761                 case OPT_NONE:
2762                         /*
2763                          * Check if the client should have no access
2764                          * to this share at all. This option behaves
2765                          * more like "root" than either "rw" or "ro".
2766                          */
2767                         if (in_access_list(cln, val) > 0)
2768                                 perm |= NFSAUTH_DENIED;
2769                         break;
2770 
2771                 case OPT_UIDMAP: {
2772                         char *c;
2773                         char *n;
2774 
2775                         /*
2776                          * The uidmap is supported for AUTH_SYS only.
2777                          */
2778                         if (flavor != AUTH_SYS)
2779                                 break;
2780 
2781                         if (!match || perm & NFSAUTH_UIDMAP || map_deny)
2782                                 break;
2783 
2784                         for (c = val; c != NULL; c = n) {
2785                                 char *s;
2786                                 char *al;
2787                                 uid_t srv;
2788 
2789                                 n = strchr(c, '~');
2790                                 if (n != NULL)
2791                                         *n++ = '\0';
2792 
2793                                 s = strchr(c, ':');
2794                                 if (s != NULL) {
2795                                         *s++ = '\0';
2796                                         al = strchr(s, ':');
2797                                         if (al != NULL)
2798                                                 *al++ = '\0';
2799                                 }
2800 
2801                                 if (s == NULL || al == NULL)
2802                                         continue;
2803 
2804                                 if (*c == '\0') {
2805                                         if (clnt_uid != (uid_t)-1)
2806                                                 continue;
2807                                 } else if (strcmp(c, "*") != 0) {
2808                                         uid_t clnt;
2809 
2810                                         if (!get_uid(c, &clnt))
2811                                                 continue;
2812 
2813                                         if (clnt_uid != clnt)
2814                                                 continue;
2815                                 }
2816 
2817                                 if (*s == '\0')
2818                                         srv = UID_NOBODY;
2819                                 else if (!get_uid(s, &srv))
2820                                         continue;
2821                                 else if (srv == (uid_t)-1) {
2822                                         map_deny = B_TRUE;
2823                                         break;
2824                                 }
2825 
2826                                 if (in_access_list(cln, al) > 0) {
2827                                         *srv_uid = srv;
2828                                         perm |= NFSAUTH_UIDMAP;
2829 
2830                                         if (perm & NFSAUTH_GROUPS) {
2831                                                 free(*srv_gids);
2832                                                 *srv_gids = NULL;
2833                                                 *srv_ngids = 0;
2834                                                 perm &= ~NFSAUTH_GROUPS;
2835                                         }
2836 
2837                                         break;
2838                                 }
2839                         }
2840 
2841                         break;
2842                 }
2843 
2844                 case OPT_GIDMAP: {
2845                         char *c;
2846                         char *n;
2847 
2848                         /*
2849                          * The gidmap is supported for AUTH_SYS only.
2850                          */
2851                         if (flavor != AUTH_SYS)
2852                                 break;
2853 
2854                         if (!match || perm & NFSAUTH_GIDMAP || map_deny)
2855                                 break;
2856 
2857                         for (c = val; c != NULL; c = n) {
2858                                 char *s;
2859                                 char *al;
2860                                 gid_t srv;
2861 
2862                                 n = strchr(c, '~');
2863                                 if (n != NULL)
2864                                         *n++ = '\0';
2865 
2866                                 s = strchr(c, ':');
2867                                 if (s != NULL) {
2868                                         *s++ = '\0';
2869                                         al = strchr(s, ':');
2870                                         if (al != NULL)
2871                                                 *al++ = '\0';
2872                                 }
2873 
2874                                 if (s == NULL || al == NULL)
2875                                         break;
2876 
2877                                 if (*c == '\0') {
2878                                         if (clnt_gid != (gid_t)-1)
2879                                                 continue;
2880                                 } else if (strcmp(c, "*") != 0) {
2881                                         gid_t clnt;
2882 
2883                                         if (!get_gid(c, &clnt))
2884                                                 continue;
2885 
2886                                         if (clnt_gid != clnt)
2887                                                 continue;
2888                                 }
2889 
2890                                 if (*s == '\0')
2891                                         srv = UID_NOBODY;
2892                                 else if (!get_gid(s, &srv))
2893                                         continue;
2894                                 else if (srv == (gid_t)-1) {
2895                                         map_deny = B_TRUE;
2896                                         break;
2897                                 }
2898 
2899                                 if (in_access_list(cln, al) > 0) {
2900                                         *srv_gid = srv;
2901                                         perm |= NFSAUTH_GIDMAP;
2902 
2903                                         if (perm & NFSAUTH_GROUPS) {
2904                                                 free(*srv_gids);
2905                                                 *srv_gids = NULL;
2906                                                 *srv_ngids = 0;
2907                                                 perm &= ~NFSAUTH_GROUPS;
2908                                         }
2909 
2910                                         break;
2911                                 }
2912                         }
2913 
2914                         break;
2915                 }
2916 
2917                 default:
2918                         break;
2919                 }
2920         }
2921 
2922 done:
2923         if (perm & NFSAUTH_ROOT) {
2924                 *srv_uid = 0;
2925                 *srv_gid = 0;
2926         }
2927 
2928         if (map_deny)
2929                 perm |= NFSAUTH_DENIED;
2930 
2931         if (!(perm & NFSAUTH_UIDMAP))
2932                 *srv_uid = clnt_uid;
2933         if (!(perm & NFSAUTH_GIDMAP))
2934                 *srv_gid = clnt_gid;
2935 
2936         /*
2937          * If no match then set the perm accordingly
2938          */
2939         if (!match || perm & NFSAUTH_DENIED) {
2940                 free(opts);
2941                 return (NFSAUTH_DENIED);
2942         }
2943 
2944         if (list) {
2945                 /*
2946                  * If the client doesn't match an "ro" or "rw" list then
2947                  * check if it may have access by using a different flavor.
2948                  * If so, return NFSAUTH_WRONGSEC.
2949                  * If not, return NFSAUTH_DENIED.
2950                  */
2951                 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2952                         if (is_wrongsec(sh, cln, flavor))
2953                                 perm |= NFSAUTH_WRONGSEC;
2954                         else
2955                                 perm |= NFSAUTH_DENIED;
2956                 }
2957         } else {
2958                 /*
2959                  * The client matched a flavor entry that
2960                  * has no explicit "rw" or "ro" determination.
2961                  * Make sure it defaults to "rw".
2962                  */
2963                 perm |= NFSAUTH_RW;
2964         }
2965 
2966         /*
2967          * The client may show up in both ro= and rw=
2968          * lists.  If so, then turn off the RO access
2969          * bit leaving RW access.
2970          */
2971         if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2972                 /*
2973                  * Logically cover all permutations of rw=,ro=.
2974                  * In the case where, rw,ro=<host> we would like
2975                  * to remove RW access for the host.  In all other cases
2976                  * RW wins the precedence battle.
2977                  */
2978                 if (!rw_val && ro_val) {
2979                         perm &= ~(NFSAUTH_RW);
2980                 } else {
2981                         perm &= ~(NFSAUTH_RO);
2982                 }
2983         }
2984 
2985         free(opts);
2986 
2987         return (perm);
2988 }
2989 
2990 void
2991 check_sharetab()
2992 {
2993         FILE *f;
2994         struct stat st;
2995         static timestruc_t last_sharetab_time;
2996         timestruc_t prev_sharetab_time;
2997         share_t *sh;
2998         struct sh_list *shp, *shp_prev;
2999         int res, c = 0;
3000 
3001         /*
3002          *  read in /etc/dfs/sharetab if it has changed
3003          */
3004         if (stat(SHARETAB, &st) != 0) {
3005                 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3006                 return;
3007         }
3008 
3009         if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
3010             st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
3011                 /*
3012                  * No change.
3013                  */
3014                 return;
3015         }
3016 
3017         /*
3018          * Remember the mod time, then after getting the
3019          * write lock check again.  If another thread
3020          * already did the update, then there's no
3021          * work to do.
3022          */
3023         prev_sharetab_time = last_sharetab_time;
3024 
3025         (void) rw_wrlock(&sharetab_lock);
3026 
3027         if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
3028             prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
3029                 (void) rw_unlock(&sharetab_lock);
3030                 return;
3031         }
3032 
3033         /*
3034          * Note that since the sharetab is now in memory
3035          * and a snapshot is taken, we no longer have to
3036          * lock the file.
3037          */
3038         f = fopen(SHARETAB, "r");
3039         if (f == NULL) {
3040                 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
3041                 (void) rw_unlock(&sharetab_lock);
3042                 return;
3043         }
3044 
3045         /*
3046          * Once we are sure /etc/dfs/sharetab has been
3047          * modified, flush netgroup cache entries.
3048          */
3049         netgrp_cache_flush();
3050 
3051         sh_free(share_list);                    /* free old list */
3052         share_list = NULL;
3053 
3054         while ((res = getshare(f, &sh)) > 0) {
3055                 c++;
3056                 if (strcmp(sh->sh_fstype, "nfs") != 0)
3057                         continue;
3058 
3059                 shp = malloc(sizeof (*shp));
3060                 if (shp == NULL)
3061                         goto alloc_failed;
3062                 if (share_list == NULL)
3063                         share_list = shp;
3064                 else
3065                         /* LINTED not used before set */
3066                         shp_prev->shl_next = shp;
3067                 shp_prev = shp;
3068                 shp->shl_next = NULL;
3069                 shp->shl_sh = sharedup(sh);
3070                 if (shp->shl_sh == NULL)
3071                         goto alloc_failed;
3072         }
3073 
3074         if (res < 0)
3075                 syslog(LOG_ERR, "%s: invalid at line %d\n",
3076                     SHARETAB, c + 1);
3077 
3078         if (stat(SHARETAB, &st) != 0) {
3079                 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3080                 (void) fclose(f);
3081                 (void) rw_unlock(&sharetab_lock);
3082                 return;
3083         }
3084 
3085         last_sharetab_time = st.st_mtim;
3086         (void) fclose(f);
3087         (void) rw_unlock(&sharetab_lock);
3088 
3089         return;
3090 
3091 alloc_failed:
3092 
3093         syslog(LOG_ERR, "check_sharetab: no memory");
3094         sh_free(share_list);
3095         share_list = NULL;
3096         (void) fclose(f);
3097         (void) rw_unlock(&sharetab_lock);
3098 }
3099 
3100 static void
3101 sh_free(struct sh_list *shp)
3102 {
3103         struct sh_list *next;
3104 
3105         while (shp) {
3106                 sharefree(shp->shl_sh);
3107                 next = shp->shl_next;
3108                 free(shp);
3109                 shp = next;
3110         }
3111 }
3112 
3113 
3114 /*
3115  * Remove an entry from mounted list
3116  */
3117 static void
3118 umount(struct svc_req *rqstp)
3119 {
3120         char *host, *path, *remove_path;
3121         char rpath[MAXPATHLEN];
3122         SVCXPRT *transp;
3123         struct cln cln;
3124 
3125         transp = rqstp->rq_xprt;
3126         path = NULL;
3127         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3128                 svcerr_decode(transp);
3129                 return;
3130         }
3131 
3132         cln_init(&cln, transp);
3133 
3134         errno = 0;
3135         if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3136                 log_cant_reply_cln(&cln);
3137 
3138         host = cln_gethost(&cln);
3139         if (host == NULL) {
3140                 /*
3141                  * Without the hostname we can't do audit or delete
3142                  * this host from the mount entries.
3143                  */
3144                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3145                 return;
3146         }
3147 
3148         if (verbose)
3149                 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3150 
3151         audit_mountd_umount(host, path);
3152 
3153         remove_path = rpath;    /* assume we will use the cannonical path */
3154         if (realpath(path, rpath) == NULL) {
3155                 if (verbose)
3156                         syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3157                 remove_path = path;     /* use path provided instead */
3158         }
3159 
3160         mntlist_delete(host, remove_path);      /* remove from mount list */
3161 
3162         cln_fini(&cln);
3163 
3164         svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3165 }
3166 
3167 /*
3168  * Remove all entries for one machine from mounted list
3169  */
3170 static void
3171 umountall(struct svc_req *rqstp)
3172 {
3173         SVCXPRT *transp;
3174         char *host;
3175         struct cln cln;
3176 
3177         transp = rqstp->rq_xprt;
3178         if (!svc_getargs(transp, xdr_void, NULL)) {
3179                 svcerr_decode(transp);
3180                 return;
3181         }
3182         /*
3183          * We assume that this call is asynchronous and made via rpcbind
3184          * callit routine.  Therefore return control immediately. The error
3185          * causes rpcbind to remain silent, as opposed to every machine
3186          * on the net blasting the requester with a response.
3187          */
3188         svcerr_systemerr(transp);
3189 
3190         cln_init(&cln, transp);
3191 
3192         host = cln_gethost(&cln);
3193         if (host == NULL) {
3194                 /* Can't do anything without the name of the client */
3195                 return;
3196         }
3197 
3198         /*
3199          * Remove all hosts entries from mount list
3200          */
3201         mntlist_delete_all(host);
3202 
3203         if (verbose)
3204                 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3205 
3206         cln_fini(&cln);
3207 }
3208 
3209 void *
3210 exmalloc(size_t size)
3211 {
3212         void *ret;
3213 
3214         if ((ret = malloc(size)) == NULL) {
3215                 syslog(LOG_ERR, "Out of memory");
3216                 exit(1);
3217         }
3218         return (ret);
3219 }
3220 
3221 static tsol_tpent_t *
3222 get_client_template(struct sockaddr *sock)
3223 {
3224         in_addr_t       v4client;
3225         in6_addr_t      v6client;
3226         char            v4_addr[INET_ADDRSTRLEN];
3227         char            v6_addr[INET6_ADDRSTRLEN];
3228         tsol_rhent_t    *rh;
3229         tsol_tpent_t    *tp;
3230 
3231         switch (sock->sa_family) {
3232         case AF_INET:
3233                 v4client = ((struct sockaddr_in *)(void *)sock)->
3234                     sin_addr.s_addr;
3235                 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
3236                     NULL)
3237                         return (NULL);
3238                 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
3239                 if (rh == NULL)
3240                         return (NULL);
3241                 tp = tsol_gettpbyname(rh->rh_template);
3242                 tsol_freerhent(rh);
3243                 return (tp);
3244                 break;
3245         case AF_INET6:
3246                 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
3247                 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
3248                     NULL)
3249                         return (NULL);
3250                 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
3251                 if (rh == NULL)
3252                         return (NULL);
3253                 tp = tsol_gettpbyname(rh->rh_template);
3254                 tsol_freerhent(rh);
3255                 return (tp);
3256                 break;
3257         default:
3258                 return (NULL);
3259         }
3260 }