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