Print this page
    
12505 Answer KEBE question about cred in unexport()
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/nfs/nfs_export.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_export.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
  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) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
  28   28   *              All rights reserved.
  29   29   */
  30   30  
  31   31  /*
  32   32   * Copyright 2018 Nexenta Systems, Inc.
  33   33   */
  34   34  
  35   35  #include <sys/types.h>
  36   36  #include <sys/param.h>
  37   37  #include <sys/time.h>
  38   38  #include <sys/vfs.h>
  39   39  #include <sys/vnode.h>
  40   40  #include <sys/socket.h>
  41   41  #include <sys/errno.h>
  42   42  #include <sys/uio.h>
  43   43  #include <sys/proc.h>
  44   44  #include <sys/user.h>
  45   45  #include <sys/file.h>
  46   46  #include <sys/tiuser.h>
  47   47  #include <sys/kmem.h>
  48   48  #include <sys/pathname.h>
  49   49  #include <sys/debug.h>
  50   50  #include <sys/vtrace.h>
  51   51  #include <sys/cmn_err.h>
  52   52  #include <sys/acl.h>
  53   53  #include <sys/utsname.h>
  54   54  #include <sys/sdt.h>
  55   55  #include <netinet/in.h>
  56   56  #include <sys/avl.h>
  57   57  
  58   58  #include <rpc/types.h>
  59   59  #include <rpc/auth.h>
  60   60  #include <rpc/svc.h>
  61   61  
  62   62  #include <nfs/nfs.h>
  63   63  #include <nfs/export.h>
  64   64  #include <nfs/nfssys.h>
  65   65  #include <nfs/nfs_clnt.h>
  66   66  #include <nfs/nfs_acl.h>
  67   67  #include <nfs/nfs_log.h>
  68   68  #include <nfs/lm.h>
  69   69  #include <sys/sunddi.h>
  70   70  
  71   71  /*
  72   72   * exi_id support
  73   73   *
  74   74   * exi_id_next          The next exi_id available.
  75   75   * exi_id_overflow      The exi_id_next already overflowed, so we should
  76   76   *                      thoroughly check for duplicates.
  77   77   * exi_id_tree          AVL tree indexed by exi_id.
  
    | 
      ↓ open down ↓ | 
    77 lines elided | 
    
      ↑ open up ↑ | 
  
  78   78   * nfs_exi_id_lock      Lock to protect the export ID list
  79   79   *
  80   80   * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
  81   81   * nfs_exi_id_lock.
  82   82   */
  83   83  static int exi_id_next;
  84   84  static bool_t exi_id_overflow;
  85   85  avl_tree_t exi_id_tree;
  86   86  kmutex_t nfs_exi_id_lock;
  87   87  
  88      -static int      unexport(nfs_export_t *, exportinfo_t *);
       88 +static int      unexport(nfs_export_t *, exportinfo_t *, cred_t *);
  89   89  static void     exportfree(exportinfo_t *);
  90   90  static int      loadindex(exportdata_t *);
  91   91  
  92   92  extern void     nfsauth_cache_free(exportinfo_t *);
  93   93  extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  94   94  extern void     sec_svc_freerootnames(int, int, caddr_t *);
  95   95  
  96   96  static int      build_seclist_nodups(exportdata_t *, secinfo_t *, int);
  97   97  static void     srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
  98   98  static void     srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
  99   99  static void     srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
 100  100                      secinfo_t *, int, bool_t);
 101  101  
 102  102  #ifdef VOLATILE_FH_TEST
 103  103  static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
 104  104  static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
 105  105  static void     free_volrnm_list(exportinfo_t *);
 106  106  #endif /* VOLATILE_FH_TEST */
 107  107  
 108  108  fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109  109  
 110  110  /*
 111  111   * macro for static dtrace probes to trace server namespace ref count mods.
 112  112   */
 113  113  #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114  114          DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115  115                  char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116  116  
 117  117  
 118  118  #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119  119  
 120  120  extern nfs_export_t *
 121  121  nfs_get_export(void)
 122  122  {
 123  123          nfs_globals_t *ng = nfs_srv_getzg();
 124  124          nfs_export_t *ne = ng->nfs_export;
 125  125          ASSERT(ne != NULL);
 126  126          return (ne);
 127  127  }
 128  128  
 129  129  static uint8_t
 130  130  xor_hash(uint8_t *data, int len)
 131  131  {
 132  132          uint8_t h = 0;
 133  133  
 134  134          while (len--)
 135  135                  h ^= *data++;
 136  136  
 137  137          return (h);
 138  138  }
 139  139  
 140  140  /*
 141  141   * File handle hash function, XOR over all bytes in fsid and fid.
 142  142   */
 143  143  static unsigned
 144  144  nfs_fhhash(fsid_t *fsid, fid_t *fid)
 145  145  {
 146  146          int len;
 147  147          uint8_t h;
 148  148  
 149  149          h = xor_hash((uint8_t *)fsid, sizeof (fsid_t));
 150  150  
 151  151          /*
 152  152           * Sanity check the length before using it
 153  153           * blindly in case the client trashed it.
 154  154           */
 155  155          len = fid->fid_len > NFS_FH4MAXDATA ? 0 : fid->fid_len;
 156  156          h ^= xor_hash((uint8_t *)fid->fid_data, len);
 157  157  
 158  158          return ((unsigned)h);
 159  159  }
 160  160  
 161  161  /*
 162  162   * Free the memory allocated within a secinfo entry.
 163  163   */
 164  164  void
 165  165  srv_secinfo_entry_free(struct secinfo *secp)
 166  166  {
 167  167          if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) {
 168  168                  sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum,
 169  169                      secp->s_rootcnt, secp->s_rootnames);
 170  170                  secp->s_rootcnt = 0;
 171  171          }
 172  172  
 173  173          if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) &&
 174  174              (secp->s_secinfo.sc_gss_mech_type)) {
 175  175                  kmem_free(secp->s_secinfo.sc_gss_mech_type->elements,
 176  176                      secp->s_secinfo.sc_gss_mech_type->length);
 177  177                  kmem_free(secp->s_secinfo.sc_gss_mech_type,
 178  178                      sizeof (rpc_gss_OID_desc));
 179  179                  secp->s_secinfo.sc_gss_mech_type = NULL;
 180  180          }
 181  181  }
 182  182  
 183  183  /*
 184  184   * Free a list of secinfo allocated in the exportdata structure.
 185  185   */
 186  186  void
 187  187  srv_secinfo_list_free(struct secinfo *secinfo, int cnt)
 188  188  {
 189  189          int i;
 190  190  
 191  191          if (cnt == 0)
 192  192                  return;
 193  193  
 194  194          for (i = 0; i < cnt; i++)
 195  195                  srv_secinfo_entry_free(&secinfo[i]);
 196  196  
 197  197          kmem_free(secinfo, cnt * sizeof (struct secinfo));
 198  198  }
 199  199  
 200  200  /*
 201  201   * Allocate and copy a secinfo data from "from" to "to".
 202  202   *
 203  203   * This routine is used by srv_secinfo_add() to add a new flavor to an
 204  204   * ancestor's export node. The rootnames are not copied because the
 205  205   * allowable rootname access only applies to the explicit exported node,
 206  206   * not its ancestor's.
 207  207   *
 208  208   * "to" should have already been allocated and zeroed before calling
 209  209   * this routine.
 210  210   *
 211  211   * This routine is used under the protection of exported_lock (RW_WRITER).
 212  212   */
 213  213  void
 214  214  srv_secinfo_copy(struct secinfo *from, struct secinfo *to)
 215  215  {
 216  216          to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum;
 217  217          to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum;
 218  218  
 219  219          if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
 220  220                  to->s_secinfo.sc_service = from->s_secinfo.sc_service;
 221  221                  bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name,
 222  222                      strlen(from->s_secinfo.sc_name));
 223  223                  bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech,
 224  224                      strlen(from->s_secinfo.sc_gss_mech));
 225  225  
 226  226                  /* copy mechanism oid */
 227  227                  to->s_secinfo.sc_gss_mech_type =
 228  228                      kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP);
 229  229                  to->s_secinfo.sc_gss_mech_type->length =
 230  230                      from->s_secinfo.sc_gss_mech_type->length;
 231  231                  to->s_secinfo.sc_gss_mech_type->elements =
 232  232                      kmem_alloc(from->s_secinfo.sc_gss_mech_type->length,
 233  233                      KM_SLEEP);
 234  234                  bcopy(from->s_secinfo.sc_gss_mech_type->elements,
 235  235                      to->s_secinfo.sc_gss_mech_type->elements,
 236  236                      from->s_secinfo.sc_gss_mech_type->length);
 237  237          }
 238  238  
 239  239          to->s_refcnt = from->s_refcnt;
 240  240          to->s_window = from->s_window;
 241  241          /* no need to copy the mode bits - s_flags */
 242  242  }
 243  243  
 244  244  /*
 245  245   * Create a secinfo array without duplicates.  The condensed
 246  246   * flavor list is used to propagate flavor ref counts  to an
 247  247   * export's ancestor pseudonodes.
 248  248   */
 249  249  static int
 250  250  build_seclist_nodups(exportdata_t *exd, secinfo_t *nodups, int exponly)
 251  251  {
 252  252          int ccnt, c;
 253  253          int ncnt, n;
 254  254          struct secinfo *cursec;
 255  255  
 256  256          ncnt = 0;
 257  257          ccnt = exd->ex_seccnt;
 258  258          cursec = exd->ex_secinfo;
 259  259  
 260  260          for (c = 0; c < ccnt; c++) {
 261  261  
 262  262                  if (exponly && ! SEC_REF_EXPORTED(&cursec[c]))
 263  263                          continue;
 264  264  
 265  265                  for (n = 0; n < ncnt; n++) {
 266  266                          if (nodups[n].s_secinfo.sc_nfsnum ==
 267  267                              cursec[c].s_secinfo.sc_nfsnum)
 268  268                                  break;
 269  269                  }
 270  270  
 271  271                  /*
 272  272                   * The structure copy below also copys ptrs embedded
 273  273                   * within struct secinfo.  The ptrs are copied but
 274  274                   * they are never freed from the nodups array.  If
 275  275                   * an ancestor's secinfo array doesn't contain one
 276  276                   * of the nodups flavors, then the entry is properly
 277  277                   * copied into the ancestor's secinfo array.
 278  278                   * (see srv_secinfo_copy)
 279  279                   */
 280  280                  if (n == ncnt) {
 281  281                          nodups[n] = cursec[c];
 282  282                          ncnt++;
 283  283                  }
 284  284          }
 285  285          return (ncnt);
 286  286  }
 287  287  
 288  288  /*
 289  289   * Add the new security flavors from newdata to the current list, pcursec.
 290  290   * Upon return, *pcursec has the newly merged secinfo list.
 291  291   *
 292  292   * There should be at least 1 secinfo entry in newsec.
 293  293   *
 294  294   * This routine is used under the protection of exported_lock (RW_WRITER).
 295  295   */
 296  296  static void
 297  297  srv_secinfo_add(secinfo_t **pcursec, int *pcurcnt, secinfo_t *newsec,
 298  298      int newcnt, int is_pseudo)
 299  299  {
 300  300          int ccnt, c;            /* sec count in current data - curdata */
 301  301          int n;                  /* index for newsec  - newsecinfo */
 302  302          int tcnt;               /* total sec count after merge */
 303  303          int mcnt;               /* total sec count after merge */
 304  304          struct secinfo *msec;   /* merged secinfo list */
 305  305          struct secinfo *cursec;
 306  306  
 307  307          cursec = *pcursec;
 308  308          ccnt = *pcurcnt;
 309  309  
 310  310          ASSERT(newcnt > 0);
 311  311          tcnt = ccnt + newcnt;
 312  312  
 313  313          for (n = 0; n < newcnt; n++) {
 314  314                  for (c = 0; c < ccnt; c++) {
 315  315                          if (newsec[n].s_secinfo.sc_nfsnum ==
 316  316                              cursec[c].s_secinfo.sc_nfsnum) {
 317  317                                  cursec[c].s_refcnt += newsec[n].s_refcnt;
 318  318                                  SECREF_TRACE(cursec, "add_ref",
 319  319                                      cursec[c].s_secinfo.sc_nfsnum,
 320  320                                      cursec[c].s_refcnt);
 321  321                                  tcnt--;
 322  322                                  break;
 323  323                          }
 324  324                  }
 325  325          }
 326  326  
 327  327          if (tcnt == ccnt)
 328  328                  return; /* no change; no new flavors */
 329  329  
 330  330          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 331  331  
 332  332          /* move current secinfo list data to the new list */
 333  333          for (c = 0; c < ccnt; c++)
 334  334                  msec[c] = cursec[c];
 335  335  
 336  336          /* Add the flavor that's not in the current data */
 337  337          mcnt = ccnt;
 338  338          for (n = 0; n < newcnt; n++) {
 339  339                  for (c = 0; c < ccnt; c++) {
 340  340                          if (newsec[n].s_secinfo.sc_nfsnum ==
 341  341                              cursec[c].s_secinfo.sc_nfsnum)
 342  342                                  break;
 343  343                  }
 344  344  
 345  345                  /* This is the one. Add it. */
 346  346                  if (c == ccnt) {
 347  347                          srv_secinfo_copy(&newsec[n], &msec[mcnt]);
 348  348  
 349  349                          if (is_pseudo)
 350  350                                  msec[mcnt].s_flags = M_RO;
 351  351  
 352  352                          SECREF_TRACE(msec, "new_ref",
 353  353                              msec[mcnt].s_secinfo.sc_nfsnum,
 354  354                              msec[mcnt].s_refcnt);
 355  355                          mcnt++;
 356  356                  }
 357  357          }
 358  358  
 359  359          ASSERT(mcnt == tcnt);
 360  360  
 361  361          /*
 362  362           * Done. Update curdata. Free the old secinfo list in
 363  363           * curdata and return the new sec array info
 364  364           */
 365  365          if (ccnt > 0)
 366  366                  kmem_free(cursec, ccnt * sizeof (struct secinfo));
 367  367          *pcurcnt = tcnt;
 368  368          *pcursec = msec;
 369  369  }
 370  370  
 371  371  /*
 372  372   * For NFS V4.
 373  373   * Remove the security data of the unexported node from its ancestors.
 374  374   * Assume there is at least one flavor entry in the current sec list
 375  375   * (pcursec).
 376  376   *
 377  377   * This routine is used under the protection of exported_lock (RW_WRITER).
 378  378   *
 379  379   * Every element of remsec is an explicitly exported flavor.  If
 380  380   * srv_secinfo_remove() is called fom an exportfs error path, then
 381  381   * the flavor list was derived from the user's share cmdline,
 382  382   * and all flavors are explicit.  If it was called from the unshare path,
 383  383   * build_seclist_nodups() was called with the exponly flag.
 384  384   */
 385  385  static void
 386  386  srv_secinfo_remove(secinfo_t **pcursec, int *pcurcnt, secinfo_t *remsec,
 387  387      int remcnt)
 388  388  {
 389  389          int ccnt, c;            /* sec count in current data - cursec */
 390  390          int r;                  /* sec count in removal data - remsec */
 391  391          int tcnt, mcnt;         /* total sec count after removing */
 392  392          struct secinfo *msec;   /* final secinfo list after removing */
 393  393          struct secinfo *cursec;
 394  394  
 395  395          cursec = *pcursec;
 396  396          ccnt = *pcurcnt;
 397  397          tcnt = ccnt;
 398  398  
 399  399          for (r = 0; r < remcnt; r++) {
 400  400                  /*
 401  401                   * At unshare/reshare time, only explicitly shared flavor ref
 402  402                   * counts are decremented and propagated to ancestors.
 403  403                   * Implicit flavor refs came from shared descendants, and
 404  404                   * they must be kept.
 405  405                   */
 406  406                  if (! SEC_REF_EXPORTED(&remsec[r]))
 407  407                          continue;
 408  408  
 409  409                  for (c = 0; c < ccnt; c++) {
 410  410                          if (remsec[r].s_secinfo.sc_nfsnum ==
 411  411                              cursec[c].s_secinfo.sc_nfsnum) {
 412  412  
 413  413                                  /*
 414  414                                   * Decrement secinfo reference count by 1.
 415  415                                   * If this entry is invalid after decrementing
 416  416                                   * the count (i.e. count < 1), this entry will
 417  417                                   * be removed.
 418  418                                   */
 419  419                                  cursec[c].s_refcnt--;
 420  420  
 421  421                                  SECREF_TRACE(cursec, "del_ref",
 422  422                                      cursec[c].s_secinfo.sc_nfsnum,
 423  423                                      cursec[c].s_refcnt);
 424  424  
 425  425                                  ASSERT(cursec[c].s_refcnt >= 0);
 426  426  
 427  427                                  if (SEC_REF_INVALID(&cursec[c]))
 428  428                                          tcnt--;
 429  429                                  break;
 430  430                          }
 431  431                  }
 432  432          }
 433  433  
 434  434          ASSERT(tcnt >= 0);
 435  435          if (tcnt == ccnt)
 436  436                  return; /* no change; no flavors to remove */
 437  437  
 438  438          if (tcnt == 0) {
 439  439                  srv_secinfo_list_free(cursec, ccnt);
 440  440                  *pcurcnt = 0;
 441  441                  *pcursec = NULL;
 442  442                  return;
 443  443          }
 444  444  
 445  445          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 446  446  
 447  447          /* walk thru the given secinfo list to remove the flavors */
 448  448          mcnt = 0;
 449  449          for (c = 0; c < ccnt; c++) {
 450  450                  if (SEC_REF_INVALID(&cursec[c])) {
 451  451                          srv_secinfo_entry_free(&cursec[c]);
 452  452                  } else {
 453  453                          msec[mcnt] = cursec[c];
 454  454                          mcnt++;
 455  455                  }
 456  456          }
 457  457  
 458  458          ASSERT(mcnt == tcnt);
 459  459          /*
 460  460           * Done. Update curdata.
 461  461           * Free the existing secinfo list in curdata. All pointers
 462  462           * within the list have either been moved to msec or freed
 463  463           * if it's invalid.
 464  464           */
 465  465          kmem_free(*pcursec, ccnt * sizeof (struct secinfo));
 466  466          *pcursec = msec;
 467  467          *pcurcnt = tcnt;
 468  468  }
 469  469  
 470  470  
 471  471  /*
 472  472   * For the reshare case, sec flavor accounting happens in 3 steps:
 473  473   * 1) propagate addition of new flavor refs up the ancestor tree
 474  474   * 2) transfer flavor refs of descendants to new/reshared exportdata
 475  475   * 3) propagate removal of old flavor refs up the ancestor tree
 476  476   *
 477  477   * srv_secinfo_exp2exp() implements step 2 of a reshare.  At this point,
 478  478   * the new flavor list has already been propagated up through the
 479  479   * ancestor tree via srv_secinfo_treeclimb().
 480  480   *
 481  481   * If there is more than 1 export reference to an old flavor (i.e. some
 482  482   * of its children shared with this flavor), this flavor information
 483  483   * needs to be transferred to the new exportdata struct.  A flavor in
 484  484   * the old exportdata has descendant refs when its s_refcnt > 1 or it
 485  485   * is implicitly shared (M_SEC4_EXPORTED not set in s_flags).
 486  486   *
 487  487   * SEC_REF_EXPORTED() is only true when  M_SEC4_EXPORTED is set
 488  488   * SEC_REF_SELF() is only true when both M_SEC4_EXPORTED is set and s_refcnt==1
 489  489   *
 490  490   * Transferring descendant flavor refcnts happens in 2 passes:
 491  491   * a) flavors used before (oldsecinfo) and after (curdata->ex_secinfo) reshare
 492  492   * b) flavors used before but not after reshare
 493  493   *
 494  494   * This routine is used under the protection of exported_lock (RW_WRITER).
 495  495   */
 496  496  void
 497  497  srv_secinfo_exp2exp(exportdata_t *curdata, secinfo_t *oldsecinfo, int ocnt)
 498  498  {
 499  499          int ccnt, c;            /* sec count in current data - curdata */
 500  500          int o;                  /* sec count in old data - oldsecinfo */
 501  501          int tcnt, mcnt;         /* total sec count after the transfer */
 502  502          struct secinfo *msec;   /* merged secinfo list */
 503  503  
 504  504          ccnt = curdata->ex_seccnt;
 505  505  
 506  506          ASSERT(ocnt > 0);
 507  507          ASSERT(!(curdata->ex_flags & EX_PSEUDO));
 508  508  
 509  509          /*
 510  510           * If the oldsecinfo has flavors with more than 1 reference count
 511  511           * and the flavor is specified in the reshare, transfer the flavor
 512  512           * refs to the new seclist (curdata.ex_secinfo).
 513  513           */
 514  514          tcnt = ccnt + ocnt;
 515  515  
 516  516          for (o = 0; o < ocnt; o++) {
 517  517  
 518  518                  if (SEC_REF_SELF(&oldsecinfo[o])) {
 519  519                          tcnt--;
 520  520                          continue;
 521  521                  }
 522  522  
 523  523                  for (c = 0; c < ccnt; c++) {
 524  524                          if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
 525  525                              curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) {
 526  526  
 527  527                                  /*
 528  528                                   * add old reference to the current
 529  529                                   * secinfo count
 530  530                                   */
 531  531                                  curdata->ex_secinfo[c].s_refcnt +=
 532  532                                      oldsecinfo[o].s_refcnt;
 533  533  
 534  534                                  /*
 535  535                                   * Delete the old export flavor
 536  536                                   * reference.  The initial reference
 537  537                                   * was created during srv_secinfo_add,
 538  538                                   * and the count is decremented below
 539  539                                   * to account for the initial reference.
 540  540                                   */
 541  541                                  if (SEC_REF_EXPORTED(&oldsecinfo[o]))
 542  542                                          curdata->ex_secinfo[c].s_refcnt--;
 543  543  
 544  544                                  SECREF_TRACE(curdata->ex_path,
 545  545                                      "reshare_xfer_common_child_refs",
 546  546                                      curdata->ex_secinfo[c].s_secinfo.sc_nfsnum,
 547  547                                      curdata->ex_secinfo[c].s_refcnt);
 548  548  
 549  549                                  ASSERT(curdata->ex_secinfo[c].s_refcnt >= 0);
 550  550  
 551  551                                  tcnt--;
 552  552                                  break;
 553  553                          }
 554  554                  }
 555  555          }
 556  556  
 557  557          if (tcnt == ccnt)
 558  558                  return; /* no more transfer to do */
 559  559  
 560  560          /*
 561  561           * oldsecinfo has flavors referenced by its children that are not
 562  562           * in the current (new) export flavor list.  Add these flavors.
 563  563           */
 564  564          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 565  565  
 566  566          /* move current secinfo list data to the new list */
 567  567          for (c = 0; c < ccnt; c++)
 568  568                  msec[c] = curdata->ex_secinfo[c];
 569  569  
 570  570          /*
 571  571           * Add the flavor that's not in the new export, but still
 572  572           * referenced by its children.
 573  573           */
 574  574          mcnt = ccnt;
 575  575          for (o = 0; o < ocnt; o++) {
 576  576                  if (! SEC_REF_SELF(&oldsecinfo[o])) {
 577  577                          for (c = 0; c < ccnt; c++) {
 578  578                                  if (oldsecinfo[o].s_secinfo.sc_nfsnum ==
 579  579                                      curdata->ex_secinfo[c].s_secinfo.sc_nfsnum)
 580  580                                          break;
 581  581                          }
 582  582  
 583  583                          /*
 584  584                           * This is the one. Add it. Decrement the ref count
 585  585                           * by 1 if the flavor is an explicitly shared flavor
 586  586                           * for the oldsecinfo export node.
 587  587                           */
 588  588                          if (c == ccnt) {
 589  589                                  srv_secinfo_copy(&oldsecinfo[o], &msec[mcnt]);
 590  590                                  if (SEC_REF_EXPORTED(&oldsecinfo[o]))
 591  591                                          msec[mcnt].s_refcnt--;
 592  592  
 593  593                                  SECREF_TRACE(curdata,
 594  594                                      "reshare_xfer_implicit_child_refs",
 595  595                                      msec[mcnt].s_secinfo.sc_nfsnum,
 596  596                                      msec[mcnt].s_refcnt);
 597  597  
 598  598                                  ASSERT(msec[mcnt].s_refcnt >= 0);
 599  599                                  mcnt++;
 600  600                          }
 601  601                  }
 602  602          }
 603  603  
 604  604          ASSERT(mcnt == tcnt);
 605  605          /*
 606  606           * Done. Update curdata, free the existing secinfo list in
 607  607           * curdata and set the new value.
 608  608           */
 609  609          if (ccnt > 0)
 610  610                  kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo));
 611  611          curdata->ex_seccnt = tcnt;
 612  612          curdata->ex_secinfo = msec;
 613  613  }
 614  614  
 615  615  /*
 616  616   * When unsharing an old export node and the old node becomes a pseudo node,
 617  617   * if there is more than 1 export reference to an old flavor (i.e. some of
 618  618   * its children shared with this flavor), this flavor information needs to
 619  619   * be transferred to the new shared node.
 620  620   *
 621  621   * This routine is used under the protection of exported_lock (RW_WRITER).
 622  622   */
 623  623  void
 624  624  srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
 625  625  {
 626  626          int ocnt, o;            /* sec count in transfer data - trandata */
 627  627          int tcnt, mcnt;         /* total sec count after transfer */
 628  628          struct secinfo *msec;   /* merged secinfo list */
 629  629  
 630  630          ASSERT(curdata->ex_flags & EX_PSEUDO);
 631  631          ASSERT(curdata->ex_seccnt == 0);
 632  632  
 633  633          ocnt = olddata->ex_seccnt;
 634  634  
 635  635          /*
 636  636           * If the olddata has flavors with more than 1 reference count,
 637  637           * transfer the information to the curdata.
 638  638           */
 639  639          tcnt = ocnt;
 640  640  
 641  641          for (o = 0; o < ocnt; o++) {
 642  642                  if (SEC_REF_SELF(&olddata->ex_secinfo[o]))
 643  643                          tcnt--;
 644  644          }
 645  645  
 646  646          if (tcnt == 0)
 647  647                  return; /* no transfer to do */
 648  648  
 649  649          msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP);
 650  650  
 651  651          mcnt = 0;
 652  652          for (o = 0; o < ocnt; o++) {
 653  653                  if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) {
 654  654  
 655  655                          /*
 656  656                           * Decrement the reference count by 1 if the flavor is
 657  657                           * an explicitly shared flavor for the olddata export
 658  658                           * node.
 659  659                           */
 660  660                          srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]);
 661  661                          msec[mcnt].s_flags = M_RO;
 662  662                          if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o]))
 663  663                                  msec[mcnt].s_refcnt--;
 664  664  
 665  665                          SECREF_TRACE(curdata, "unshare_morph_pseudo",
 666  666                              msec[mcnt].s_secinfo.sc_nfsnum,
 667  667                              msec[mcnt].s_refcnt);
 668  668  
 669  669                          ASSERT(msec[mcnt].s_refcnt >= 0);
 670  670                          mcnt++;
 671  671                  }
 672  672          }
 673  673  
 674  674          ASSERT(mcnt == tcnt);
 675  675          /*
 676  676           * Done. Update curdata.
 677  677           * Free up the existing secinfo list in curdata and
 678  678           * set the new value.
 679  679           */
 680  680          curdata->ex_seccnt = tcnt;
 681  681          curdata->ex_secinfo = msec;
 682  682  }
 683  683  
 684  684  /*
 685  685   * Find for given treenode the exportinfo which has its
 686  686   * exp_visible linked on its exi_visible list.
 687  687   *
 688  688   * Note: We could add new pointer either to treenode or
 689  689   * to exp_visible, which will point there directly.
 690  690   * This would buy some speed for some memory.
 691  691   */
 692  692  exportinfo_t *
 693  693  vis2exi(treenode_t *tnode)
 694  694  {
 695  695          exportinfo_t *exi_ret = NULL;
 696  696  
 697  697          for (;;) {
 698  698                  tnode = tnode->tree_parent;
 699  699                  if (TREE_ROOT(tnode)) {
 700  700                          exi_ret = tnode->tree_exi;
 701  701                          break;
 702  702                  }
 703  703          }
 704  704  
 705  705          /* Every visible should have its home exportinfo */
 706  706          ASSERT(exi_ret != NULL);
 707  707          return (exi_ret);
 708  708  }
 709  709  
 710  710  /*
 711  711   * For NFS V4.
 712  712   * Add or remove the newly exported or unexported security flavors of the
 713  713   * given exportinfo from its ancestors upto the system root.
 714  714   */
 715  715  static void
 716  716  srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 717  717      int seccnt, bool_t isadd)
 718  718  {
 719  719          treenode_t *tnode;
 720  720  
 721  721          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 722  722  
 723  723          /*
 724  724           * exi_tree can be null for the zone root
 725  725           * which means we're already at the "top"
 726  726           * and there's nothing more to "climb".
 727  727           */
 728  728          tnode = exip->exi_tree;
 729  729          if (tnode == NULL) {
 730  730                  /* Should only happen for... */
 731  731                  ASSERT(exip == ne->exi_root);
 732  732                  return;
 733  733          }
 734  734  
 735  735          if (seccnt == 0)
 736  736                  return;
 737  737  
 738  738          /*
 739  739           * If flavors are being added and the new export root isn't
 740  740           * also VROOT, its implicitly allowed flavors are inherited from
 741  741           * its pseudonode.
 742  742           * Note - for VROOT exports the implicitly allowed flavors were
 743  743           * transferred from the PSEUDO export in exportfs()
 744  744           */
 745  745          if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 746  746              !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 747  747              tnode->tree_vis->vis_seccnt > 0) {
 748  748                  srv_secinfo_add(&exip->exi_export.ex_secinfo,
 749  749                      &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 750  750                      tnode->tree_vis->vis_seccnt, FALSE);
 751  751          }
 752  752  
 753  753          /*
 754  754           * Move to parent node and propagate sec flavor
 755  755           * to exportinfo and to visible structures.
 756  756           */
 757  757          tnode = tnode->tree_parent;
 758  758  
 759  759          while (tnode != NULL) {
 760  760  
 761  761                  /* If there is exportinfo, update it */
 762  762                  if (tnode->tree_exi != NULL) {
 763  763                          secinfo_t **pxsec =
 764  764                              &tnode->tree_exi->exi_export.ex_secinfo;
 765  765                          int *pxcnt = &tnode->tree_exi->exi_export.ex_seccnt;
 766  766                          int is_pseudo = PSEUDO(tnode->tree_exi);
 767  767                          if (isadd)
 768  768                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 769  769                                      is_pseudo);
 770  770                          else
 771  771                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 772  772                  }
 773  773  
 774  774                  /* Update every visible - only root node has no visible */
 775  775                  if (tnode->tree_vis != NULL) {
 776  776                          secinfo_t **pxsec = &tnode->tree_vis->vis_secinfo;
 777  777                          int *pxcnt = &tnode->tree_vis->vis_seccnt;
 778  778                          if (isadd)
 779  779                                  srv_secinfo_add(pxsec, pxcnt, sec, seccnt,
 780  780                                      FALSE);
 781  781                          else
 782  782                                  srv_secinfo_remove(pxsec, pxcnt, sec, seccnt);
 783  783                  }
 784  784                  tnode = tnode->tree_parent;
 785  785          }
 786  786  }
 787  787  
 788  788  /* hash_name is a text substitution for either fid_hash or path_hash */
 789  789  #define exp_hash_unlink(exi, hash_name) \
 790  790          if (*(exi)->hash_name.bckt == (exi)) \
 791  791                  *(exi)->hash_name.bckt = (exi)->hash_name.next; \
 792  792          if ((exi)->hash_name.prev) \
 793  793                  (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 794  794          if ((exi)->hash_name.next) \
 795  795                  (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 796  796          (exi)->hash_name.bckt = NULL;
 797  797  
 798  798  #define exp_hash_link(exi, hash_name, bucket) \
 799  799          (exi)->hash_name.bckt = (bucket); \
 800  800          (exi)->hash_name.prev = NULL; \
 801  801          (exi)->hash_name.next = *(bucket); \
 802  802          if ((exi)->hash_name.next) \
 803  803                  (exi)->hash_name.next->hash_name.prev = (exi); \
 804  804          *(bucket) = (exi);
 805  805  
 806  806  void
 807  807  export_link(nfs_export_t *ne, exportinfo_t *exi)
 808  808  {
 809  809          exportinfo_t **bckt;
 810  810  
 811  811          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 812  812  
 813  813          bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 814  814          exp_hash_link(exi, fid_hash, bckt);
 815  815  
 816  816          bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 817  817              strlen(exi->exi_export.ex_path))];
 818  818          exp_hash_link(exi, path_hash, bckt);
 819  819          exi->exi_ne = ne;
 820  820  }
 821  821  
 822  822  /*
 823  823   * Helper functions for exi_id handling
 824  824   */
 825  825  static int
 826  826  exi_id_compar(const void *v1, const void *v2)
 827  827  {
 828  828          const struct exportinfo *e1 = v1;
 829  829          const struct exportinfo *e2 = v2;
 830  830  
 831  831          if (e1->exi_id < e2->exi_id)
 832  832                  return (-1);
 833  833          if (e1->exi_id > e2->exi_id)
 834  834                  return (1);
 835  835  
 836  836          return (0);
 837  837  }
 838  838  
 839  839  int
 840  840  exi_id_get_next()
 841  841  {
 842  842          struct exportinfo e;
 843  843          int ret = exi_id_next;
 844  844  
 845  845          ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
 846  846  
 847  847          do {
 848  848                  exi_id_next++;
 849  849                  if (exi_id_next == 0)
 850  850                          exi_id_overflow = TRUE;
 851  851  
 852  852                  if (!exi_id_overflow)
 853  853                          break;
 854  854  
 855  855                  if (exi_id_next == ret)
 856  856                          cmn_err(CE_PANIC, "exi_id exhausted");
 857  857  
 858  858                  e.exi_id = exi_id_next;
 859  859          } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 860  860  
 861  861          return (ret);
 862  862  }
 863  863  
 864  864  /*
 865  865   * Get the root file handle for this zone.
 866  866   * Called when nfs_svc() starts
 867  867   */
 868  868  int
 869  869  nfs_export_get_rootfh(nfs_globals_t *g)
 870  870  {
 871  871          nfs_export_t *ne = g->nfs_export;
 872  872          int err;
 873  873  
 874  874          ne->exi_rootfid.fid_len = MAXFIDSZ;
 875  875          err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
 876  876          if (err != 0) {
 877  877                  ne->exi_rootfid.fid_len = 0;
 878  878                  return (err);
 879  879          }
 880  880  
 881  881          /* Setup the fhandle template exi_fh */
 882  882          ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 883  883          ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 884  884          bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 885  885              ne->exi_rootfid.fid_len);
 886  886          ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 887  887  
 888  888          return (0);
 889  889  }
 890  890  
 891  891  void
 892  892  nfs_export_zone_init(nfs_globals_t *ng)
 893  893  {
 894  894          int i;
 895  895          nfs_export_t *ne;
 896  896          zone_t *zone;
 897  897  
 898  898          ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 899  899  
 900  900          rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 901  901  
 902  902          ne->ne_globals = ng; /* "up" pointer */
 903  903  
 904  904          /*
 905  905           * Allocate the place holder for the public file handle, which
 906  906           * is all zeroes. It is initially set to the root filesystem.
 907  907           */
 908  908          ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 909  909          ne->exi_public = ne->exi_root;
 910  910  
 911  911          ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 912  912          ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
 913  913          ne->exi_root->exi_export.ex_path =
 914  914              kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 915  915          ne->exi_root->exi_export.ex_path[0] = '/';
 916  916          ne->exi_root->exi_export.ex_path[1] = '\0';
 917  917  
 918  918          ne->exi_root->exi_count = 1;
 919  919          mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 920  920  
 921  921          /*
 922  922           * Because we cannot:
 923  923           *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
 924  924           * We grab the zone pointer explicitly (like netstacks do) and
 925  925           * set the rootvp here.
 926  926           *
 927  927           * Subsequent exportinfo_t's that get export_link()ed to "ne" also
 928  928           * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
 929  929           * will get the zone's rootvp for a given exportinfo_t.
 930  930           */
 931  931          zone = zone_find_by_id_nolock(ng->nfs_zoneid);
 932  932          ne->exi_root->exi_vp = zone->zone_rootvp;
 933  933          ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 934  934  
 935  935          /*
 936  936           * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 937  937           * because we can't correctly return errors here.
 938  938           */
 939  939  
 940  940          /* Initialize auth cache and auth cache lock */
 941  941          for (i = 0; i < AUTH_TABLESIZE; i++) {
 942  942                  ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 943  943                      KM_SLEEP);
 944  944                  avl_create(ne->exi_root->exi_cache[i],
 945  945                      nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 946  946                      offsetof(struct auth_cache_clnt, authc_link));
 947  947          }
 948  948          rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 949  949  
 950  950          /* setup exi_fh later, in nfs_export_get_rootfid */
 951  951  
 952  952          rw_enter(&ne->exported_lock, RW_WRITER);
 953  953  
 954  954          /* Publish the exportinfo in the hash table */
 955  955          export_link(ne, ne->exi_root);
 956  956  
 957  957          /* Initialize exi_id and exi_kstats */
 958  958          mutex_enter(&nfs_exi_id_lock);
 959  959          ne->exi_root->exi_id = exi_id_get_next();
 960  960          avl_add(&exi_id_tree, ne->exi_root);
 961  961          mutex_exit(&nfs_exi_id_lock);
 962  962  
 963  963          rw_exit(&ne->exported_lock);
 964  964          ne->ns_root = NULL;
 965  965  
 966  966          ng->nfs_export = ne;
 967  967  }
  
    | 
      ↓ open down ↓ | 
    869 lines elided | 
    
      ↑ open up ↑ | 
  
 968  968  
 969  969  /*
 970  970   * During zone shutdown, remove exports
 971  971   */
 972  972  void
 973  973  nfs_export_zone_shutdown(nfs_globals_t *ng)
 974  974  {
 975  975          nfs_export_t *ne = ng->nfs_export;
 976  976          struct exportinfo *exi, *nexi;
 977  977          int i, errors;
      978 +        zoneid_t zoneid = ng->nfs_zoneid;
      979 +        cred_t *cr;
 978  980  
      981 +        /*
      982 +         * Use the zone's credential.  Since this is a zone shutdown method,
      983 +         * the zone_t should still be around for a zone_get_kcred() call.
      984 +         */
      985 +        cr = zone_get_kcred(zoneid);
      986 +        VERIFY(cr != NULL);
 979  987          rw_enter(&ne->exported_lock, RW_READER);
 980  988  
 981  989          errors = 0;
 982  990          for (i = 0; i < EXPTABLESIZE; i++) {
 983  991  
 984  992                  exi = ne->exptable[i];
 985  993                  if (exi != NULL)
 986  994                          exi_hold(exi);
 987  995  
 988  996                  while (exi != NULL) {
 989      -
      997 +                        ASSERT3U(zoneid, ==, exi->exi_zoneid);
 990  998                          /*
 991  999                           * Get and hold next export before
 992 1000                           * dropping the rwlock and unexport
 993 1001                           */
 994 1002                          nexi = exi->fid_hash.next;
 995 1003                          if (nexi != NULL)
 996 1004                                  exi_hold(nexi);
 997 1005  
 998 1006                          rw_exit(&ne->exported_lock);
 999 1007  
1000 1008                          /*
1001 1009                           * Skip ne->exi_root which gets special
1002 1010                           * create/destroy handling.
1003 1011                           */
1004 1012                          if (exi != ne->exi_root &&
1005      -                            unexport(ne, exi) != 0)
     1013 +                            unexport(ne, exi, cr) != 0)
1006 1014                                  errors++;
1007 1015                          exi_rele(exi);
1008 1016  
1009 1017                          rw_enter(&ne->exported_lock, RW_READER);
1010 1018                          exi = nexi;
1011 1019                  }
1012 1020          }
1013 1021          if (errors > 0) {
1014 1022                  cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
1015 1023                      (int)ng->nfs_zoneid);
1016 1024          }
1017 1025  
1018 1026          rw_exit(&ne->exported_lock);
     1027 +        crfree(cr);
