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