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