1019 1028  }
1020 1029  
1021 1030  void
1022 1031  nfs_export_zone_fini(nfs_globals_t *ng)
1023 1032  {
1024 1033          int i;
1025 1034          nfs_export_t *ne = ng->nfs_export;
1026 1035          struct exportinfo *exi;
1027 1036  
1028 1037          ng->nfs_export = NULL;
1029 1038  
1030 1039          rw_enter(&ne->exported_lock, RW_WRITER);
1031 1040  
1032 1041          mutex_enter(&nfs_exi_id_lock);
1033 1042          avl_remove(&exi_id_tree, ne->exi_root);
1034 1043          mutex_exit(&nfs_exi_id_lock);
1035 1044  
1036 1045          export_unlink(ne, ne->exi_root);
1037 1046  
1038 1047          rw_exit(&ne->exported_lock);
1039 1048  
1040 1049          /* Deallocate the place holder for the public file handle */
1041 1050          srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
1042 1051              ne->exi_root->exi_export.ex_seccnt);
1043 1052          mutex_destroy(&ne->exi_root->exi_lock);
1044 1053  
1045 1054          rw_destroy(&ne->exi_root->exi_cache_lock);
1046 1055          for (i = 0; i < AUTH_TABLESIZE; i++) {
1047 1056                  avl_destroy(ne->exi_root->exi_cache[i]);
1048 1057                  kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
1049 1058          }
1050 1059  
1051 1060          kmem_free(ne->exi_root->exi_export.ex_path,
1052 1061              ne->exi_root->exi_export.ex_pathlen + 1);
1053 1062          kmem_free(ne->exi_root, sizeof (*ne->exi_root));
1054 1063  
1055 1064          /*
1056 1065           * The shutdown hook should have left the exi_id_tree
1057 1066           * with nothing belonging to this zone.
1058 1067           */
1059 1068          mutex_enter(&nfs_exi_id_lock);
1060 1069          i = 0;
1061 1070          exi = avl_first(&exi_id_tree);
1062 1071          while (exi != NULL) {
1063 1072                  if (exi->exi_zoneid == ng->nfs_zoneid)
1064 1073                          i++;
1065 1074                  exi = AVL_NEXT(&exi_id_tree, exi);
1066 1075          }
1067 1076          mutex_exit(&nfs_exi_id_lock);
1068 1077          if (i > 0) {
1069 1078                  cmn_err(CE_NOTE,
1070 1079                      "NFS: zone %d has %d export IDs left after shutdown",
1071 1080                      (int)ng->nfs_zoneid, i);
1072 1081          }
1073 1082          rw_destroy(&ne->exported_lock);
1074 1083          kmem_free(ne, sizeof (*ne));
1075 1084  }
1076 1085  
1077 1086  /*
1078 1087   * Initialization routine for export routines.
1079 1088   * Should only be called once.
1080 1089   */
1081 1090  void
1082 1091  nfs_exportinit(void)
1083 1092  {
1084 1093          mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
1085 1094  
1086 1095          /* exi_id handling initialization */
1087 1096          exi_id_next = 0;
1088 1097          exi_id_overflow = FALSE;
1089 1098          avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
1090 1099              offsetof(struct exportinfo, exi_id_link));
1091 1100  
1092 1101          nfslog_init();
1093 1102  }
1094 1103  
1095 1104  /*
1096 1105   * Finalization routine for export routines.
1097 1106   */
1098 1107  void
1099 1108  nfs_exportfini(void)
1100 1109  {
1101 1110          avl_destroy(&exi_id_tree);
1102 1111          mutex_destroy(&nfs_exi_id_lock);
1103 1112  }
1104 1113  
1105 1114  /*
1106 1115   *  Check if 2 gss mechanism identifiers are the same.
1107 1116   *
1108 1117   *  return FALSE if not the same.
1109 1118   *  return TRUE if the same.
1110 1119   */
1111 1120  static bool_t
1112 1121  nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
1113 1122  {
1114 1123          if ((mech1->length == 0) && (mech2->length == 0))
1115 1124                  return (TRUE);
1116 1125  
1117 1126          if (mech1->length != mech2->length)
1118 1127                  return (FALSE);
1119 1128  
1120 1129          return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
1121 1130  }
1122 1131  
1123 1132  /*
1124 1133   *  This routine is used by rpc to map rpc security number
1125 1134   *  to nfs specific security flavor number.
1126 1135   *
1127 1136   *  The gss callback prototype is
1128 1137   *  callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *,
1129 1138   *                              rpc_gss_lock_t *, void **),
1130 1139   *  since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments
1131 1140   *  we cast them to void.
1132 1141   */
1133 1142  /*ARGSUSED*/
1134 1143  bool_t
1135 1144  rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
1136 1145      rpc_gss_lock_t *lock, void **cookie)
1137 1146  {
1138 1147          int i, j;
1139 1148          rpc_gss_rawcred_t *raw_cred;
1140 1149          struct exportinfo *exi;
1141 1150          nfs_export_t *ne = nfs_get_export();
1142 1151  
1143 1152          /*
1144 1153           * We don't deal with delegated credentials.
1145 1154           */
1146 1155          if (deleg != GSS_C_NO_CREDENTIAL)
1147 1156                  return (FALSE);
1148 1157  
1149 1158          raw_cred = lock->raw_cred;
1150 1159          *cookie = NULL;
1151 1160  
1152 1161          rw_enter(&ne->exported_lock, RW_READER);
1153 1162  
1154 1163          for (i = 0; i < EXPTABLESIZE; i++) {
1155 1164                  exi = ne->exptable[i];
1156 1165                  while (exi) {
1157 1166                          if (exi->exi_export.ex_seccnt > 0) {
1158 1167                                  struct secinfo *secp;
1159 1168                                  seconfig_t *se;
1160 1169                                  int seccnt;
1161 1170  
1162 1171                                  secp = exi->exi_export.ex_secinfo;
1163 1172                                  seccnt = exi->exi_export.ex_seccnt;
1164 1173                                  for (j = 0; j < seccnt; j++) {
1165 1174                                          /*
1166 1175                                           *  If there is a map of the triplet
1167 1176                                           *  (mechanism, service, qop) between
1168 1177                                           *  raw_cred and the exported flavor,
1169 1178                                           *  get the psudo flavor number.
1170 1179                                           *  Also qop should not be NULL, it
1171 1180                                           *  should be "default" or something
1172 1181                                           *  else.
1173 1182                                           */
1174 1183                                          se = &secp[j].s_secinfo;
1175 1184                                          if ((se->sc_rpcnum == RPCSEC_GSS) &&
1176 1185  
1177 1186                                              (nfs_mech_equal(
1178 1187                                              se->sc_gss_mech_type,
1179 1188                                              raw_cred->mechanism)) &&
1180 1189  
1181 1190                                              (se->sc_service ==
1182 1191                                              raw_cred->service) &&
1183 1192                                              (raw_cred->qop == se->sc_qop)) {
1184 1193  
1185 1194                                                  *cookie = (void *)(uintptr_t)
1186 1195                                                      se->sc_nfsnum;
1187 1196                                                  goto done;
1188 1197                                          }
1189 1198                                  }
1190 1199                          }
1191 1200                          exi = exi->fid_hash.next;
1192 1201                  }
1193 1202          }
1194 1203  done:
1195 1204          rw_exit(&ne->exported_lock);
1196 1205  
1197 1206          /*
1198 1207           * If no nfs pseudo number mapping can be found in the export
1199 1208           * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
1200 1209           * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
1201 1210           *
1202 1211           * For example:
1203 1212           *      server first shares with krb5i;
1204 1213           *      client mounts with krb5i;
1205 1214           *      server re-shares with krb5p;
1206 1215           *      client tries with krb5i, but no mapping can be found;
1207 1216           *      rpcsec_gss module calls this routine to do the mapping,
1208 1217           *              if this routine fails, request is rejected from
1209 1218           *              the rpc layer.
1210 1219           *      What we need is to let the nfs layer rejects the request.
1211 1220           *      For V4, we can reject with NFS4ERR_WRONGSEC and the client
1212 1221           *      may recover from it by getting the new flavor via SECINFO.
1213 1222           *
1214 1223           * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf)
1215 1224           * is owned by IANA (see RFC 2623).
1216 1225           *
1217 1226           * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around
1218 1227           * the implementation issue. This number should not overlap with
1219 1228           * any new IANA defined pseudo flavor numbers.
1220 1229           */
1221 1230          if (*cookie == NULL)
1222 1231                  *cookie = (void *)NFS_FLAVOR_NOMAP;
1223 1232  
1224 1233          lock->locked = TRUE;
1225 1234  
1226 1235          return (TRUE);
1227 1236  }
1228 1237  
1229 1238  
1230 1239  /*
1231 1240   * Exportfs system call; credentials should be checked before
1232 1241   * calling this function.
1233 1242   */
1234 1243  int
1235 1244  exportfs(struct exportfs_args *args, model_t model, cred_t *cr)
1236 1245  {
1237 1246          vnode_t *vp;
1238 1247          vnode_t *dvp;
1239 1248          struct exportdata *kex;
1240 1249          struct exportinfo *exi = NULL;
1241 1250          struct exportinfo *ex, *ex1, *ex2;
1242 1251          fid_t fid;
1243 1252          fsid_t fsid;
1244 1253          int error;
1245 1254          size_t allocsize;
1246 1255          struct secinfo *sp;
1247 1256          struct secinfo *exs;
1248 1257          rpc_gss_callback_t cb;
1249 1258          char *pathbuf;
1250 1259          char *log_buffer;
1251 1260          char *tagbuf;
1252 1261          int callback;
1253 1262          int allocd_seccnt;
1254 1263          STRUCT_HANDLE(exportfs_args, uap);
1255 1264          STRUCT_DECL(exportdata, uexi);
1256 1265          struct secinfo newsec[MAX_FLAVORS];
1257 1266          int newcnt;
1258 1267          struct secinfo oldsec[MAX_FLAVORS];
1259 1268          int oldcnt;
1260 1269          int i;
1261 1270          struct pathname lookpn;
1262 1271          nfs_export_t *ne = nfs_get_export();
1263 1272  
1264 1273          STRUCT_SET_HANDLE(uap, model, args);
1265 1274  
1266 1275          /* Read in pathname from userspace */
1267 1276          if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1268 1277                  return (error);
1269 1278  
1270 1279          /* Walk the export list looking for that pathname */
1271 1280          rw_enter(&ne->exported_lock, RW_READER);
1272 1281          DTRACE_PROBE(nfss__i__exported_lock1_start);
1273 1282          for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1274 1283              strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1275 1284                  if (ex1 != ne->exi_root && 0 ==
1276 1285                      strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1277 1286                          exi_hold(ex1);
1278 1287                          break;
  
    | 
      ↓ open down ↓ | 
    250 lines elided | 
    
      ↑ open up ↑ | 
  
1279 1288                  }
1280 1289          }
1281 1290          DTRACE_PROBE(nfss__i__exported_lock1_stop);
1282 1291          rw_exit(&ne->exported_lock);
1283 1292  
1284 1293          /* Is this an unshare? */
1285 1294          if (STRUCT_FGETP(uap, uex) == NULL) {
1286 1295                  pn_free(&lookpn);
1287 1296                  if (ex1 == NULL)
1288 1297                          return (EINVAL);
1289      -                error = unexport(ne, ex1);
     1298 +                error = unexport(ne, ex1, cr);
1290 1299                  exi_rele(ex1);
1291 1300                  return (error);
1292 1301          }
1293 1302  
1294 1303          /* It is a share or a re-share */
1295 1304          error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1296 1305              FOLLOW, &dvp, &vp);
1297 1306          if (error == EINVAL) {
1298 1307                  /*
1299 1308                   * if fname resolves to / we get EINVAL error
1300 1309                   * since we wanted the parent vnode. Try again
1301 1310                   * with NULL dvp.
1302 1311                   */
1303 1312                  error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1304 1313                      FOLLOW, NULL, &vp);
1305 1314                  dvp = NULL;
1306 1315          }
1307 1316          if (!error && vp == NULL) {
1308 1317                  /* Last component of fname not found */
1309 1318                  if (dvp != NULL)
1310 1319                          VN_RELE(dvp);
1311 1320                  error = ENOENT;
1312 1321          }
1313 1322          if (error) {
1314 1323                  pn_free(&lookpn);
1315 1324                  if (ex1)
1316 1325                          exi_rele(ex1);
1317 1326                  return (error);
1318 1327          }
1319 1328  
1320 1329          /*
1321 1330           * 'vp' may be an AUTOFS node, so we perform a
1322 1331           * VOP_ACCESS() to trigger the mount of the
1323 1332           * intended filesystem, so we can share the intended
1324 1333           * filesystem instead of the AUTOFS filesystem.
1325 1334           */
1326 1335          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
1327 1336  
1328 1337          /*
1329 1338           * We're interested in the top most filesystem.
1330 1339           * This is specially important when uap->dname is a trigger
1331 1340           * AUTOFS node, since we're really interested in sharing the
1332 1341           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1333 1342           * call not the AUTOFS node itself.
1334 1343           */
1335 1344          if (vn_mountedvfs(vp) != NULL) {
1336 1345                  if (error = traverse(&vp)) {
1337 1346                          VN_RELE(vp);
1338 1347                          if (dvp != NULL)
1339 1348                                  VN_RELE(dvp);
1340 1349                          pn_free(&lookpn);
1341 1350                          if (ex1)
1342 1351                                  exi_rele(ex1);
1343 1352                          return (error);
1344 1353                  }
1345 1354          }
1346 1355  
1347 1356          /* Do not allow sharing another vnode for already shared path */
1348 1357          if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1349 1358                  VN_RELE(vp);
1350 1359                  if (dvp != NULL)
1351 1360                          VN_RELE(dvp);
1352 1361                  pn_free(&lookpn);
1353 1362                  exi_rele(ex1);
1354 1363                  return (EEXIST);
1355 1364          }
1356 1365          if (ex1)
1357 1366                  exi_rele(ex1);
1358 1367  
1359 1368          /*
1360 1369           * Get the vfs id
1361 1370           */
1362 1371          bzero(&fid, sizeof (fid));
1363 1372          fid.fid_len = MAXFIDSZ;
1364 1373          error = VOP_FID(vp, &fid, NULL);
1365 1374          fsid = vp->v_vfsp->vfs_fsid;
1366 1375  
1367 1376          if (error) {
1368 1377                  VN_RELE(vp);
1369 1378                  if (dvp != NULL)
1370 1379                          VN_RELE(dvp);
1371 1380                  /*
1372 1381                   * If VOP_FID returns ENOSPC then the fid supplied
1373 1382                   * is too small.  For now we simply return EREMOTE.
1374 1383                   */
1375 1384                  if (error == ENOSPC)
1376 1385                          error = EREMOTE;
1377 1386                  pn_free(&lookpn);
1378 1387                  return (error);
1379 1388          }
1380 1389  
1381 1390          /*
1382 1391           * Do not allow re-sharing a shared vnode under a different path
1383 1392           * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1384 1393           */
1385 1394          rw_enter(&ne->exported_lock, RW_READER);
1386 1395          DTRACE_PROBE(nfss__i__exported_lock2_start);
1387 1396          for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1388 1397              ex2 = ex2->fid_hash.next) {
1389 1398                  if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1390 1399                      VN_CMP(ex2->exi_vp, vp) &&
1391 1400                      strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1392 1401                          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1393 1402                          rw_exit(&ne->exported_lock);
1394 1403                          VN_RELE(vp);
1395 1404                          if (dvp != NULL)
1396 1405                                  VN_RELE(dvp);
1397 1406                          pn_free(&lookpn);
1398 1407                          return (EEXIST);
1399 1408                  }
1400 1409          }
1401 1410          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1402 1411          rw_exit(&ne->exported_lock);
1403 1412          pn_free(&lookpn);
1404 1413  
1405 1414          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1406 1415          exi->exi_fsid = fsid;
1407 1416          exi->exi_fid = fid;
1408 1417          exi->exi_vp = vp;
1409 1418          exi->exi_count = 1;
1410 1419          exi->exi_zoneid = crgetzoneid(cr);
1411 1420          ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1412 1421          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1413 1422              VSW_VOLATILEDEV) ? 1 : 0;
1414 1423          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1415 1424          exi->exi_dvp = dvp;
1416 1425  
1417 1426          /*
1418 1427           * Initialize auth cache and auth cache lock
1419 1428           */
1420 1429          for (i = 0; i < AUTH_TABLESIZE; i++) {
1421 1430                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
1422 1431                  avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
1423 1432                      sizeof (struct auth_cache_clnt),
1424 1433                      offsetof(struct auth_cache_clnt, authc_link));
1425 1434          }
1426 1435          rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
1427 1436  
1428 1437          /*
1429 1438           * Build up the template fhandle
1430 1439           */
1431 1440          exi->exi_fh.fh_fsid = fsid;
1432 1441          if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) {
1433 1442                  error = EREMOTE;
1434 1443                  goto out1;
1435 1444          }
1436 1445          exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
1437 1446          bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
1438 1447              exi->exi_fid.fid_len);
1439 1448  
1440 1449          exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
1441 1450  
1442 1451          kex = &exi->exi_export;
1443 1452  
1444 1453          /*
1445 1454           * Load in everything, and do sanity checking
1446 1455           */
1447 1456          STRUCT_INIT(uexi, model);
1448 1457          if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi),
1449 1458              STRUCT_SIZE(uexi))) {
1450 1459                  error = EFAULT;
1451 1460                  goto out1;
1452 1461          }
1453 1462  
1454 1463          kex->ex_version = STRUCT_FGET(uexi, ex_version);
1455 1464          if (kex->ex_version != EX_CURRENT_VERSION) {
1456 1465                  error = EINVAL;
1457 1466                  cmn_err(CE_WARN,
1458 1467                      "NFS: exportfs requires export struct version 2 - got %d\n",
1459 1468                      kex->ex_version);
1460 1469                  goto out1;
1461 1470          }
1462 1471  
1463 1472          /*
1464 1473           * Must have at least one security entry
1465 1474           */
1466 1475          kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt);
1467 1476          if (kex->ex_seccnt < 1) {
1468 1477                  error = EINVAL;
1469 1478                  goto out1;
1470 1479          }
1471 1480  
1472 1481          kex->ex_path = STRUCT_FGETP(uexi, ex_path);
1473 1482          kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen);
1474 1483          kex->ex_flags = STRUCT_FGET(uexi, ex_flags);
1475 1484          kex->ex_anon = STRUCT_FGET(uexi, ex_anon);
1476 1485          kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo);
1477 1486          kex->ex_index = STRUCT_FGETP(uexi, ex_index);
1478 1487          kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer);
1479 1488          kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen);
1480 1489          kex->ex_tag = STRUCT_FGETP(uexi, ex_tag);
1481 1490          kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen);
1482 1491  
1483 1492          /*
1484 1493           * Copy the exported pathname into
1485 1494           * an appropriately sized buffer.
1486 1495           */
1487 1496          pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1488 1497          if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) {
1489 1498                  kmem_free(pathbuf, MAXPATHLEN);
1490 1499                  error = EFAULT;
1491 1500                  goto out1;
1492 1501          }
1493 1502          kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
1494 1503          bcopy(pathbuf, kex->ex_path, kex->ex_pathlen);
1495 1504          kex->ex_path[kex->ex_pathlen] = '\0';
1496 1505          kmem_free(pathbuf, MAXPATHLEN);
1497 1506  
1498 1507          /*
1499 1508           * Get the path to the logging buffer and the tag
1500 1509           */
1501 1510          if (kex->ex_flags & EX_LOG) {
1502 1511                  log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1503 1512                  if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN,
1504 1513                      &kex->ex_log_bufferlen)) {
1505 1514                          kmem_free(log_buffer, MAXPATHLEN);
1506 1515                          error = EFAULT;
1507 1516                          goto out2;
1508 1517                  }
1509 1518                  kex->ex_log_buffer =
1510 1519                      kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP);
1511 1520                  bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen);
1512 1521                  kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0';
1513 1522                  kmem_free(log_buffer, MAXPATHLEN);
1514 1523  
1515 1524                  tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1516 1525                  if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN,
1517 1526                      &kex->ex_taglen)) {
1518 1527                          kmem_free(tagbuf, MAXPATHLEN);
1519 1528                          error = EFAULT;
1520 1529                          goto out3;
1521 1530                  }
1522 1531                  kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP);
1523 1532                  bcopy(tagbuf, kex->ex_tag, kex->ex_taglen);
1524 1533                  kex->ex_tag[kex->ex_taglen] = '\0';
1525 1534                  kmem_free(tagbuf, MAXPATHLEN);
1526 1535          }
1527 1536  
1528 1537          /*
1529 1538           * Load the security information for each flavor
1530 1539           */
1531 1540          allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model);
1532 1541          sp = kmem_zalloc(allocsize, KM_SLEEP);
1533 1542          if (copyin(kex->ex_secinfo, sp, allocsize)) {
1534 1543                  kmem_free(sp, allocsize);
1535 1544                  error = EFAULT;
1536 1545                  goto out4;
1537 1546          }
1538 1547  
1539 1548          /*
1540 1549           * All of these nested structures need to be converted to
1541 1550           * the kernel native format.
1542 1551           */
1543 1552          if (model != DATAMODEL_NATIVE) {
1544 1553                  size_t allocsize2;
1545 1554                  struct secinfo *sp2;
1546 1555  
1547 1556                  allocsize2 = kex->ex_seccnt * sizeof (struct secinfo);
1548 1557                  sp2 = kmem_zalloc(allocsize2, KM_SLEEP);
1549 1558  
1550 1559                  for (i = 0; i < kex->ex_seccnt; i++) {
1551 1560                          STRUCT_HANDLE(secinfo, usi);
1552 1561  
1553 1562                          STRUCT_SET_HANDLE(usi, model,
1554 1563                              (struct secinfo *)((caddr_t)sp +
1555 1564                              (i * SIZEOF_STRUCT(secinfo, model))));
1556 1565                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_name),
1557 1566                              sp2[i].s_secinfo.sc_name, MAX_NAME_LEN);
1558 1567                          sp2[i].s_secinfo.sc_nfsnum =
1559 1568                              STRUCT_FGET(usi, s_secinfo.sc_nfsnum);
1560 1569                          sp2[i].s_secinfo.sc_rpcnum =
1561 1570                              STRUCT_FGET(usi, s_secinfo.sc_rpcnum);
1562 1571                          bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech),
1563 1572                              sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN);
1564 1573                          sp2[i].s_secinfo.sc_gss_mech_type =
1565 1574                              STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type);
1566 1575                          sp2[i].s_secinfo.sc_qop =
1567 1576                              STRUCT_FGET(usi, s_secinfo.sc_qop);
1568 1577                          sp2[i].s_secinfo.sc_service =
1569 1578                              STRUCT_FGET(usi, s_secinfo.sc_service);
1570 1579  
1571 1580                          sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
1572 1581                          sp2[i].s_window = STRUCT_FGET(usi, s_window);
1573 1582                          sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
1574 1583                          sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
1575 1584                          sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
1576 1585                  }
1577 1586                  kmem_free(sp, allocsize);
1578 1587                  sp = sp2;
1579 1588                  allocsize = allocsize2;
1580 1589          }
1581 1590  
1582 1591          kex->ex_secinfo = sp;
1583 1592  
1584 1593          /*
1585 1594           * And now copy rootnames for each individual secinfo.
1586 1595           */
1587 1596          callback = 0;
1588 1597          allocd_seccnt = 0;
1589 1598          while (allocd_seccnt < kex->ex_seccnt) {
1590 1599  
1591 1600                  exs = &sp[allocd_seccnt];
1592 1601                  if (exs->s_rootcnt > 0) {
1593 1602                          if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum,
1594 1603                              exs->s_rootcnt, &exs->s_rootnames, model)) {
1595 1604                                  error = EFAULT;
1596 1605                                  goto out5;
1597 1606                          }
1598 1607                  }
1599 1608  
1600 1609                  if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) {
1601 1610                          rpc_gss_OID mech_tmp;
1602 1611                          STRUCT_DECL(rpc_gss_OID_s, umech_tmp);
1603 1612                          caddr_t elements_tmp;
1604 1613  
1605 1614                          /* Copyin mechanism type */
1606 1615                          STRUCT_INIT(umech_tmp, model);
1607 1616                          mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP);
1608 1617                          if (copyin(exs->s_secinfo.sc_gss_mech_type,
1609 1618                              STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) {
1610 1619                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1611 1620                                  error = EFAULT;
1612 1621                                  goto out5;
1613 1622                          }
1614 1623                          mech_tmp->length = STRUCT_FGET(umech_tmp, length);
1615 1624                          mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements);
1616 1625  
1617 1626                          elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP);
1618 1627                          if (copyin(mech_tmp->elements, elements_tmp,
1619 1628                              mech_tmp->length)) {
1620 1629                                  kmem_free(elements_tmp, mech_tmp->length);
1621 1630                                  kmem_free(mech_tmp, sizeof (*mech_tmp));
1622 1631                                  error = EFAULT;
1623 1632                                  goto out5;
1624 1633                          }
1625 1634                          mech_tmp->elements = elements_tmp;
1626 1635                          exs->s_secinfo.sc_gss_mech_type = mech_tmp;
1627 1636                          allocd_seccnt++;
1628 1637  
1629 1638                          callback = 1;
1630 1639                  } else
1631 1640                          allocd_seccnt++;
1632 1641          }
1633 1642  
1634 1643          /*
1635 1644           * Init the secinfo reference count and mark these flavors
1636 1645           * explicitly exported flavors.
1637 1646           */
1638 1647          for (i = 0; i < kex->ex_seccnt; i++) {
1639 1648                  kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED;
1640 1649                  kex->ex_secinfo[i].s_refcnt = 1;
1641 1650          }
1642 1651  
1643 1652          /*
1644 1653           *  Set up rpcsec_gss callback routine entry if any.
1645 1654           */
1646 1655          if (callback) {
1647 1656                  cb.callback = rfs_gsscallback;
1648 1657                  cb.program = NFS_ACL_PROGRAM;
1649 1658                  for (cb.version = NFS_ACL_VERSMIN;
1650 1659                      cb.version <= NFS_ACL_VERSMAX; cb.version++) {
1651 1660                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1652 1661                              (void *)&cb);
1653 1662                  }
1654 1663  
1655 1664                  cb.program = NFS_PROGRAM;
1656 1665                  for (cb.version = NFS_VERSMIN;
1657 1666                      cb.version <= NFS_VERSMAX; cb.version++) {
1658 1667                          (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK,
1659 1668                              (void *)&cb);
1660 1669                  }
1661 1670          }
1662 1671  
1663 1672          /*
1664 1673           * Check the index flag. Do this here to avoid holding the
1665 1674           * lock while dealing with the index option (as we do with
1666 1675           * the public option).
1667 1676           */
1668 1677          if (kex->ex_flags & EX_INDEX) {
1669 1678                  if (!kex->ex_index) {   /* sanity check */
1670 1679                          error = EINVAL;
1671 1680                          goto out5;
1672 1681                  }
1673 1682                  if (error = loadindex(kex))
1674 1683                          goto out5;
1675 1684          }
1676 1685  
1677 1686          if (kex->ex_flags & EX_LOG) {
1678 1687                  if (error = nfslog_setup(exi))
1679 1688                          goto out6;
1680 1689          }
1681 1690  
1682 1691          /*
1683 1692           * Insert the new entry at the front of the export list
1684 1693           */
1685 1694          rw_enter(&ne->exported_lock, RW_WRITER);
1686 1695          DTRACE_PROBE(nfss__i__exported_lock3_start);
1687 1696  
1688 1697          export_link(ne, exi);
1689 1698  
1690 1699          /*
1691 1700           * Check the rest of the list for an old entry for the fs.
1692 1701           * If one is found then unlink it, wait until this is the
1693 1702           * only reference and then free it.
1694 1703           */
1695 1704          for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1696 1705                  if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
1697 1706                          mutex_enter(&nfs_exi_id_lock);
1698 1707                          avl_remove(&exi_id_tree, ex);
1699 1708                          mutex_exit(&nfs_exi_id_lock);
1700 1709                          export_unlink(ne, ex);
1701 1710                          break;
1702 1711                  }
1703 1712          }
1704 1713  
1705 1714          /*
1706 1715           * If the public filehandle is pointing at the
1707 1716           * old entry, then point it back at the root.
1708 1717           */
1709 1718          if (ex != NULL && ex == ne->exi_public)
1710 1719                  ne->exi_public = ne->exi_root;
1711 1720  
1712 1721          /*
1713 1722           * If the public flag is on, make the global exi_public
1714 1723           * point to this entry and turn off the public bit so that
1715 1724           * we can distinguish it from the place holder export.
1716 1725           */
1717 1726          if (kex->ex_flags & EX_PUBLIC) {
1718 1727                  ne->exi_public = exi;
1719 1728                  kex->ex_flags &= ~EX_PUBLIC;
1720 1729          }
1721 1730  
1722 1731  #ifdef VOLATILE_FH_TEST
1723 1732          /*
1724 1733           * Set up the volatile_id value if volatile on share.
1725 1734           * The list of volatile renamed filehandles is always destroyed,
1726 1735           * if the fs was reshared.
1727 1736           */
1728 1737          if (kex->ex_flags & EX_VOLFH)
1729 1738                  exi->exi_volatile_id = gethrestime_sec();
1730 1739  
1731 1740          mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL);
1732 1741  #endif /* VOLATILE_FH_TEST */
1733 1742  
1734 1743          /*
1735 1744           * If this is a new export, then climb up
1736 1745           * the tree and check if any pseudo exports
1737 1746           * need to be created to provide a path for
1738 1747           * NFS v4 clients.
1739 1748           */
1740 1749          if (ex == NULL) {
1741 1750                  error = treeclimb_export(exi);
1742 1751                  if (error)
1743 1752                          goto out7;
1744 1753          } else {
1745 1754                  /* If it's a re-export update namespace tree */
1746 1755                  exi->exi_tree = ex->exi_tree;
1747 1756                  exi->exi_tree->tree_exi = exi;
1748 1757  
1749 1758                  /* Update the change timestamp */
1750 1759                  tree_update_change(ne, exi->exi_tree, NULL);
1751 1760          }
1752 1761  
1753 1762          /*
1754 1763           * build a unique flavor list from the flavors specified
1755 1764           * in the share cmd.  unique means that each flavor only
1756 1765           * appears once in the secinfo list -- no duplicates allowed.
1757 1766           */
1758 1767          newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1759 1768  
1760 1769          srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1761 1770  
1762 1771          /*
1763 1772           * If re-sharing an old export entry, update the secinfo data
1764 1773           * depending on if the old entry is a pseudo node or not.
1765 1774           */
1766 1775          if (ex != NULL) {
1767 1776                  oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1768 1777                  if (PSEUDO(ex)) {
1769 1778                          /*
1770 1779                           * The dir being shared is a pseudo export root (which
1771 1780                           * will be transformed into a real export root).  The
1772 1781                           * flavor(s) of the new share were propagated to the
1773 1782                           * ancestors by srv_secinfo_treeclimb() above.  Now
1774 1783                           * transfer the implicit flavor refs from the old
1775 1784                           * pseudo exprot root to the new (real) export root.
1776 1785                           */
1777 1786                          srv_secinfo_add(&exi->exi_export.ex_secinfo,
1778 1787                              &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1779 1788                  } else {
1780 1789                          /*
1781 1790                           * First transfer implicit flavor refs to new export.
1782 1791                           * Remove old flavor refs last.
1783 1792                           */
1784 1793                          srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1785 1794                          srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1786 1795                  }
1787 1796          }
1788 1797  
1789 1798          /*
1790 1799           * If it's a re-export and the old entry has a pseudonode list,
1791 1800           * transfer it to the new export.
1792 1801           */
1793 1802          if (ex != NULL && (ex->exi_visible != NULL)) {
1794 1803                  exi->exi_visible = ex->exi_visible;
1795 1804                  ex->exi_visible = NULL;
1796 1805          }
1797 1806  
1798 1807          /*
1799 1808           * Initialize exi_id and exi_kstats
1800 1809           */
1801 1810          if (ex != NULL) {
1802 1811                  exi->exi_id = ex->exi_id;
1803 1812          } else {
1804 1813                  mutex_enter(&nfs_exi_id_lock);
1805 1814                  exi->exi_id = exi_id_get_next();
1806 1815                  mutex_exit(&nfs_exi_id_lock);
1807 1816          }
1808 1817          mutex_enter(&nfs_exi_id_lock);
1809 1818          avl_add(&exi_id_tree, exi);
1810 1819          mutex_exit(&nfs_exi_id_lock);
1811 1820  
1812 1821          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1813 1822          rw_exit(&ne->exported_lock);
1814 1823  
1815 1824          if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1816 1825                  /*
1817 1826                   * Log share operation to this buffer only.
1818 1827                   */
1819 1828                  nfslog_share_record(exi, cr);
1820 1829          }
1821 1830  
1822 1831          if (ex != NULL)
1823 1832                  exi_rele(ex);
1824 1833  
1825 1834          return (0);
1826 1835  
1827 1836  out7:
1828 1837          /* Unlink the new export in exptable. */
1829 1838          export_unlink(ne, exi);
1830 1839          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1831 1840          rw_exit(&ne->exported_lock);
1832 1841  out6:
1833 1842          if (kex->ex_flags & EX_INDEX)
1834 1843                  kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1835 1844  out5:
1836 1845          /* free partially completed allocation */
1837 1846          while (--allocd_seccnt >= 0) {
1838 1847                  exs = &kex->ex_secinfo[allocd_seccnt];
1839 1848                  srv_secinfo_entry_free(exs);
1840 1849          }
1841 1850  
1842 1851          if (kex->ex_secinfo) {
1843 1852                  kmem_free(kex->ex_secinfo,
1844 1853                      kex->ex_seccnt * sizeof (struct secinfo));
1845 1854          }
1846 1855  
1847 1856  out4:
1848 1857          if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL)
1849 1858                  kmem_free(kex->ex_tag, kex->ex_taglen + 1);
1850 1859  out3:
1851 1860          if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL)
1852 1861                  kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1);
1853 1862  out2:
1854 1863          kmem_free(kex->ex_path, kex->ex_pathlen + 1);
1855 1864  out1:
1856 1865          VN_RELE(vp);
1857 1866          if (dvp != NULL)
1858 1867                  VN_RELE(dvp);
1859 1868          mutex_destroy(&exi->exi_lock);
1860 1869          rw_destroy(&exi->exi_cache_lock);
1861 1870          for (i = 0; i < AUTH_TABLESIZE; i++) {
1862 1871                  avl_destroy(exi->exi_cache[i]);
1863 1872                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
1864 1873          }
1865 1874  
1866 1875          kmem_free(exi, sizeof (*exi));
1867 1876  
1868 1877          return (error);
1869 1878  }
1870 1879  
1871 1880  /*
1872 1881   * Remove the exportinfo from the export list
1873 1882   */
1874 1883  void
1875 1884  export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1876 1885  {
1877 1886          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1878 1887  
  
    | 
      ↓ open down ↓ | 
    579 lines elided | 
    
      ↑ open up ↑ | 
  
1879 1888          exp_hash_unlink(exi, fid_hash);
1880 1889          exp_hash_unlink(exi, path_hash);
1881 1890          ASSERT3P(exi->exi_ne, ==, ne);
1882 1891          exi->exi_ne = NULL;
1883 1892  }
1884 1893  
1885 1894  /*
1886 1895   * Unexport an exported filesystem
1887 1896   */
1888 1897  static int
1889      -unexport(nfs_export_t *ne, struct exportinfo *exi)
     1898 +unexport(nfs_export_t *ne, struct exportinfo *exi, cred_t *cr)
