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