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