1890 1899  {
1891 1900          struct secinfo cursec[MAX_FLAVORS];
1892 1901          int curcnt;
1893 1902  
1894 1903          rw_enter(&ne->exported_lock, RW_WRITER);
1895 1904  
1896 1905          /* Check if exi is still linked in the export table */
1897 1906          if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1898 1907                  rw_exit(&ne->exported_lock);
1899 1908                  return (EINVAL);
1900 1909          }
1901 1910  
1902 1911          mutex_enter(&nfs_exi_id_lock);
1903 1912          avl_remove(&exi_id_tree, exi);
1904 1913          mutex_exit(&nfs_exi_id_lock);
1905 1914          export_unlink(ne, exi);
1906 1915  
1907 1916          /*
1908 1917           * Remove security flavors before treeclimb_unexport() is called
1909 1918           * because srv_secinfo_treeclimb needs the namespace tree
1910 1919           */
1911 1920          curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1912 1921          srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1913 1922  
1914 1923          /*
1915 1924           * If there's a visible list, then need to leave
1916 1925           * a pseudo export here to retain the visible list
1917 1926           * for paths to exports below.
1918 1927           */
1919 1928          if (exi->exi_visible != NULL) {
1920 1929                  struct exportinfo *newexi;
1921 1930  
1922 1931                  newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1923 1932                      exi->exi_visible, &exi->exi_export);
1924 1933                  exi->exi_visible = NULL;
1925 1934  
1926 1935                  /* interconnect the existing treenode with the new exportinfo */
1927 1936                  newexi->exi_tree = exi->exi_tree;
1928 1937                  newexi->exi_tree->tree_exi = newexi;
1929 1938  
1930 1939                  /* Update the change timestamp */
1931 1940                  tree_update_change(ne, exi->exi_tree, NULL);
1932 1941          } else {
1933 1942                  treeclimb_unexport(ne, exi);
1934 1943          }
1935 1944  
1936 1945          rw_exit(&ne->exported_lock);
1937 1946  
1938 1947          /*
1939 1948           * Need to call into the NFSv4 server and release all data
1940 1949           * held on this particular export.  This is important since
1941 1950           * the v4 server may be holding file locks or vnodes under
1942 1951           * this export.
1943 1952           */
1944 1953          rfs4_clean_state_exi(ne, exi);
1945 1954  
1946 1955          /*
  
    | 
      ↓ open down ↓ | 
    47 lines elided | 
    
      ↑ open up ↑ | 
  
1947 1956           * Notify the lock manager that the filesystem is being
1948 1957           * unexported.
1949 1958           */
1950 1959          lm_unexport(exi);
1951 1960  
1952 1961          /*
1953 1962           * If this was a public export, restore
1954 1963           * the public filehandle to the root.
1955 1964           */
1956 1965  
1957      -        /*
1958      -         * XXX KEBE ASKS --> Should CRED() instead be
1959      -         * exi->exi_zone->zone_kcred?
1960      -         */
1961 1966          if (exi == ne->exi_public) {
1962 1967                  ne->exi_public = ne->exi_root;
1963 1968  
1964      -                nfslog_share_record(ne->exi_public, CRED());
     1969 +                nfslog_share_record(ne->exi_public, cr);
1965 1970          }
1966 1971  
1967 1972          if (exi->exi_export.ex_flags & EX_LOG)
1968      -                nfslog_unshare_record(exi, CRED());
     1973 +                nfslog_unshare_record(exi, cr);
