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         struct netbuf *pnb;
1803         struct nd_hostservlist *clnames = NULL;
1804 
1805         /* If no access list - then it's unrestricted */
1806         if (access_list == NULL || *access_list == '\0')
1807                 return (1);
1808 
1809         if ((pnb = cln_getnbuf(cln)) == NULL)
1810                 return (-1);
1811 
1812         for (;;) {
1813                 if ((cstr = strpbrk(cstr, "[:")) != NULL) {
1814                         if (*cstr == ':') {
1815                                 *cstr = '\0';
1816                         } else {
1817                                 assert(*cstr == '[');
1818                                 cstr = strchr(cstr + 1, ']');
1819                                 if (cstr == NULL)
1820                                         return (-1);
1821                                 cstr++;
1822                                 continue;
1823                         }
1824                 }
1825 
1826                 /*
1827                  * If the list name has a '-' prepended then a match of
1828                  * the following name implies failure instead of success.
1829                  */
1830                 if (*gr == '-') {
1831                         response = 0;
1832                         gr++;
1833                 } else {
1834                         response = 1;
1835                 }
1836 
1837                 /*
1838                  * First check if we have '@' entry, as it doesn't
1839                  * require client hostname.
1840                  */
1841                 if (*gr == '@') {
1842                         gr++;
1843 
1844                         /* Netname support */
1845                         if (!isdigit(*gr) && *gr != '[') {
1846                                 struct netent n, *np;
1847 
1848                                 if ((np = getnetbyname_r(gr, &n, buff,
1849                                     sizeof (buff))) != NULL &&
1850                                     np->n_net != 0) {
1851                                         while ((np->n_net & 0xFF000000u) == 0)
1852                                                 np->n_net <<= 8;
1853                                         np->n_net = htonl(np->n_net);
1854                                         if (inet_ntop(AF_INET, &np->n_net, addr,
1855                                             INET_ADDRSTRLEN) == NULL)
1856                                                 break;
1857                                         if (inet_matchaddr(pnb->buf, addr))
1858                                                 return (response);
1859                                 }
1860                         } else {
1861                                 if (inet_matchaddr(pnb->buf, gr))
1862                                         return (response);
1863                         }
1864 
1865                         goto next;
1866                 }
1867 
1868                 /*
1869                  * No other checks can be performed if client address
1870                  * can't be resolved.
1871                  */
1872                 if ((clnames = cln_getclientsnames(cln)) == NULL)
1873                         goto next;
1874 
1875                 /* Otherwise loop through all client hostname aliases */
1876                 for (i = 0; i < clnames->h_cnt; i++) {
1877                         char *host = clnames->h_hostservs[i].h_host;
1878 
1879                         /*
1880                          * If the list name begins with a dot then
1881                          * do a domain name suffix comparison.
1882                          * A single dot matches any name with no
1883                          * suffix.
1884                          */
1885                         if (*gr == '.') {
1886                                 if (*(gr + 1) == '\0') {  /* single dot */
1887                                         if (strchr(host, '.') == NULL)
1888                                                 return (response);
1889                                 } else {
1890                                         int off = strlen(host) - strlen(gr);
1891                                         if (off > 0 &&
1892                                             strcasecmp(host + off, gr) == 0) {
1893                                                 return (response);
1894                                         }
1895                                 }
1896                         } else {
1897                                 /* Just do a hostname match */
1898                                 if (strcasecmp(gr, host) == 0)
1899                                         return (response);
1900                         }
1901                 }
1902 
1903                 nentries++;
1904 
1905 next:
1906                 if (cstr == NULL)
1907                         break;
1908 
1909                 gr = ++cstr;
1910         }
1911 
1912         if (clnames == NULL)
1913                 return (0);
1914 
1915         return (netgroup_check(clnames, access_list, nentries));
1916 }
1917 
1918 
1919 static char *optlist[] = {
1920 #define OPT_RO          0
1921         SHOPT_RO,
1922 #define OPT_RW          1
1923         SHOPT_RW,
1924 #define OPT_ROOT        2
1925         SHOPT_ROOT,
1926 #define OPT_SECURE      3
1927         SHOPT_SECURE,
1928 #define OPT_ANON        4
1929         SHOPT_ANON,
1930 #define OPT_WINDOW      5
1931         SHOPT_WINDOW,
1932 #define OPT_NOSUID      6
1933         SHOPT_NOSUID,
1934 #define OPT_ACLOK       7
1935         SHOPT_ACLOK,
1936 #define OPT_SEC         8
1937         SHOPT_SEC,
1938 #define OPT_NONE        9
1939         SHOPT_NONE,
1940 #define OPT_UIDMAP      10
1941         SHOPT_UIDMAP,
1942 #define OPT_GIDMAP      11
1943         SHOPT_GIDMAP,
1944         NULL
1945 };
1946 
1947 static int
1948 map_flavor(char *str)
1949 {
1950         seconfig_t sec;
1951 
1952         if (nfs_getseconfig_byname(str, &sec))
1953                 return (-1);
1954 
1955         return (sec.sc_nfsnum);
1956 }
1957 
1958 /*
1959  * If the option string contains a "sec="
1960  * option, then use new option syntax.
1961  */
1962 static int
1963 newopts(char *opts)
1964 {
1965         char *head, *p, *val;
1966 
1967         if (!opts || *opts == '\0')
1968                 return (0);
1969 
1970         head = strdup(opts);
1971         if (head == NULL) {
1972                 syslog(LOG_ERR, "opts: no memory");
1973                 return (0);
1974         }
1975 
1976         p = head;
1977         while (*p) {
1978                 if (getsubopt(&p, optlist, &val) == OPT_SEC) {
1979                         free(head);
1980                         return (1);
1981                 }
1982         }
1983 
1984         free(head);
1985         return (0);
1986 }
1987 
1988 /*
1989  * Given an export and the clients hostname(s)
1990  * determine the security flavors that this
1991  * client is permitted to use.
1992  *
1993  * This routine is called only for "old" syntax, i.e.
1994  * only one security flavor is allowed.  So we need
1995  * to determine two things: the particular flavor,
1996  * and whether the client is allowed to use this
1997  * flavor, i.e. is in the access list.
1998  *
1999  * Note that if there is no access list, then the
2000  * default is that access is granted.
2001  */
2002 static int
2003 getclientsflavors_old(share_t *sh, struct cln *cln, int *flavors)
2004 {
2005         char *opts, *p, *val;
2006         boolean_t ok = B_FALSE;
2007         int defaultaccess = 1;
2008         boolean_t reject = B_FALSE;
2009 
2010         opts = strdup(sh->sh_opts);
2011         if (opts == NULL) {
2012                 syslog(LOG_ERR, "getclientsflavors: no memory");
2013                 return (0);
2014         }
2015 
2016         flavors[0] = AUTH_SYS;
2017         p = opts;
2018 
2019         while (*p) {
2020 
2021                 switch (getsubopt(&p, optlist, &val)) {
2022                 case OPT_SECURE:
2023                         flavors[0] = AUTH_DES;
2024                         break;
2025 
2026                 case OPT_RO:
2027                 case OPT_RW:
2028                         defaultaccess = 0;
2029                         if (in_access_list(cln, val) > 0)
2030                                 ok = B_TRUE;
2031                         break;
2032 
2033                 case OPT_NONE:
2034                         defaultaccess = 0;
2035                         if (in_access_list(cln, val) > 0)
2036                                 reject = B_TRUE;
2037                 }
2038         }
2039 
2040         free(opts);
2041 
2042         /* none takes precedence over everything else */
2043         if (reject)
2044                 ok = B_FALSE;
2045 
2046         return (defaultaccess || ok);
2047 }
2048 
2049 /*
2050  * Given an export and the clients hostname(s)
2051  * determine the security flavors that this
2052  * client is permitted to use.
2053  *
2054  * This is somewhat more complicated than the "old"
2055  * routine because the options may contain multiple
2056  * security flavors (sec=) each with its own access
2057  * lists.  So a client could be granted access based
2058  * on a number of security flavors.  Note that the
2059  * type of access might not always be the same, the
2060  * client may get readonly access with one flavor
2061  * and readwrite with another, however the client
2062  * is not told this detail, it gets only the list
2063  * of flavors, and only if the client is using
2064  * version 3 of the mount protocol.
2065  */
2066 static int
2067 getclientsflavors_new(share_t *sh, struct cln *cln, int *flavors)
2068 {
2069         char *opts, *p, *val;
2070         char *lasts;
2071         char *f;
2072         boolean_t defaultaccess = B_TRUE;       /* default access is rw */
2073         boolean_t access_ok = B_FALSE;
2074         int count, c;
2075         boolean_t reject = B_FALSE;
2076 
2077         opts = strdup(sh->sh_opts);
2078         if (opts == NULL) {
2079                 syslog(LOG_ERR, "getclientsflavors: no memory");
2080                 return (0);
2081         }
2082 
2083         p = opts;
2084         count = c = 0;
2085 
2086         while (*p) {
2087                 switch (getsubopt(&p, optlist, &val)) {
2088                 case OPT_SEC:
2089                         if (reject)
2090                                 access_ok = B_FALSE;
2091 
2092                         /*
2093                          * Before a new sec=xxx option, check if we need
2094                          * to move the c index back to the previous count.
2095                          */
2096                         if (!defaultaccess && !access_ok) {
2097                                 c = count;
2098                         }
2099 
2100                         /* get all the sec=f1[:f2] flavors */
2101                         while ((f = strtok_r(val, ":", &lasts)) != NULL) {
2102                                 flavors[c++] = map_flavor(f);
2103                                 val = NULL;
2104                         }
2105 
2106                         /* for a new sec=xxx option, default is rw access */
2107                         defaultaccess = B_TRUE;
2108                         access_ok = B_FALSE;
2109                         reject = B_FALSE;
2110                         break;
2111 
2112                 case OPT_RO:
2113                 case OPT_RW:
2114                         defaultaccess = B_FALSE;
2115                         if (in_access_list(cln, val) > 0)
2116                                 access_ok = B_TRUE;
2117                         break;
2118 
2119                 case OPT_NONE:
2120                         defaultaccess = B_FALSE;
2121                         if (in_access_list(cln, val) > 0)
2122                                 reject = B_TRUE; /* none overides rw/ro */
2123                         break;
2124                 }
2125         }
2126 
2127         if (reject)
2128                 access_ok = B_FALSE;
2129 
2130         if (!defaultaccess && !access_ok)
2131                 c = count;
2132 
2133         free(opts);
2134 
2135         return (c);
2136 }
2137 
2138 /*
2139  * This is a tricky piece of code that parses the
2140  * share options looking for a match on the auth
2141  * flavor that the client is using. If it finds
2142  * a match, then the client is given ro, rw, or
2143  * no access depending whether it is in the access
2144  * list.  There is a special case for "secure"
2145  * flavor.  Other flavors are values of the new "sec=" option.
2146  */
2147 int
2148 check_client(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2149     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2150     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2151 {
2152         if (newopts(sh->sh_opts))
2153                 return (check_client_new(sh, cln, flavor, clnt_uid, clnt_gid,
2154                     clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2155                     srv_gids));
2156         else
2157                 return (check_client_old(sh, cln, flavor, clnt_uid, clnt_gid,
2158                     clnt_ngids, clnt_gids, srv_uid, srv_gid, srv_ngids,
2159                     srv_gids));
2160 }
2161 
2162 extern int _getgroupsbymember(const char *, gid_t[], int, int);
2163 
2164 /*
2165  * Get supplemental groups for uid
2166  */
2167 static int
2168 getusergroups(uid_t uid, uint_t *ngrps, gid_t **grps)
2169 {
2170         struct passwd pwd;
2171         char *pwbuf = alloca(pw_size);
2172         gid_t *tmpgrps = alloca(ngroups_max * sizeof (gid_t));
2173         int tmpngrps;
2174 
2175         if (getpwuid_r(uid, &pwd, pwbuf, pw_size) == NULL)
2176                 return (-1);
2177 
2178         tmpgrps[0] = pwd.pw_gid;
2179 
2180         tmpngrps = _getgroupsbymember(pwd.pw_name, tmpgrps, ngroups_max, 1);
2181         if (tmpngrps <= 0) {
2182                 syslog(LOG_WARNING,
2183                     "getusergroups(): Unable to get groups for user %s",
2184                     pwd.pw_name);
2185 
2186                 return (-1);
2187         }
2188 
2189         *grps = malloc(tmpngrps * sizeof (gid_t));
2190         if (*grps == NULL) {
2191                 syslog(LOG_ERR,
2192                     "getusergroups(): Memory allocation failed: %m");
2193 
2194                 return (-1);
2195         }
2196 
2197         *ngrps = tmpngrps;
2198         (void) memcpy(*grps, tmpgrps, tmpngrps * sizeof (gid_t));
2199 
2200         return (0);
2201 }
2202 
2203 /*
2204  * is_a_number(number)
2205  *
2206  * is the string a number in one of the forms we want to use?
2207  */
2208 
2209 static int
2210 is_a_number(char *number)
2211 {
2212         int ret = 1;
2213         int hex = 0;
2214 
2215         if (strncmp(number, "0x", 2) == 0) {
2216                 number += 2;
2217                 hex = 1;
2218         } else if (*number == '-') {
2219                 number++; /* skip the minus */
2220         }
2221         while (ret == 1 && *number != '\0') {
2222                 if (hex) {
2223                         ret = isxdigit(*number++);
2224                 } else {
2225                         ret = isdigit(*number++);
2226                 }
2227         }
2228         return (ret);
2229 }
2230 
2231 static boolean_t
2232 get_uid(char *value, uid_t *uid)
2233 {
2234         if (!is_a_number(value)) {
2235                 struct passwd *pw;
2236                 /*
2237                  * in this case it would have to be a
2238                  * user name
2239                  */
2240                 pw = getpwnam(value);
2241                 if (pw == NULL)
2242                         return (B_FALSE);
2243                 *uid = pw->pw_uid;
2244                 endpwent();
2245         } else {
2246                 uint64_t intval;
2247                 intval = strtoull(value, NULL, 0);
2248                 if (intval > UID_MAX && intval != -1)
2249                         return (B_FALSE);
2250                 *uid = (uid_t)intval;
2251         }
2252 
2253         return (B_TRUE);
2254 }
2255 
2256 static boolean_t
2257 get_gid(char *value, gid_t *gid)
2258 {
2259         if (!is_a_number(value)) {
2260                 struct group *gr;
2261                 /*
2262                  * in this case it would have to be a
2263                  * group name
2264                  */
2265                 gr = getgrnam(value);
2266                 if (gr == NULL)
2267                         return (B_FALSE);
2268                 *gid = gr->gr_gid;
2269                 endgrent();
2270         } else {
2271                 uint64_t intval;
2272                 intval = strtoull(value, NULL, 0);
2273                 if (intval > UID_MAX && intval != -1)
2274                         return (B_FALSE);
2275                 *gid = (gid_t)intval;
2276         }
2277 
2278         return (B_TRUE);
2279 }
2280 
2281 static int
2282 check_client_old(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2283     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2284     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2285 {
2286         char *opts, *p, *val;
2287         int match;      /* Set when a flavor is matched */
2288         int perm = 0;   /* Set when "ro", "rw" or "root" is matched */
2289         int list = 0;   /* Set when "ro", "rw" is found */
2290         int ro_val = 0; /* Set if ro option is 'ro=' */
2291         int rw_val = 0; /* Set if rw option is 'rw=' */
2292 
2293         boolean_t map_deny = B_FALSE;
2294 
2295         opts = strdup(sh->sh_opts);
2296         if (opts == NULL) {
2297                 syslog(LOG_ERR, "check_client: no memory");
2298                 return (0);
2299         }
2300 
2301         /*
2302          * If client provided 16 supplemental groups with AUTH_SYS, lookup
2303          * locally for all of them
2304          */
2305         if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2306                 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2307                         perm |= NFSAUTH_GROUPS;
2308 
2309         p = opts;
2310         match = AUTH_UNIX;
2311 
2312         while (*p) {
2313                 switch (getsubopt(&p, optlist, &val)) {
2314 
2315                 case OPT_SECURE:
2316                         match = AUTH_DES;
2317 
2318                         if (perm & NFSAUTH_GROUPS) {
2319                                 free(*srv_gids);
2320                                 *srv_ngids = 0;
2321                                 *srv_gids = NULL;
2322                                 perm &= ~NFSAUTH_GROUPS;
2323                         }
2324 
2325                         break;
2326 
2327                 case OPT_RO:
2328                         list++;
2329                         if (val != NULL)
2330                                 ro_val++;
2331                         if (in_access_list(cln, val) > 0)
2332                                 perm |= NFSAUTH_RO;
2333                         break;
2334 
2335                 case OPT_RW:
2336                         list++;
2337                         if (val != NULL)
2338                                 rw_val++;
2339                         if (in_access_list(cln, val) > 0)
2340                                 perm |= NFSAUTH_RW;
2341                         break;
2342 
2343                 case OPT_ROOT:
2344                         /*
2345                          * Check if the client is in
2346                          * the root list. Only valid
2347                          * for AUTH_SYS.
2348                          */
2349                         if (flavor != AUTH_SYS)
2350                                 break;
2351 
2352                         if (val == NULL || *val == '\0')
2353                                 break;
2354 
2355                         if (clnt_uid != 0)
2356                                 break;
2357 
2358                         if (in_access_list(cln, val) > 0) {
2359                                 perm |= NFSAUTH_ROOT;
2360                                 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2361                                 map_deny = B_FALSE;
2362 
2363                                 if (perm & NFSAUTH_GROUPS) {
2364                                         free(*srv_gids);
2365                                         *srv_ngids = 0;
2366                                         *srv_gids = NULL;
2367                                         perm &= ~NFSAUTH_GROUPS;
2368                                 }
2369                         }
2370                         break;
2371 
2372                 case OPT_NONE:
2373                         /*
2374                          * Check if the client should have no access
2375                          * to this share at all. This option behaves
2376                          * more like "root" than either "rw" or "ro".
2377                          */
2378                         if (in_access_list(cln, val) > 0)
2379                                 perm |= NFSAUTH_DENIED;
2380                         break;
2381 
2382                 case OPT_UIDMAP: {
2383                         char *c;
2384                         char *n;
2385 
2386                         /*
2387                          * The uidmap is supported for AUTH_SYS only.
2388                          */
2389                         if (flavor != AUTH_SYS)
2390                                 break;
2391 
2392                         if (perm & NFSAUTH_UIDMAP || map_deny)
2393                                 break;
2394 
2395                         for (c = val; c != NULL; c = n) {
2396                                 char *s;
2397                                 char *al;
2398                                 uid_t srv;
2399 
2400                                 n = strchr(c, '~');
2401                                 if (n != NULL)
2402                                         *n++ = '\0';
2403 
2404                                 s = strchr(c, ':');
2405                                 if (s != NULL) {
2406                                         *s++ = '\0';
2407                                         al = strchr(s, ':');
2408                                         if (al != NULL)
2409                                                 *al++ = '\0';
2410                                 }
2411 
2412                                 if (s == NULL || al == NULL)
2413                                         continue;
2414 
2415                                 if (*c == '\0') {
2416                                         if (clnt_uid != (uid_t)-1)
2417                                                 continue;
2418                                 } else if (strcmp(c, "*") != 0) {
2419                                         uid_t clnt;
2420 
2421                                         if (!get_uid(c, &clnt))
2422                                                 continue;
2423 
2424                                         if (clnt_uid != clnt)
2425                                                 continue;
2426                                 }
2427 
2428                                 if (*s == '\0')
2429                                         srv = UID_NOBODY;
2430                                 else if (!get_uid(s, &srv))
2431                                         continue;
2432                                 else if (srv == (uid_t)-1) {
2433                                         map_deny = B_TRUE;
2434                                         break;
2435                                 }
2436 
2437                                 if (in_access_list(cln, al) > 0) {
2438                                         *srv_uid = srv;
2439                                         perm |= NFSAUTH_UIDMAP;
2440 
2441                                         if (perm & NFSAUTH_GROUPS) {
2442                                                 free(*srv_gids);
2443                                                 *srv_ngids = 0;
2444                                                 *srv_gids = NULL;
2445                                                 perm &= ~NFSAUTH_GROUPS;
2446                                         }
2447 
2448                                         break;
2449                                 }
2450                         }
2451 
2452                         break;
2453                 }
2454 
2455                 case OPT_GIDMAP: {
2456                         char *c;
2457                         char *n;
2458 
2459                         /*
2460                          * The gidmap is supported for AUTH_SYS only.
2461                          */
2462                         if (flavor != AUTH_SYS)
2463                                 break;
2464 
2465                         if (perm & NFSAUTH_GIDMAP || map_deny)
2466                                 break;
2467 
2468                         for (c = val; c != NULL; c = n) {
2469                                 char *s;
2470                                 char *al;
2471                                 gid_t srv;
2472 
2473                                 n = strchr(c, '~');
2474                                 if (n != NULL)
2475                                         *n++ = '\0';
2476 
2477                                 s = strchr(c, ':');
2478                                 if (s != NULL) {
2479                                         *s++ = '\0';
2480                                         al = strchr(s, ':');
2481                                         if (al != NULL)
2482                                                 *al++ = '\0';
2483                                 }
2484 
2485                                 if (s == NULL || al == NULL)
2486                                         break;
2487 
2488                                 if (*c == '\0') {
2489                                         if (clnt_gid != (gid_t)-1)
2490                                                 continue;
2491                                 } else if (strcmp(c, "*") != 0) {
2492                                         gid_t clnt;
2493 
2494                                         if (!get_gid(c, &clnt))
2495                                                 continue;
2496 
2497                                         if (clnt_gid != clnt)
2498                                                 continue;
2499                                 }
2500 
2501                                 if (*s == '\0')
2502                                         srv = UID_NOBODY;
2503                                 else if (!get_gid(s, &srv))
2504                                         continue;
2505                                 else if (srv == (gid_t)-1) {
2506                                         map_deny = B_TRUE;
2507                                         break;
2508                                 }
2509 
2510                                 if (in_access_list(cln, al) > 0) {
2511                                         *srv_gid = srv;
2512                                         perm |= NFSAUTH_GIDMAP;
2513 
2514                                         if (perm & NFSAUTH_GROUPS) {
2515                                                 free(*srv_gids);
2516                                                 *srv_ngids = 0;
2517                                                 *srv_gids = NULL;
2518                                                 perm &= ~NFSAUTH_GROUPS;
2519                                         }
2520 
2521                                         break;
2522                                 }
2523                         }
2524 
2525                         break;
2526                 }
2527 
2528                 default:
2529                         break;
2530                 }
2531         }
2532 
2533         free(opts);
2534 
2535         if (perm & NFSAUTH_ROOT) {
2536                 *srv_uid = 0;
2537                 *srv_gid = 0;
2538         }
2539 
2540         if (map_deny)
2541                 perm |= NFSAUTH_DENIED;
2542 
2543         if (!(perm & NFSAUTH_UIDMAP))
2544                 *srv_uid = clnt_uid;
2545         if (!(perm & NFSAUTH_GIDMAP))
2546                 *srv_gid = clnt_gid;
2547 
2548         if (flavor != match || perm & NFSAUTH_DENIED)
2549                 return (NFSAUTH_DENIED);
2550 
2551         if (list) {
2552                 /*
2553                  * If the client doesn't match an "ro" or "rw"
2554                  * list then set no access.
2555                  */
2556                 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0)
2557                         perm |= NFSAUTH_DENIED;
2558         } else {
2559                 /*
2560                  * The client matched a flavor entry that
2561                  * has no explicit "rw" or "ro" determination.
2562                  * Default it to "rw".
2563                  */
2564                 perm |= NFSAUTH_RW;
2565         }
2566 
2567         /*
2568          * The client may show up in both ro= and rw=
2569          * lists.  If so, then turn off the RO access
2570          * bit leaving RW access.
2571          */
2572         if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2573                 /*
2574                  * Logically cover all permutations of rw=,ro=.
2575                  * In the case where, rw,ro=<host> we would like
2576                  * to remove RW access for the host.  In all other cases
2577                  * RW wins the precedence battle.
2578                  */
2579                 if (!rw_val && ro_val) {
2580                         perm &= ~(NFSAUTH_RW);
2581                 } else {
2582                         perm &= ~(NFSAUTH_RO);
2583                 }
2584         }
2585 
2586         return (perm);
2587 }
2588 
2589 /*
2590  * Check if the client has access by using a flavor different from
2591  * the given "flavor". If "flavor" is not in the flavor list,
2592  * return TRUE to indicate that this "flavor" is a wrong sec.
2593  */
2594 static bool_t
2595 is_wrongsec(share_t *sh, struct cln *cln, int flavor)
2596 {
2597         int flavor_list[MAX_FLAVORS];
2598         int flavor_count, i;
2599 
2600         /* get the flavor list that the client has access with */
2601         flavor_count = getclientsflavors_new(sh, cln, flavor_list);
2602 
2603         if (flavor_count == 0)
2604                 return (FALSE);
2605 
2606         /*
2607          * Check if the given "flavor" is in the flavor_list.
2608          */
2609         for (i = 0; i < flavor_count; i++) {
2610                 if (flavor == flavor_list[i])
2611                         return (FALSE);
2612         }
2613 
2614         /*
2615          * If "flavor" is not in the flavor_list, return TRUE to indicate
2616          * that the client should have access by using a security flavor
2617          * different from this "flavor".
2618          */
2619         return (TRUE);
2620 }
2621 
2622 /*
2623  * Given an export and the client's hostname, we
2624  * check the security options to see whether the
2625  * client is allowed to use the given security flavor.
2626  *
2627  * The strategy is to proceed through the options looking
2628  * for a flavor match, then pay attention to the ro, rw,
2629  * and root options.
2630  *
2631  * Note that an entry may list several flavors in a
2632  * single entry, e.g.
2633  *
2634  *   sec=krb5,rw=clnt1:clnt2,ro,sec=sys,ro
2635  *
2636  */
2637 
2638 static int
2639 check_client_new(share_t *sh, struct cln *cln, int flavor, uid_t clnt_uid,
2640     gid_t clnt_gid, uint_t clnt_ngids, gid_t *clnt_gids, uid_t *srv_uid,
2641     gid_t *srv_gid, uint_t *srv_ngids, gid_t **srv_gids)
2642 {
2643         char *opts, *p, *val;
2644         char *lasts;
2645         char *f;
2646         int match = 0;  /* Set when a flavor is matched */
2647         int perm = 0;   /* Set when "ro", "rw" or "root" is matched */
2648         int list = 0;   /* Set when "ro", "rw" is found */
2649         int ro_val = 0; /* Set if ro option is 'ro=' */
2650         int rw_val = 0; /* Set if rw option is 'rw=' */
2651 
2652         boolean_t map_deny = B_FALSE;
2653 
2654         opts = strdup(sh->sh_opts);
2655         if (opts == NULL) {
2656                 syslog(LOG_ERR, "check_client: no memory");
2657                 return (0);
2658         }
2659 
2660         /*
2661          * If client provided 16 supplemental groups with AUTH_SYS, lookup
2662          * locally for all of them
2663          */
2664         if (flavor == AUTH_SYS && clnt_ngids == NGRPS && ngroups_max > NGRPS)
2665                 if (getusergroups(clnt_uid, srv_ngids, srv_gids) == 0)
2666                         perm |= NFSAUTH_GROUPS;
2667 
2668         p = opts;
2669 
2670         while (*p) {
2671                 switch (getsubopt(&p, optlist, &val)) {
2672 
2673                 case OPT_SEC:
2674                         if (match)
2675                                 goto done;
2676 
2677                         while ((f = strtok_r(val, ":", &lasts))
2678                             != NULL) {
2679                                 if (flavor == map_flavor(f)) {
2680                                         match = 1;
2681                                         break;
2682                                 }
2683                                 val = NULL;
2684                         }
2685                         break;
2686 
2687                 case OPT_RO:
2688                         if (!match)
2689                                 break;
2690 
2691                         list++;
2692                         if (val != NULL)
2693                                 ro_val++;
2694                         if (in_access_list(cln, val) > 0)
2695                                 perm |= NFSAUTH_RO;
2696                         break;
2697 
2698                 case OPT_RW:
2699                         if (!match)
2700                                 break;
2701 
2702                         list++;
2703                         if (val != NULL)
2704                                 rw_val++;
2705                         if (in_access_list(cln, val) > 0)
2706                                 perm |= NFSAUTH_RW;
2707                         break;
2708 
2709                 case OPT_ROOT:
2710                         /*
2711                          * Check if the client is in
2712                          * the root list. Only valid
2713                          * for AUTH_SYS.
2714                          */
2715                         if (flavor != AUTH_SYS)
2716                                 break;
2717 
2718                         if (!match)
2719                                 break;
2720 
2721                         if (val == NULL || *val == '\0')
2722                                 break;
2723 
2724                         if (clnt_uid != 0)
2725                                 break;
2726 
2727                         if (in_access_list(cln, val) > 0) {
2728                                 perm |= NFSAUTH_ROOT;
2729                                 perm |= NFSAUTH_UIDMAP | NFSAUTH_GIDMAP;
2730                                 map_deny = B_FALSE;
2731 
2732                                 if (perm & NFSAUTH_GROUPS) {
2733                                         free(*srv_gids);
2734                                         *srv_gids = NULL;
2735                                         *srv_ngids = 0;
2736                                         perm &= ~NFSAUTH_GROUPS;
2737                                 }
2738                         }
2739                         break;
2740 
2741                 case OPT_NONE:
2742                         /*
2743                          * Check if the client should have no access
2744                          * to this share at all. This option behaves
2745                          * more like "root" than either "rw" or "ro".
2746                          */
2747                         if (in_access_list(cln, val) > 0)
2748                                 perm |= NFSAUTH_DENIED;
2749                         break;
2750 
2751                 case OPT_UIDMAP: {
2752                         char *c;
2753                         char *n;
2754 
2755                         /*
2756                          * The uidmap is supported for AUTH_SYS only.
2757                          */
2758                         if (flavor != AUTH_SYS)
2759                                 break;
2760 
2761                         if (!match || perm & NFSAUTH_UIDMAP || map_deny)
2762                                 break;
2763 
2764                         for (c = val; c != NULL; c = n) {
2765                                 char *s;
2766                                 char *al;
2767                                 uid_t srv;
2768 
2769                                 n = strchr(c, '~');
2770                                 if (n != NULL)
2771                                         *n++ = '\0';
2772 
2773                                 s = strchr(c, ':');
2774                                 if (s != NULL) {
2775                                         *s++ = '\0';
2776                                         al = strchr(s, ':');
2777                                         if (al != NULL)
2778                                                 *al++ = '\0';
2779                                 }
2780 
2781                                 if (s == NULL || al == NULL)
2782                                         continue;
2783 
2784                                 if (*c == '\0') {
2785                                         if (clnt_uid != (uid_t)-1)
2786                                                 continue;
2787                                 } else if (strcmp(c, "*") != 0) {
2788                                         uid_t clnt;
2789 
2790                                         if (!get_uid(c, &clnt))
2791                                                 continue;
2792 
2793                                         if (clnt_uid != clnt)
2794                                                 continue;
2795                                 }
2796 
2797                                 if (*s == '\0')
2798                                         srv = UID_NOBODY;
2799                                 else if (!get_uid(s, &srv))
2800                                         continue;
2801                                 else if (srv == (uid_t)-1) {
2802                                         map_deny = B_TRUE;
2803                                         break;
2804                                 }
2805 
2806                                 if (in_access_list(cln, al) > 0) {
2807                                         *srv_uid = srv;
2808                                         perm |= NFSAUTH_UIDMAP;
2809 
2810                                         if (perm & NFSAUTH_GROUPS) {
2811                                                 free(*srv_gids);
2812                                                 *srv_gids = NULL;
2813                                                 *srv_ngids = 0;
2814                                                 perm &= ~NFSAUTH_GROUPS;
2815                                         }
2816 
2817                                         break;
2818                                 }
2819                         }
2820 
2821                         break;
2822                 }
2823 
2824                 case OPT_GIDMAP: {
2825                         char *c;
2826                         char *n;
2827 
2828                         /*
2829                          * The gidmap is supported for AUTH_SYS only.
2830                          */
2831                         if (flavor != AUTH_SYS)
2832                                 break;
2833 
2834                         if (!match || perm & NFSAUTH_GIDMAP || map_deny)
2835                                 break;
2836 
2837                         for (c = val; c != NULL; c = n) {
2838                                 char *s;
2839                                 char *al;
2840                                 gid_t srv;
2841 
2842                                 n = strchr(c, '~');
2843                                 if (n != NULL)
2844                                         *n++ = '\0';
2845 
2846                                 s = strchr(c, ':');
2847                                 if (s != NULL) {
2848                                         *s++ = '\0';
2849                                         al = strchr(s, ':');
2850                                         if (al != NULL)
2851                                                 *al++ = '\0';
2852                                 }
2853 
2854                                 if (s == NULL || al == NULL)
2855                                         break;
2856 
2857                                 if (*c == '\0') {
2858                                         if (clnt_gid != (gid_t)-1)
2859                                                 continue;
2860                                 } else if (strcmp(c, "*") != 0) {
2861                                         gid_t clnt;
2862 
2863                                         if (!get_gid(c, &clnt))
2864                                                 continue;
2865 
2866                                         if (clnt_gid != clnt)
2867                                                 continue;
2868                                 }
2869 
2870                                 if (*s == '\0')
2871                                         srv = UID_NOBODY;
2872                                 else if (!get_gid(s, &srv))
2873                                         continue;
2874                                 else if (srv == (gid_t)-1) {
2875                                         map_deny = B_TRUE;
2876                                         break;
2877                                 }
2878 
2879                                 if (in_access_list(cln, al) > 0) {
2880                                         *srv_gid = srv;
2881                                         perm |= NFSAUTH_GIDMAP;
2882 
2883                                         if (perm & NFSAUTH_GROUPS) {
2884                                                 free(*srv_gids);
2885                                                 *srv_gids = NULL;
2886                                                 *srv_ngids = 0;
2887                                                 perm &= ~NFSAUTH_GROUPS;
2888                                         }
2889 
2890                                         break;
2891                                 }
2892                         }
2893 
2894                         break;
2895                 }
2896 
2897                 default:
2898                         break;
2899                 }
2900         }
2901 
2902 done:
2903         if (perm & NFSAUTH_ROOT) {
2904                 *srv_uid = 0;
2905                 *srv_gid = 0;
2906         }
2907 
2908         if (map_deny)
2909                 perm |= NFSAUTH_DENIED;
2910 
2911         if (!(perm & NFSAUTH_UIDMAP))
2912                 *srv_uid = clnt_uid;
2913         if (!(perm & NFSAUTH_GIDMAP))
2914                 *srv_gid = clnt_gid;
2915 
2916         /*
2917          * If no match then set the perm accordingly
2918          */
2919         if (!match || perm & NFSAUTH_DENIED) {
2920                 free(opts);
2921                 return (NFSAUTH_DENIED);
2922         }
2923 
2924         if (list) {
2925                 /*
2926                  * If the client doesn't match an "ro" or "rw" list then
2927                  * check if it may have access by using a different flavor.
2928                  * If so, return NFSAUTH_WRONGSEC.
2929                  * If not, return NFSAUTH_DENIED.
2930                  */
2931                 if ((perm & (NFSAUTH_RO | NFSAUTH_RW)) == 0) {
2932                         if (is_wrongsec(sh, cln, flavor))
2933                                 perm |= NFSAUTH_WRONGSEC;
2934                         else
2935                                 perm |= NFSAUTH_DENIED;
2936                 }
2937         } else {
2938                 /*
2939                  * The client matched a flavor entry that
2940                  * has no explicit "rw" or "ro" determination.
2941                  * Make sure it defaults to "rw".
2942                  */
2943                 perm |= NFSAUTH_RW;
2944         }
2945 
2946         /*
2947          * The client may show up in both ro= and rw=
2948          * lists.  If so, then turn off the RO access
2949          * bit leaving RW access.
2950          */
2951         if (perm & NFSAUTH_RO && perm & NFSAUTH_RW) {
2952                 /*
2953                  * Logically cover all permutations of rw=,ro=.
2954                  * In the case where, rw,ro=<host> we would like
2955                  * to remove RW access for the host.  In all other cases
2956                  * RW wins the precedence battle.
2957                  */
2958                 if (!rw_val && ro_val) {
2959                         perm &= ~(NFSAUTH_RW);
2960                 } else {
2961                         perm &= ~(NFSAUTH_RO);
2962                 }
2963         }
2964 
2965         free(opts);
2966 
2967         return (perm);
2968 }
2969 
2970 void
2971 check_sharetab()
2972 {
2973         FILE *f;
2974         struct stat st;
2975         static timestruc_t last_sharetab_time;
2976         timestruc_t prev_sharetab_time;
2977         share_t *sh;
2978         struct sh_list *shp, *shp_prev;
2979         int res, c = 0;
2980 
2981         /*
2982          *  read in /etc/dfs/sharetab if it has changed
2983          */
2984         if (stat(SHARETAB, &st) != 0) {
2985                 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
2986                 return;
2987         }
2988 
2989         if (st.st_mtim.tv_sec == last_sharetab_time.tv_sec &&
2990             st.st_mtim.tv_nsec == last_sharetab_time.tv_nsec) {
2991                 /*
2992                  * No change.
2993                  */
2994                 return;
2995         }
2996 
2997         /*
2998          * Remember the mod time, then after getting the
2999          * write lock check again.  If another thread
3000          * already did the update, then there's no
3001          * work to do.
3002          */
3003         prev_sharetab_time = last_sharetab_time;
3004 
3005         (void) rw_wrlock(&sharetab_lock);
3006 
3007         if (prev_sharetab_time.tv_sec != last_sharetab_time.tv_sec ||
3008             prev_sharetab_time.tv_nsec != last_sharetab_time.tv_nsec) {
3009                 (void) rw_unlock(&sharetab_lock);
3010                 return;
3011         }
3012 
3013         /*
3014          * Note that since the sharetab is now in memory
3015          * and a snapshot is taken, we no longer have to
3016          * lock the file.
3017          */
3018         f = fopen(SHARETAB, "r");
3019         if (f == NULL) {
3020                 syslog(LOG_ERR, "Cannot open %s: %m", SHARETAB);
3021                 (void) rw_unlock(&sharetab_lock);
3022                 return;
3023         }
3024 
3025         /*
3026          * Once we are sure /etc/dfs/sharetab has been
3027          * modified, flush netgroup cache entries.
3028          */
3029         netgrp_cache_flush();
3030 
3031         sh_free(share_list);                    /* free old list */
3032         share_list = NULL;
3033 
3034         while ((res = getshare(f, &sh)) > 0) {
3035                 c++;
3036                 if (strcmp(sh->sh_fstype, "nfs") != 0)
3037                         continue;
3038 
3039                 shp = malloc(sizeof (*shp));
3040                 if (shp == NULL)
3041                         goto alloc_failed;
3042                 if (share_list == NULL)
3043                         share_list = shp;
3044                 else
3045                         /* LINTED not used before set */
3046                         shp_prev->shl_next = shp;
3047                 shp_prev = shp;
3048                 shp->shl_next = NULL;
3049                 shp->shl_sh = sharedup(sh);
3050                 if (shp->shl_sh == NULL)
3051                         goto alloc_failed;
3052         }
3053 
3054         if (res < 0)
3055                 syslog(LOG_ERR, "%s: invalid at line %d\n",
3056                     SHARETAB, c + 1);
3057 
3058         if (stat(SHARETAB, &st) != 0) {
3059                 syslog(LOG_ERR, "Cannot stat %s: %m", SHARETAB);
3060                 (void) fclose(f);
3061                 (void) rw_unlock(&sharetab_lock);
3062                 return;
3063         }
3064 
3065         last_sharetab_time = st.st_mtim;
3066         (void) fclose(f);
3067         (void) rw_unlock(&sharetab_lock);
3068 
3069         return;
3070 
3071 alloc_failed:
3072 
3073         syslog(LOG_ERR, "check_sharetab: no memory");
3074         sh_free(share_list);
3075         share_list = NULL;
3076         (void) fclose(f);
3077         (void) rw_unlock(&sharetab_lock);
3078 }
3079 
3080 static void
3081 sh_free(struct sh_list *shp)
3082 {
3083         struct sh_list *next;
3084 
3085         while (shp) {
3086                 sharefree(shp->shl_sh);
3087                 next = shp->shl_next;
3088                 free(shp);
3089                 shp = next;
3090         }
3091 }
3092 
3093 
3094 /*
3095  * Remove an entry from mounted list
3096  */
3097 static void
3098 umount(struct svc_req *rqstp)
3099 {
3100         char *host, *path, *remove_path;
3101         char rpath[MAXPATHLEN];
3102         SVCXPRT *transp;
3103         struct cln cln;
3104 
3105         transp = rqstp->rq_xprt;
3106         path = NULL;
3107         if (!svc_getargs(transp, xdr_dirpath, (caddr_t)&path)) {
3108                 svcerr_decode(transp);
3109                 return;
3110         }
3111 
3112         cln_init(&cln, transp);
3113 
3114         errno = 0;
3115         if (!svc_sendreply(transp, xdr_void, (char *)NULL))
3116                 log_cant_reply_cln(&cln);
3117 
3118         host = cln_gethost(&cln);
3119         if (host == NULL) {
3120                 /*
3121                  * Without the hostname we can't do audit or delete
3122                  * this host from the mount entries.
3123                  */
3124                 svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3125                 return;
3126         }
3127 
3128         if (verbose)
3129                 syslog(LOG_NOTICE, "UNMOUNT: %s unmounted %s", host, path);
3130 
3131         audit_mountd_umount(host, path);
3132 
3133         remove_path = rpath;    /* assume we will use the cannonical path */
3134         if (realpath(path, rpath) == NULL) {
3135                 if (verbose)
3136                         syslog(LOG_WARNING, "UNMOUNT: realpath: %s: %m ", path);
3137                 remove_path = path;     /* use path provided instead */
3138         }
3139 
3140         mntlist_delete(host, remove_path);      /* remove from mount list */
3141 
3142         cln_fini(&cln);
3143 
3144         svc_freeargs(transp, xdr_dirpath, (caddr_t)&path);
3145 }
3146 
3147 /*
3148  * Remove all entries for one machine from mounted list
3149  */
3150 static void
3151 umountall(struct svc_req *rqstp)
3152 {
3153         SVCXPRT *transp;
3154         char *host;
3155         struct cln cln;
3156 
3157         transp = rqstp->rq_xprt;
3158         if (!svc_getargs(transp, xdr_void, NULL)) {
3159                 svcerr_decode(transp);
3160                 return;
3161         }
3162         /*
3163          * We assume that this call is asynchronous and made via rpcbind
3164          * callit routine.  Therefore return control immediately. The error
3165          * causes rpcbind to remain silent, as opposed to every machine
3166          * on the net blasting the requester with a response.
3167          */
3168         svcerr_systemerr(transp);
3169 
3170         cln_init(&cln, transp);
3171 
3172         host = cln_gethost(&cln);
3173         if (host == NULL) {
3174                 /* Can't do anything without the name of the client */
3175                 return;
3176         }
3177 
3178         /*
3179          * Remove all hosts entries from mount list
3180          */
3181         mntlist_delete_all(host);
3182 
3183         if (verbose)
3184                 syslog(LOG_NOTICE, "UNMOUNTALL: from %s", host);
3185 
3186         cln_fini(&cln);
3187 }
3188 
3189 void *
3190 exmalloc(size_t size)
3191 {
3192         void *ret;
3193 
3194         if ((ret = malloc(size)) == NULL) {
3195                 syslog(LOG_ERR, "Out of memory");
3196                 exit(1);
3197         }
3198         return (ret);
3199 }
3200 
3201 static tsol_tpent_t *
3202 get_client_template(struct sockaddr *sock)
3203 {
3204         in_addr_t       v4client;
3205         in6_addr_t      v6client;
3206         char            v4_addr[INET_ADDRSTRLEN];
3207         char            v6_addr[INET6_ADDRSTRLEN];
3208         tsol_rhent_t    *rh;
3209         tsol_tpent_t    *tp;
3210 
3211         switch (sock->sa_family) {
3212         case AF_INET:
3213                 v4client = ((struct sockaddr_in *)(void *)sock)->
3214                     sin_addr.s_addr;
3215                 if (inet_ntop(AF_INET, &v4client, v4_addr, INET_ADDRSTRLEN) ==
3216                     NULL)
3217                         return (NULL);
3218                 rh = tsol_getrhbyaddr(v4_addr, sizeof (v4_addr), AF_INET);
3219                 if (rh == NULL)
3220                         return (NULL);
3221                 tp = tsol_gettpbyname(rh->rh_template);
3222                 tsol_freerhent(rh);
3223                 return (tp);
3224                 break;
3225         case AF_INET6:
3226                 v6client = ((struct sockaddr_in6 *)(void *)sock)->sin6_addr;
3227                 if (inet_ntop(AF_INET6, &v6client, v6_addr, INET6_ADDRSTRLEN) ==
3228                     NULL)
3229                         return (NULL);
3230                 rh = tsol_getrhbyaddr(v6_addr, sizeof (v6_addr), AF_INET6);
3231                 if (rh == NULL)
3232                         return (NULL);
3233                 tp = tsol_gettpbyname(rh->rh_template);
3234                 tsol_freerhent(rh);
3235                 return (tp);
3236                 break;
3237         default:
3238                 return (NULL);
3239         }
3240 }