1969 1974  
1970 1975          exi_rele(exi);
1971 1976          return (0);
1972 1977  }
1973 1978  
1974 1979  /*
1975 1980   * Get file handle system call.
1976 1981   * Takes file name and returns a file handle for it.
1977 1982   * Credentials must be verified before calling.
1978 1983   */
1979 1984  int
1980 1985  nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
1981 1986  {
1982 1987          nfs_fh3 fh;
1983 1988          char buf[NFS3_MAXFHSIZE];
1984 1989          char *logptr, logbuf[NFS3_MAXFHSIZE];
1985 1990          int l = NFS3_MAXFHSIZE;
1986 1991          vnode_t *vp;
1987 1992          vnode_t *dvp;
1988 1993          struct exportinfo *exi;
1989 1994          int error;
1990 1995          int vers;
1991 1996          STRUCT_HANDLE(nfs_getfh_args, uap);
1992 1997  
1993 1998  #ifdef lint
1994 1999          model = model;          /* STRUCT macros don't always use it */
1995 2000  #endif
1996 2001  
1997 2002          STRUCT_SET_HANDLE(uap, model, args);
1998 2003  
1999 2004          error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
2000 2005              FOLLOW, &dvp, &vp);
2001 2006          if (error == EINVAL) {
2002 2007                  /*
2003 2008                   * if fname resolves to / we get EINVAL error
2004 2009                   * since we wanted the parent vnode. Try again
2005 2010                   * with NULL dvp.
2006 2011                   */
2007 2012                  error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE,
2008 2013                      FOLLOW, NULL, &vp);
2009 2014                  dvp = NULL;
2010 2015          }
2011 2016          if (!error && vp == NULL) {
2012 2017                  /*
2013 2018                   * Last component of fname not found
2014 2019                   */
2015 2020                  if (dvp != NULL) {
2016 2021                          VN_RELE(dvp);
2017 2022                  }
2018 2023                  error = ENOENT;
2019 2024          }
2020 2025          if (error)
2021 2026                  return (error);
2022 2027  
2023 2028          /*
2024 2029           * 'vp' may be an AUTOFS node, so we perform a
2025 2030           * VOP_ACCESS() to trigger the mount of the
2026 2031           * intended filesystem, so we can share the intended
2027 2032           * filesystem instead of the AUTOFS filesystem.
2028 2033           */
2029 2034          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
2030 2035  
2031 2036          /*
2032 2037           * We're interested in the top most filesystem.
2033 2038           * This is specially important when uap->dname is a trigger
2034 2039           * AUTOFS node, since we're really interested in sharing the
2035 2040           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
2036 2041           * call not the AUTOFS node itself.
2037 2042           */
2038 2043          if (vn_mountedvfs(vp) != NULL) {
2039 2044                  if (error = traverse(&vp)) {
2040 2045                          VN_RELE(vp);
2041 2046                          if (dvp != NULL)
2042 2047                                  VN_RELE(dvp);
2043 2048                          return (error);
2044 2049                  }
2045 2050          }
2046 2051  
2047 2052          vers = STRUCT_FGET(uap, vers);
2048 2053          exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE);
2049 2054          if (!error) {
2050 2055                  if (vers == NFS_VERSION) {
2051 2056                          error = makefh((fhandle_t *)buf, vp, exi);
2052 2057                          l = NFS_FHSIZE;
2053 2058                          logptr = buf;
2054 2059                  } else if (vers == NFS_V3) {
2055 2060                          int i, sz, pad;
2056 2061  
2057 2062                          error = makefh3(&fh, vp, exi);
2058 2063                          l = RNDUP(fh.fh3_length);
2059 2064                          if (!error && (l > sizeof (fhandle3_t)))
2060 2065                                  error = EREMOTE;
2061 2066                          logptr = logbuf;
2062 2067                          if (!error) {
2063 2068                                  i = 0;
2064 2069                                  sz = sizeof (fsid_t);
2065 2070                                  bcopy(&fh.fh3_fsid, &buf[i], sz);
2066 2071                                  i += sz;
2067 2072  
2068 2073                                  /*
2069 2074                                   * For backwards compatibility, the
2070 2075                                   * fid length may be less than
2071 2076                                   * NFS_FHMAXDATA, but it was always
2072 2077                                   * encoded as NFS_FHMAXDATA bytes.
2073 2078                                   */
2074 2079  
2075 2080                                  sz = sizeof (ushort_t);
2076 2081                                  bcopy(&fh.fh3_len, &buf[i], sz);
2077 2082                                  i += sz;
2078 2083                                  bcopy(fh.fh3_data, &buf[i], fh.fh3_len);
2079 2084                                  i += fh.fh3_len;
2080 2085                                  pad = (NFS_FHMAXDATA - fh.fh3_len);
2081 2086                                  if (pad > 0) {
2082 2087                                          bzero(&buf[i], pad);
2083 2088                                          i += pad;
2084 2089                                          l += pad;
2085 2090                                  }
2086 2091  
2087 2092                                  sz = sizeof (ushort_t);
2088 2093                                  bcopy(&fh.fh3_xlen, &buf[i], sz);
2089 2094                                  i += sz;
2090 2095                                  bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen);
2091 2096                                  i += fh.fh3_xlen;
2092 2097                                  pad = (NFS_FHMAXDATA - fh.fh3_xlen);
2093 2098                                  if (pad > 0) {
2094 2099                                          bzero(&buf[i], pad);
2095 2100                                          i += pad;
2096 2101                                          l += pad;
2097 2102                                  }
2098 2103                          }
2099 2104                          /*
2100 2105                           * If we need to do NFS logging, the filehandle
2101 2106                           * must be downsized to 32 bytes.
2102 2107                           */
2103 2108                          if (!error && exi->exi_export.ex_flags & EX_LOG) {
2104 2109                                  i = 0;
2105 2110                                  sz = sizeof (fsid_t);
2106 2111                                  bcopy(&fh.fh3_fsid, &logbuf[i], sz);
2107 2112                                  i += sz;
2108 2113                                  sz = sizeof (ushort_t);
2109 2114                                  bcopy(&fh.fh3_len, &logbuf[i], sz);
2110 2115                                  i += sz;
2111 2116                                  sz = NFS_FHMAXDATA;
2112 2117                                  bcopy(fh.fh3_data, &logbuf[i], sz);
2113 2118                                  i += sz;
2114 2119                                  sz = sizeof (ushort_t);
2115 2120                                  bcopy(&fh.fh3_xlen, &logbuf[i], sz);
2116 2121                                  i += sz;
2117 2122                                  sz = NFS_FHMAXDATA;
2118 2123                                  bcopy(fh.fh3_xdata, &logbuf[i], sz);
2119 2124                                  i += sz;
2120 2125                          }
2121 2126                  }
2122 2127                  if (!error && exi->exi_export.ex_flags & EX_LOG) {
2123 2128                          nfslog_getfh(exi, (fhandle_t *)logptr,
2124 2129                              STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
2125 2130                  }
2126 2131                  exi_rele(exi);
2127 2132                  if (!error) {
2128 2133                          if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
2129 2134                                  error = EFAULT;
2130 2135                          if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
2131 2136                                  error = EFAULT;
2132 2137                  }
2133 2138          }
2134 2139          VN_RELE(vp);
2135 2140          if (dvp != NULL) {
2136 2141                  VN_RELE(dvp);
2137 2142          }
2138 2143          return (error);
2139 2144  }
2140 2145  
2141 2146  /*
2142 2147   * Strategy: if vp is in the export list, then
2143 2148   * return the associated file handle. Otherwise, ".."
2144 2149   * once up the vp and try again, until the root of the
2145 2150   * filesystem is reached.
2146 2151   */
2147 2152  struct   exportinfo *
2148 2153  nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk,
2149 2154      int *err, bool_t v4srv)
2150 2155  {
2151 2156          fid_t fid;
2152 2157          int error;
2153 2158          struct exportinfo *exi;
2154 2159  
2155 2160          ASSERT(vp);
2156 2161          VN_HOLD(vp);
2157 2162          if (dvp != NULL) {
2158 2163                  VN_HOLD(dvp);
2159 2164          }
2160 2165          if (walk != NULL)
2161 2166                  *walk = 0;
2162 2167  
2163 2168          for (;;) {
2164 2169                  bzero(&fid, sizeof (fid));
2165 2170                  fid.fid_len = MAXFIDSZ;
2166 2171                  error = vop_fid_pseudo(vp, &fid);
2167 2172                  if (error) {
2168 2173                          /*
2169 2174                           * If vop_fid_pseudo returns ENOSPC then the fid
2170 2175                           * supplied is too small. For now we simply
2171 2176                           * return EREMOTE.
2172 2177                           */
2173 2178                          if (error == ENOSPC)
2174 2179                                  error = EREMOTE;
2175 2180                          break;
2176 2181                  }
2177 2182  
2178 2183                  if (v4srv)
2179 2184                          exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2180 2185                  else
2181 2186                          exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2182 2187  
2183 2188                  if (exi != NULL) {
2184 2189                          /*
2185 2190                           * Found the export info
2186 2191                           */
2187 2192                          break;
2188 2193                  }
2189 2194  
2190 2195                  /*
2191 2196                   * We have just failed finding a matching export.
2192 2197                   * If we're at the root of this filesystem, then
2193 2198                   * it's time to stop (with failure).
2194 2199                   */
2195 2200                  ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2196 2201                  if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2197 2202                          error = EINVAL;
2198 2203                          break;
2199 2204                  }
2200 2205  
2201 2206                  if (walk != NULL)
2202 2207                          (*walk)++;
2203 2208  
2204 2209                  /*
2205 2210                   * Now, do a ".." up vp. If dvp is supplied, use it,
2206 2211                   * otherwise, look it up.
2207 2212                   */
2208 2213                  if (dvp == NULL) {
2209 2214                          error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2210 2215                              NULL, NULL, NULL);
2211 2216                          if (error)
2212 2217                                  break;
2213 2218                  }
2214 2219                  VN_RELE(vp);
2215 2220                  vp = dvp;
2216 2221                  dvp = NULL;
2217 2222          }
2218 2223          VN_RELE(vp);
2219 2224          if (dvp != NULL) {
2220 2225                  VN_RELE(dvp);
2221 2226          }
2222 2227          if (error != 0) {
2223 2228                  if (err != NULL)
2224 2229                          *err = error;
2225 2230                  return (NULL);
2226 2231          }
2227 2232          return (exi);
2228 2233  }
2229 2234  
2230 2235  int
2231 2236  chk_clnt_sec(exportinfo_t *exi, struct svc_req *req)
2232 2237  {
2233 2238          int i, nfsflavor;
2234 2239          struct secinfo *sp;
2235 2240  
2236 2241          /*
2237 2242           *  Get the nfs flavor number from xprt.
2238 2243           */
2239 2244          nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie;
2240 2245  
2241 2246          sp = exi->exi_export.ex_secinfo;
2242 2247          for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
2243 2248                  if ((nfsflavor == sp[i].s_secinfo.sc_nfsnum) &&
2244 2249                      SEC_REF_EXPORTED(sp + i))
2245 2250                          return (TRUE);
2246 2251          }
2247 2252          return (FALSE);
2248 2253  }
2249 2254  
2250 2255  /*
2251 2256   * Make an fhandle from a vnode
2252 2257   */
2253 2258  int
2254 2259  makefh(fhandle_t *fh, vnode_t *vp, exportinfo_t *exi)
2255 2260  {
2256 2261          int error;
2257 2262  
2258 2263          *fh = exi->exi_fh;      /* struct copy */
2259 2264  
2260 2265          error = VOP_FID(vp, (fid_t *)&fh->fh_len, NULL);
2261 2266          if (error) {
2262 2267                  /*
2263 2268                   * Should be something other than EREMOTE
2264 2269                   */
2265 2270                  return (EREMOTE);
2266 2271          }
2267 2272          return (0);
2268 2273  }
2269 2274  
2270 2275  /*
2271 2276   * This routine makes an overloaded V2 fhandle which contains
2272 2277   * sec modes.
2273 2278   *
2274 2279   * Note that the first four octets contain the length octet,
2275 2280   * the status octet, and two padded octets to make them XDR
2276 2281   * four-octet aligned.
2277 2282   *
2278 2283   *   1   2   3   4                                          32
2279 2284   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2280 2285   * | l | s |   |   |     sec_1     |...|     sec_n     |...|   |
2281 2286   * +---+---+---+---+---+---+---+---+   +---+---+---+---+   +---+
2282 2287   *
2283 2288   * where
2284 2289   *
2285 2290   *   the status octet s indicates whether there are more security
2286 2291   *   flavors (1 means yes, 0 means no) that require the client to
2287 2292   *   perform another 0x81 LOOKUP to get them,
2288 2293   *
2289 2294   *   the length octet l is the length describing the number of
2290 2295   *   valid octets that follow.  (l = 4 * n, where n is the number
2291 2296   *   of security flavors sent in the current overloaded filehandle.)
2292 2297   *
2293 2298   *   sec_index should always be in the inclusive range: [1 - ex_seccnt],
2294 2299   *   and it tells server where to start within the secinfo array.
2295 2300   *   Usually it will always be 1; however, if more flavors are used
2296 2301   *   for the public export than can be encoded in the overloaded FH
2297 2302   *   (7 for NFS2), subsequent SNEGO MCLs will have a larger index
2298 2303   *   so the server will pick up where it left off from the previous
2299 2304   *   MCL reply.
2300 2305   *
2301 2306   *   With NFS4 support, implicitly allowed flavors are also in
2302 2307   *   the secinfo array; however, they should not be returned in
2303 2308   *   SNEGO MCL replies.
2304 2309   */
2305 2310  int
2306 2311  makefh_ol(fhandle_t *fh, exportinfo_t *exi, uint_t sec_index)
2307 2312  {
2308 2313          secinfo_t sec[MAX_FLAVORS];
2309 2314          int totalcnt, i, *ipt, cnt, seccnt, secidx, fh_max_cnt;
2310 2315          char *c;
2311 2316  
2312 2317          if (fh == NULL || exi == NULL || sec_index < 1)
2313 2318                  return (EREMOTE);
2314 2319  
2315 2320          /*
2316 2321           * WebNFS clients need to know the unique set of explicitly
2317 2322           * shared flavors in used for the public export. When
2318 2323           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2319 2324           * shared flavors are included in the list.
2320 2325           */
2321 2326          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2322 2327          if (sec_index > seccnt)
2323 2328                  return (EREMOTE);
2324 2329  
2325 2330          fh_max_cnt = (NFS_FHSIZE / sizeof (int)) - 1;
2326 2331          totalcnt = seccnt - sec_index + 1;
2327 2332          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2328 2333  
2329 2334          c = (char *)fh;
2330 2335          /*
2331 2336           * Encode the length octet representing the number of
2332 2337           * security flavors (in bytes) in this overloaded fh.
2333 2338           */
2334 2339          *c = cnt * sizeof (int);
2335 2340  
2336 2341          /*
2337 2342           * Encode the status octet that indicates whether there
2338 2343           * are more security flavors the client needs to get.
2339 2344           */
2340 2345          *(c + 1) = totalcnt > fh_max_cnt;
2341 2346  
2342 2347          /*
2343 2348           * put security flavors in the overloaded fh
2344 2349           */
2345 2350          ipt = (int *)(c + sizeof (int32_t));
2346 2351          secidx = sec_index - 1;
2347 2352          for (i = 0; i < cnt; i++) {
2348 2353                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2349 2354          }
2350 2355          return (0);
2351 2356  }
2352 2357  
2353 2358  /*
2354 2359   * Make an nfs_fh3 from a vnode
2355 2360   */
2356 2361  int
2357 2362  makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi)
2358 2363  {
2359 2364          int error;
2360 2365          fid_t fid;
2361 2366  
2362 2367          bzero(&fid, sizeof (fid));
2363 2368          fid.fid_len = sizeof (fh->fh3_data);
2364 2369          error = VOP_FID(vp, &fid, NULL);
2365 2370          if (error)
2366 2371                  return (EREMOTE);
2367 2372  
2368 2373          bzero(fh, sizeof (nfs_fh3));
2369 2374          fh->fh3_fsid = exi->exi_fsid;
2370 2375          fh->fh3_len = fid.fid_len;
2371 2376          bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len);
2372 2377  
2373 2378          fh->fh3_xlen = exi->exi_fid.fid_len;
2374 2379          ASSERT(fh->fh3_xlen <= sizeof (fh->fh3_xdata));
2375 2380          bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen);
2376 2381  
2377 2382          fh->fh3_length = sizeof (fh->fh3_fsid)
2378 2383              + sizeof (fh->fh3_len) + fh->fh3_len
2379 2384              + sizeof (fh->fh3_xlen) + fh->fh3_xlen;
2380 2385          fh->fh3_flags = 0;
2381 2386  
2382 2387          return (0);
2383 2388  }
2384 2389  
2385 2390  /*
2386 2391   * This routine makes an overloaded V3 fhandle which contains
2387 2392   * sec modes.
2388 2393   *
2389 2394   *  1        4
2390 2395   * +--+--+--+--+
2391 2396   * |    len    |
2392 2397   * +--+--+--+--+
2393 2398   *                                               up to 64
2394 2399   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2395 2400   * |s |  |  |  |   sec_1   |   sec_2   | ... |   sec_n   |
2396 2401   * +--+--+--+--+--+--+--+--+--+--+--+--+     +--+--+--+--+
2397 2402   *
2398 2403   * len = 4 * (n+1), where n is the number of security flavors
2399 2404   * sent in the current overloaded filehandle.
2400 2405   *
2401 2406   * the status octet s indicates whether there are more security
2402 2407   * mechanisms (1 means yes, 0 means no) that require the client
2403 2408   * to perform another 0x81 LOOKUP to get them.
2404 2409   *
2405 2410   * Three octets are padded after the status octet.
2406 2411   */
2407 2412  int
2408 2413  makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index)
2409 2414  {
2410 2415          secinfo_t sec[MAX_FLAVORS];
2411 2416          int totalcnt, cnt, *ipt, i, seccnt, fh_max_cnt, secidx;
2412 2417          char *c;
2413 2418  
2414 2419          if (fh == NULL || exi == NULL || sec_index < 1)
2415 2420                  return (EREMOTE);
2416 2421  
2417 2422          /*
2418 2423           * WebNFS clients need to know the unique set of explicitly
2419 2424           * shared flavors in used for the public export. When
2420 2425           * "TRUE" is passed to build_seclist_nodups(), only explicitly
2421 2426           * shared flavors are included in the list.
2422 2427           */
2423 2428          seccnt = build_seclist_nodups(&exi->exi_export, sec, TRUE);
2424 2429  
2425 2430          if (sec_index > seccnt)
2426 2431                  return (EREMOTE);
2427 2432  
2428 2433          fh_max_cnt = (NFS3_FHSIZE / sizeof (int)) - 1;
2429 2434          totalcnt = seccnt - sec_index + 1;
2430 2435          cnt = totalcnt > fh_max_cnt ? fh_max_cnt : totalcnt;
2431 2436  
2432 2437          /*
2433 2438           * Place the length in fh3_length representing the number
2434 2439           * of security flavors (in bytes) in this overloaded fh.
2435 2440           */
2436 2441          fh->fh3_flags = FH_WEBNFS;
2437 2442          fh->fh3_length = (cnt+1) * sizeof (int32_t);
2438 2443  
2439 2444          c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i;
2440 2445          /*
2441 2446           * Encode the status octet that indicates whether there
2442 2447           * are more security flavors the client needs to get.
2443 2448           */
2444 2449          *c = totalcnt > fh_max_cnt;
2445 2450  
2446 2451          /*
2447 2452           * put security flavors in the overloaded fh
2448 2453           */
2449 2454          secidx = sec_index - 1;
2450 2455          ipt = (int *)(c + sizeof (int32_t));
2451 2456          for (i = 0; i < cnt; i++) {
2452 2457                  ipt[i] = htonl(sec[i + secidx].s_secinfo.sc_nfsnum);
2453 2458          }
2454 2459          return (0);
2455 2460  }
2456 2461  
2457 2462  /*
2458 2463   * Make an nfs_fh4 from a vnode
2459 2464   */
2460 2465  int
2461 2466  makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi)
2462 2467  {
2463 2468          int error;
2464 2469          nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2465 2470          fid_t fid;
2466 2471  
2467 2472          bzero(&fid, sizeof (fid));
2468 2473          fid.fid_len = MAXFIDSZ;
2469 2474          /*
2470 2475           * vop_fid_pseudo() is used to set up NFSv4 namespace, so
2471 2476           * use vop_fid_pseudo() here to get the fid instead of VOP_FID.
2472 2477           */
2473 2478          error = vop_fid_pseudo(vp, &fid);
2474 2479          if (error)
2475 2480                  return (error);
2476 2481  
2477 2482          fh->nfs_fh4_len = NFS_FH4_LEN;
2478 2483  
2479 2484          fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid;
2480 2485          fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen;
2481 2486  
2482 2487          bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data));
2483 2488          bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata));
2484 2489          ASSERT(exi->exi_fh.fh_xlen <= sizeof (fh_fmtp->fh4_i.fhx_xdata));
2485 2490          bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata,
2486 2491              exi->exi_fh.fh_xlen);
2487 2492  
2488 2493          fh_fmtp->fh4_len = fid.fid_len;
2489 2494          ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data));
2490 2495          bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len);
2491 2496          fh_fmtp->fh4_flag = 0;
2492 2497  
2493 2498  #ifdef VOLATILE_FH_TEST
2494 2499          /*
2495 2500           * XXX (temporary?)
2496 2501           * Use the rnode volatile_id value to add volatility to the fh.
2497 2502           *
2498 2503           * For testing purposes there are currently two scenarios, based
2499 2504           * on whether the filesystem was shared with "volatile_fh"
2500 2505           * or "expire_on_rename". In the first case, use the value of
2501 2506           * export struct share_time as the volatile_id. In the second
2502 2507           * case use the vnode volatile_id value (which is set to the
2503 2508           * time in which the file was renamed).
2504 2509           *
2505 2510           * Note that the above are temporary constructs for testing only
2506 2511           * XXX
2507 2512           */
2508 2513          if (exi->exi_export.ex_flags & EX_VOLRNM) {
2509 2514                  fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh);
2510 2515          } else if (exi->exi_export.ex_flags & EX_VOLFH) {
2511 2516                  fh_fmtp->fh4_volatile_id = exi->exi_volatile_id;
2512 2517          } else {
2513 2518                  fh_fmtp->fh4_volatile_id = 0;
2514 2519          }
2515 2520  #endif /* VOLATILE_FH_TEST */
2516 2521  
2517 2522          return (0);
2518 2523  }
2519 2524  
2520 2525  /*
2521 2526   * Convert an fhandle into a vnode.
2522 2527   * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
2523 2528   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2524 2529   * are done with it.
2525 2530   */
2526 2531  vnode_t *
2527 2532  nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi)
2528 2533  {
2529 2534          vfs_t *vfsp;
2530 2535          vnode_t *vp;
2531 2536          int error;
2532 2537          fid_t *fidp;
2533 2538  
2534 2539          TRACE_0(TR_FAC_NFS, TR_FHTOVP_START,
2535 2540              "fhtovp_start");
2536 2541  
2537 2542          if (exi == NULL) {
2538 2543                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2539 2544                      "fhtovp_end:(%S)", "exi NULL");
2540 2545                  return (NULL);  /* not exported */
2541 2546          }
2542 2547  
2543 2548          ASSERT(exi->exi_vp != NULL);
2544 2549  
2545 2550          if (PUBLIC_FH2(fh)) {
2546 2551                  if (exi->exi_export.ex_flags & EX_PUBLIC) {
2547 2552                          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2548 2553                              "fhtovp_end:(%S)", "root not exported");
2549 2554                          return (NULL);
2550 2555                  }
2551 2556                  vp = exi->exi_vp;
2552 2557                  VN_HOLD(vp);
2553 2558                  return (vp);
2554 2559          }
2555 2560  
2556 2561          vfsp = exi->exi_vp->v_vfsp;
2557 2562          ASSERT(vfsp != NULL);
2558 2563          fidp = (fid_t *)&fh->fh_len;
2559 2564  
2560 2565          error = VFS_VGET(vfsp, &vp, fidp);
2561 2566          if (error || vp == NULL) {
2562 2567                  TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2563 2568                      "fhtovp_end:(%S)", "VFS_GET failed or vp NULL");
2564 2569                  return (NULL);
2565 2570          }
2566 2571          TRACE_1(TR_FAC_NFS, TR_FHTOVP_END,
2567 2572              "fhtovp_end:(%S)", "end");
2568 2573          return (vp);
2569 2574  }
2570 2575  
2571 2576  /*
2572 2577   * Convert an nfs_fh3 into a vnode.
2573 2578   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2574 2579   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2575 2580   * are done with it.
2576 2581   */
2577 2582  vnode_t *
2578 2583  nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi)
2579 2584  {
2580 2585          vfs_t *vfsp;
2581 2586          vnode_t *vp;
2582 2587          int error;
2583 2588          fid_t *fidp;
2584 2589  
2585 2590          if (exi == NULL)
2586 2591                  return (NULL);  /* not exported */
2587 2592  
2588 2593          ASSERT(exi->exi_vp != NULL);
2589 2594  
2590 2595          if (PUBLIC_FH3(fh)) {
2591 2596                  if (exi->exi_export.ex_flags & EX_PUBLIC)
2592 2597                          return (NULL);
2593 2598                  vp = exi->exi_vp;
2594 2599                  VN_HOLD(vp);
2595 2600                  return (vp);
2596 2601          }
2597 2602  
2598 2603          if (fh->fh3_length < NFS3_OLDFHSIZE ||
2599 2604              fh->fh3_length > NFS3_MAXFHSIZE)
2600 2605                  return (NULL);
2601 2606  
2602 2607          vfsp = exi->exi_vp->v_vfsp;
2603 2608          ASSERT(vfsp != NULL);
2604 2609          fidp = FH3TOFIDP(fh);
2605 2610  
2606 2611          error = VFS_VGET(vfsp, &vp, fidp);
2607 2612          if (error || vp == NULL)
2608 2613                  return (NULL);
2609 2614  
2610 2615          return (vp);
2611 2616  }
2612 2617  
2613 2618  /*
2614 2619   * Convert an nfs_fh4 into a vnode.
2615 2620   * Uses the file id (fh_len + fh_data) in the file handle to get the vnode.
2616 2621   * WARNING: users of this routine must do a VN_RELE on the vnode when they
2617 2622   * are done with it.
2618 2623   */
2619 2624  vnode_t *
2620 2625  nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp)
2621 2626  {
2622 2627          vfs_t *vfsp;
2623 2628          vnode_t *vp = NULL;
2624 2629          int error;
2625 2630          fid_t *fidp;
2626 2631          nfs_fh4_fmt_t *fh_fmtp;
2627 2632  #ifdef VOLATILE_FH_TEST
2628 2633          uint32_t volatile_id = 0;
2629 2634  #endif /* VOLATILE_FH_TEST */
2630 2635  
2631 2636          if (exi == NULL) {
2632 2637                  *statp = NFS4ERR_STALE;
2633 2638                  return (NULL);  /* not exported */
2634 2639          }
2635 2640          ASSERT(exi->exi_vp != NULL);
2636 2641  
2637 2642          /* caller should have checked this */
2638 2643          ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN);
2639 2644  
2640 2645          fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val;
2641 2646          vfsp = exi->exi_vp->v_vfsp;
2642 2647          ASSERT(vfsp != NULL);
2643 2648          fidp = (fid_t *)&fh_fmtp->fh4_len;
2644 2649  
2645 2650  #ifdef VOLATILE_FH_TEST
2646 2651          /* XXX check if volatile - should be changed later */
2647 2652          if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) {
2648 2653                  /*
2649 2654                   * Filesystem is shared with volatile filehandles
2650 2655                   */
2651 2656                  if (exi->exi_export.ex_flags & EX_VOLRNM)
2652 2657                          volatile_id = find_volrnm_fh_id(exi, fh);
2653 2658                  else
2654 2659                          volatile_id = exi->exi_volatile_id;
2655 2660  
2656 2661                  if (fh_fmtp->fh4_volatile_id != volatile_id) {
2657 2662                          *statp = NFS4ERR_FHEXPIRED;
2658 2663                          return (NULL);
2659 2664                  }
2660 2665          }
2661 2666          /*
2662 2667           * XXX even if test_volatile_fh false, the fh may contain a
2663 2668           * volatile id if obtained when the test was set.
2664 2669           */
2665 2670          fh_fmtp->fh4_volatile_id = (uchar_t)0;
2666 2671  #endif /* VOLATILE_FH_TEST */
2667 2672  
2668 2673          error = VFS_VGET(vfsp, &vp, fidp);
2669 2674          /*
2670 2675           * If we can not get vp from VFS_VGET, perhaps this is
2671 2676           * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem.
2672 2677           * Check it out.
2673 2678           */
2674 2679          if (error && PSEUDO(exi))
2675 2680                  error = nfs4_vget_pseudo(exi, &vp, fidp);
2676 2681  
2677 2682          if (error || vp == NULL) {
2678 2683                  *statp = NFS4ERR_STALE;
2679 2684                  return (NULL);
2680 2685          }
2681 2686          /* XXX - disgusting hack */
2682 2687          if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR)
2683 2688                  vp->v_type = VDIR;
2684 2689          *statp = NFS4_OK;
2685 2690          return (vp);
2686 2691  }
2687 2692  
2688 2693  /*
2689 2694   * Find the export structure associated with the given filesystem.
2690 2695   * If found, then increment the ref count (exi_count).
2691 2696   */
2692 2697  struct exportinfo *
2693 2698  checkexport(fsid_t *fsid, fid_t *fid)
2694 2699  {
2695 2700          struct exportinfo *exi;
2696 2701          nfs_export_t *ne = nfs_get_export();
2697 2702  
2698 2703          rw_enter(&ne->exported_lock, RW_READER);
2699 2704          for (exi = ne->exptable[exptablehash(fsid, fid)];
2700 2705              exi != NULL;
2701 2706              exi = exi->fid_hash.next) {
2702 2707                  if (exportmatch(exi, fsid, fid)) {
2703 2708                          /*
2704 2709                           * If this is the place holder for the
2705 2710                           * public file handle, then return the
2706 2711                           * real export entry for the public file
2707 2712                           * handle.
2708 2713                           */
2709 2714                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2710 2715                                  exi = ne->exi_public;
2711 2716                          }
2712 2717  
2713 2718                          exi_hold(exi);
2714 2719                          rw_exit(&ne->exported_lock);
2715 2720                          return (exi);
2716 2721                  }
2717 2722          }
2718 2723          rw_exit(&ne->exported_lock);
2719 2724          return (NULL);
2720 2725  }
2721 2726  
2722 2727  
2723 2728  /*
2724 2729   * "old school" version of checkexport() for NFS4.  NFS4
2725 2730   * rfs4_compound holds exported_lock for duration of compound
2726 2731   * processing.  This version doesn't manipulate exi_count
2727 2732   * since NFS4 breaks fundamental assumptions in the exi_count
2728 2733   * design.
2729 2734   */
2730 2735  struct exportinfo *
2731 2736  checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2732 2737  {
2733 2738          struct exportinfo *exi;
2734 2739          nfs_export_t *ne = nfs_get_export();
2735 2740  
2736 2741          ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2737 2742  
2738 2743          for (exi = ne->exptable[exptablehash(fsid, fid)];
2739 2744              exi != NULL;
2740 2745              exi = exi->fid_hash.next) {
2741 2746                  if (exportmatch(exi, fsid, fid)) {
2742 2747                          /*
2743 2748                           * If this is the place holder for the
2744 2749                           * public file handle, then return the
2745 2750                           * real export entry for the public file
2746 2751                           * handle.
2747 2752                           */
2748 2753                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2749 2754                                  exi = ne->exi_public;
2750 2755                          }
2751 2756  
2752 2757                          /*
2753 2758                           * If vp is given, check if vp is the
2754 2759                           * same vnode as the exported node.
2755 2760                           *
2756 2761                           * Since VOP_FID of a lofs node returns the
2757 2762                           * fid of its real node (ufs), the exported
2758 2763                           * node for lofs and (pseudo) ufs may have
2759 2764                           * the same fsid and fid.
2760 2765                           */
2761 2766                          if (vp == NULL || vp == exi->exi_vp)
2762 2767                                  return (exi);
2763 2768                  }
2764 2769          }
2765 2770  
2766 2771          return (NULL);
2767 2772  }
2768 2773  
2769 2774  /*
2770 2775   * Free an entire export list node
2771 2776   */
2772 2777  void
2773 2778  exportfree(struct exportinfo *exi)
2774 2779  {
2775 2780          struct exportdata *ex;
2776 2781          struct charset_cache *cache;
2777 2782          int i;
2778 2783  
2779 2784          ex = &exi->exi_export;
2780 2785  
2781 2786          ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2782 2787          VN_RELE(exi->exi_vp);
2783 2788          if (exi->exi_dvp != NULL)
2784 2789                  VN_RELE(exi->exi_dvp);
2785 2790  
2786 2791          if (ex->ex_flags & EX_INDEX)
2787 2792                  kmem_free(ex->ex_index, strlen(ex->ex_index) + 1);
2788 2793  
2789 2794          kmem_free(ex->ex_path, ex->ex_pathlen + 1);
2790 2795          nfsauth_cache_free(exi);
2791 2796  
2792 2797          /*
2793 2798           * if there is a character set mapping cached, clean it up.
2794 2799           */
2795 2800          for (cache = exi->exi_charset; cache != NULL;
2796 2801              cache = exi->exi_charset) {
2797 2802                  if (cache->inbound != (kiconv_t)-1)
2798 2803                          (void) kiconv_close(cache->inbound);
2799 2804                  if (cache->outbound != (kiconv_t)-1)
2800 2805                          (void) kiconv_close(cache->outbound);
2801 2806                  exi->exi_charset = cache->next;
2802 2807                  kmem_free(cache, sizeof (struct charset_cache));
2803 2808          }
2804 2809  
2805 2810          if (exi->exi_logbuffer != NULL)
2806 2811                  nfslog_disable(exi);
2807 2812  
2808 2813          if (ex->ex_flags & EX_LOG) {
2809 2814                  kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1);
2810 2815                  kmem_free(ex->ex_tag, ex->ex_taglen + 1);
2811 2816          }
2812 2817  
2813 2818          if (exi->exi_visible)
2814 2819                  free_visible(exi->exi_visible);
2815 2820  
2816 2821          srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt);
2817 2822  
2818 2823  #ifdef VOLATILE_FH_TEST
2819 2824          free_volrnm_list(exi);
2820 2825          mutex_destroy(&exi->exi_vol_rename_lock);
2821 2826  #endif /* VOLATILE_FH_TEST */
2822 2827  
2823 2828          mutex_destroy(&exi->exi_lock);
2824 2829          rw_destroy(&exi->exi_cache_lock);
2825 2830          /*
2826 2831           * All nodes in the exi_cache AVL trees were removed and freed in the
2827 2832           * nfsauth_cache_free() call above.  We will just destroy and free the
2828 2833           * empty AVL trees here.
2829 2834           */
2830 2835          for (i = 0; i < AUTH_TABLESIZE; i++) {
2831 2836                  avl_destroy(exi->exi_cache[i]);
2832 2837                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
2833 2838          }
2834 2839  
2835 2840          kmem_free(exi, sizeof (*exi));
2836 2841  }
2837 2842  
2838 2843  /*
2839 2844   * load the index file from user space into kernel space.
2840 2845   */
2841 2846  static int
2842 2847  loadindex(struct exportdata *kex)
2843 2848  {
2844 2849          int error;
2845 2850          char index[MAXNAMELEN+1];
2846 2851          size_t len;
2847 2852  
2848 2853          /*
2849 2854           * copyinstr copies the complete string including the NULL and
2850 2855           * returns the len with the NULL byte included in the calculation
2851 2856           * as long as the max length is not exceeded.
2852 2857           */
2853 2858          if (error = copyinstr(kex->ex_index, index, sizeof (index), &len))
2854 2859                  return (error);
2855 2860  
2856 2861          kex->ex_index = kmem_alloc(len, KM_SLEEP);
2857 2862          bcopy(index, kex->ex_index, len);
2858 2863  
2859 2864          return (0);
2860 2865  }
2861 2866  
2862 2867  void
2863 2868  exi_hold(struct exportinfo *exi)
2864 2869  {
2865 2870          mutex_enter(&exi->exi_lock);
2866 2871          exi->exi_count++;
2867 2872          mutex_exit(&exi->exi_lock);
2868 2873  }
2869 2874  
2870 2875  /*
2871 2876   * When a thread completes using exi, it should call exi_rele().
2872 2877   * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2873 2878   * if this is the last user of exi and exi is not on exportinfo list anymore
2874 2879   */
2875 2880  void
2876 2881  exi_rele(struct exportinfo *exi)
2877 2882  {
2878 2883          mutex_enter(&exi->exi_lock);
2879 2884          exi->exi_count--;
2880 2885          if (exi->exi_count == 0) {
2881 2886                  mutex_exit(&exi->exi_lock);
2882 2887                  exportfree(exi);
2883 2888          } else
2884 2889                  mutex_exit(&exi->exi_lock);
2885 2890  }
2886 2891  
2887 2892  #ifdef VOLATILE_FH_TEST
2888 2893  /*
2889 2894   * Test for volatile fh's - add file handle to list and set its volatile id
2890 2895   * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2891 2896   * the vol_rename queue is purged.
2892 2897   *
2893 2898   * XXX This code is for unit testing purposes only... To correctly use it, it
2894 2899   * needs to tie a rename list to the export struct and (more
2895 2900   * important), protect access to the exi rename list using a write lock.
2896 2901   */
2897 2902  
2898 2903  /*
2899 2904   * get the fh vol record if it's in the volatile on rename list. Don't check
2900 2905   * volatile_id in the file handle - compare only the file handles.
2901 2906   */
2902 2907  static struct ex_vol_rename *
2903 2908  find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p)
2904 2909  {
2905 2910          struct ex_vol_rename *p = NULL;
2906 2911          fhandle4_t *fhp;
2907 2912  
2908 2913          /* XXX shouldn't we assert &exported_lock held? */
2909 2914          ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock));
2910 2915  
2911 2916          if (fh4p->nfs_fh4_len != NFS_FH4_LEN) {
2912 2917                  return (NULL);
2913 2918          }
2914 2919          fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i;
2915 2920          for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) {
2916 2921                  if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i,
2917 2922                      sizeof (fhandle4_t)) == 0)
2918 2923                          break;
2919 2924          }
2920 2925          return (p);
2921 2926  }
2922 2927  
2923 2928  /*
2924 2929   * get the volatile id for the fh (if there is - else return 0). Ignore the
2925 2930   * volatile_id in the file handle - compare only the file handles.
2926 2931   */
2927 2932  static uint32_t
2928 2933  find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p)
2929 2934  {
2930 2935          struct ex_vol_rename *p;
2931 2936          uint32_t volatile_id;
2932 2937  
2933 2938          mutex_enter(&exi->exi_vol_rename_lock);
2934 2939          p = find_volrnm_fh(exi, fh4p);
2935 2940          volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id :
2936 2941              exi->exi_volatile_id);
2937 2942          mutex_exit(&exi->exi_vol_rename_lock);
2938 2943          return (volatile_id);
2939 2944  }
2940 2945  
2941 2946  /*
2942 2947   * Free the volatile on rename list - will be called if a filesystem is
2943 2948   * unshared or reshared without EX_VOLRNM
2944 2949   */
2945 2950  static void
2946 2951  free_volrnm_list(struct exportinfo *exi)
2947 2952  {
2948 2953          struct ex_vol_rename *p, *pnext;
2949 2954  
2950 2955          /* no need to hold mutex lock - this one is called from exportfree */
2951 2956          for (p = exi->exi_vol_rename; p != NULL; p = pnext) {
2952 2957                  pnext = p->vrn_next;
2953 2958                  kmem_free(p, sizeof (*p));
2954 2959          }
2955 2960          exi->exi_vol_rename = NULL;
2956 2961  }
2957 2962  
2958 2963  /*
2959 2964   * Add a file handle to the volatile on rename list.
2960 2965   */
2961 2966  void
2962 2967  add_volrnm_fh(struct exportinfo *exi, vnode_t *vp)
2963 2968  {
2964 2969          struct ex_vol_rename *p;
2965 2970          char fhbuf[NFS4_FHSIZE];
2966 2971          nfs_fh4 fh4;
2967 2972          int error;
2968 2973  
2969 2974          fh4.nfs_fh4_val = fhbuf;
2970 2975          error = makefh4(&fh4, vp, exi);
2971 2976          if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) {
2972 2977                  return;
2973 2978          }
2974 2979  
2975 2980          mutex_enter(&exi->exi_vol_rename_lock);
2976 2981  
2977 2982          p = find_volrnm_fh(exi, &fh4);
2978 2983  
2979 2984          if (p == NULL) {
2980 2985                  p = kmem_alloc(sizeof (*p), KM_SLEEP);
2981 2986                  bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt));
2982 2987                  p->vrn_next = exi->exi_vol_rename;
2983 2988                  exi->exi_vol_rename = p;
2984 2989          }
2985 2990  
2986 2991          p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec();
2987 2992          mutex_exit(&exi->exi_vol_rename_lock);
2988 2993  }
2989 2994  
2990 2995  #endif /* VOLATILE_FH_TEST */
  
    | 
      ↓ open down ↓ | 
    1012 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX