Print this page
    
2619 asynchronous destruction of ZFS file systems
2747 SPA versioning with zfs feature flags
Reviewed by: Matt Ahrens <mahrens@delphix.com>
Reviewed by: George Wilson <gwilson@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>
Approved by: Dan McDonald <danmcd@nexenta.com>
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/zfs/dsl_deleg.c
          +++ new/usr/src/uts/common/fs/zfs/dsl_deleg.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   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  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   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  23      - * Copyright (c) 2011 by Delphix. All rights reserved.
       23 + * Copyright (c) 2012 by Delphix. All rights reserved.
  24   24   */
  25   25  
  26   26  /*
  27   27   * DSL permissions are stored in a two level zap attribute
  28   28   * mechanism.   The first level identifies the "class" of
  29   29   * entry.  The class is identified by the first 2 letters of
  30   30   * the attribute.  The second letter "l" or "d" identifies whether
  31   31   * it is a local or descendent permission.  The first letter
  32   32   * identifies the type of entry.
  33   33   *
  34   34   * ul$<id>    identifies permissions granted locally for this userid.
  35   35   * ud$<id>    identifies permissions granted on descendent datasets for
  36   36   *            this userid.
  37   37   * Ul$<id>    identifies permission sets granted locally for this userid.
  38   38   * Ud$<id>    identifies permission sets granted on descendent datasets for
  39   39   *            this userid.
  40   40   * gl$<id>    identifies permissions granted locally for this groupid.
  41   41   * gd$<id>    identifies permissions granted on descendent datasets for
  42   42   *            this groupid.
  43   43   * Gl$<id>    identifies permission sets granted locally for this groupid.
  44   44   * Gd$<id>    identifies permission sets granted on descendent datasets for
  45   45   *            this groupid.
  46   46   * el$        identifies permissions granted locally for everyone.
  47   47   * ed$        identifies permissions granted on descendent datasets
  48   48   *            for everyone.
  49   49   * El$        identifies permission sets granted locally for everyone.
  50   50   * Ed$        identifies permission sets granted to descendent datasets for
  51   51   *            everyone.
  52   52   * c-$        identifies permission to create at dataset creation time.
  53   53   * C-$        identifies permission sets to grant locally at dataset creation
  54   54   *            time.
  55   55   * s-$@<name> permissions defined in specified set @<name>
  56   56   * S-$@<name> Sets defined in named set @<name>
  57   57   *
  58   58   * Each of the above entities points to another zap attribute that contains one
  59   59   * attribute for each allowed permission, such as create, destroy,...
  60   60   * All of the "upper" case class types will specify permission set names
  61   61   * rather than permissions.
  62   62   *
  63   63   * Basically it looks something like this:
  64   64   * ul$12 -> ZAP OBJ -> permissions...
  65   65   *
  66   66   * The ZAP OBJ is referred to as the jump object.
  67   67   */
  68   68  
  69   69  #include <sys/dmu.h>
  70   70  #include <sys/dmu_objset.h>
  71   71  #include <sys/dmu_tx.h>
  72   72  #include <sys/dsl_dataset.h>
  73   73  #include <sys/dsl_dir.h>
  74   74  #include <sys/dsl_prop.h>
  75   75  #include <sys/dsl_synctask.h>
  76   76  #include <sys/dsl_deleg.h>
  77   77  #include <sys/spa.h>
  78   78  #include <sys/zap.h>
  79   79  #include <sys/fs/zfs.h>
  80   80  #include <sys/cred.h>
  81   81  #include <sys/sunddi.h>
  82   82  
  83   83  #include "zfs_deleg.h"
  84   84  
  85   85  /*
  86   86   * Validate that user is allowed to delegate specified permissions.
  87   87   *
  88   88   * In order to delegate "create" you must have "create"
  89   89   * and "allow".
  90   90   */
  91   91  int
  92   92  dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
  93   93  {
  94   94          nvpair_t *whopair = NULL;
  95   95          int error;
  96   96  
  97   97          if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
  98   98                  return (error);
  99   99  
 100  100          while (whopair = nvlist_next_nvpair(nvp, whopair)) {
 101  101                  nvlist_t *perms;
 102  102                  nvpair_t *permpair = NULL;
 103  103  
 104  104                  VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
 105  105  
 106  106                  while (permpair = nvlist_next_nvpair(perms, permpair)) {
 107  107                          const char *perm = nvpair_name(permpair);
 108  108  
 109  109                          if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
 110  110                                  return (EPERM);
 111  111  
 112  112                          if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
 113  113                                  return (error);
 114  114                  }
 115  115          }
 116  116          return (0);
 117  117  }
 118  118  
 119  119  /*
 120  120   * Validate that user is allowed to unallow specified permissions.  They
 121  121   * must have the 'allow' permission, and even then can only unallow
 122  122   * perms for their uid.
 123  123   */
 124  124  int
 125  125  dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
 126  126  {
 127  127          nvpair_t *whopair = NULL;
 128  128          int error;
 129  129          char idstr[32];
 130  130  
 131  131          if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
 132  132                  return (error);
 133  133  
 134  134          (void) snprintf(idstr, sizeof (idstr), "%lld",
 135  135              (longlong_t)crgetuid(cr));
 136  136  
 137  137          while (whopair = nvlist_next_nvpair(nvp, whopair)) {
 138  138                  zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
 139  139  
 140  140                  if (type != ZFS_DELEG_USER &&
 141  141                      type != ZFS_DELEG_USER_SETS)
 142  142                          return (EPERM);
 143  143  
 144  144                  if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
 145  145                          return (EPERM);
 146  146          }
 147  147          return (0);
 148  148  }
 149  149  
 150  150  static void
 151  151  dsl_deleg_set_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 152  152  {
 153  153          dsl_dir_t *dd = arg1;
 154  154          nvlist_t *nvp = arg2;
 155  155          objset_t *mos = dd->dd_pool->dp_meta_objset;
 156  156          nvpair_t *whopair = NULL;
 157  157          uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
 158  158  
 159  159          if (zapobj == 0) {
 160  160                  dmu_buf_will_dirty(dd->dd_dbuf, tx);
 161  161                  zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos,
 162  162                      DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
 163  163          }
  
    | 
      ↓ open down ↓ | 
    130 lines elided | 
    
      ↑ open up ↑ | 
  
 164  164  
 165  165          while (whopair = nvlist_next_nvpair(nvp, whopair)) {
 166  166                  const char *whokey = nvpair_name(whopair);
 167  167                  nvlist_t *perms;
 168  168                  nvpair_t *permpair = NULL;
 169  169                  uint64_t jumpobj;
 170  170  
 171  171                  VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
 172  172  
 173  173                  if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
 174      -                        jumpobj = zap_create(mos, DMU_OT_DSL_PERMS,
 175      -                            DMU_OT_NONE, 0, tx);
 176      -                        VERIFY(zap_update(mos, zapobj,
 177      -                            whokey, 8, 1, &jumpobj, tx) == 0);
      174 +                        jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
      175 +                            zapobj, whokey, tx);
 178  176                  }
 179  177  
 180  178                  while (permpair = nvlist_next_nvpair(perms, permpair)) {
 181  179                          const char *perm = nvpair_name(permpair);
 182  180                          uint64_t n = 0;
 183  181  
 184  182                          VERIFY(zap_update(mos, jumpobj,
 185  183                              perm, 8, 1, &n, tx) == 0);
 186  184                          spa_history_log_internal(LOG_DS_PERM_UPDATE,
 187  185                              dd->dd_pool->dp_spa, tx,
 188  186                              "%s %s dataset = %llu", whokey, perm,
 189  187                              dd->dd_phys->dd_head_dataset_obj);
 190  188                  }
 191  189          }
 192  190  }
 193  191  
 194  192  static void
 195  193  dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 196  194  {
 197  195          dsl_dir_t *dd = arg1;
 198  196          nvlist_t *nvp = arg2;
 199  197          objset_t *mos = dd->dd_pool->dp_meta_objset;
 200  198          nvpair_t *whopair = NULL;
 201  199          uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
 202  200  
 203  201          if (zapobj == 0)
 204  202                  return;
 205  203  
 206  204          while (whopair = nvlist_next_nvpair(nvp, whopair)) {
 207  205                  const char *whokey = nvpair_name(whopair);
 208  206                  nvlist_t *perms;
 209  207                  nvpair_t *permpair = NULL;
 210  208                  uint64_t jumpobj;
 211  209  
 212  210                  if (nvpair_value_nvlist(whopair, &perms) != 0) {
 213  211                          if (zap_lookup(mos, zapobj, whokey, 8,
 214  212                              1, &jumpobj) == 0) {
 215  213                                  (void) zap_remove(mos, zapobj, whokey, tx);
 216  214                                  VERIFY(0 == zap_destroy(mos, jumpobj, tx));
 217  215                          }
 218  216                          spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE,
 219  217                              dd->dd_pool->dp_spa, tx,
 220  218                              "%s dataset = %llu", whokey,
 221  219                              dd->dd_phys->dd_head_dataset_obj);
 222  220                          continue;
 223  221                  }
 224  222  
 225  223                  if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
 226  224                          continue;
 227  225  
 228  226                  while (permpair = nvlist_next_nvpair(perms, permpair)) {
 229  227                          const char *perm = nvpair_name(permpair);
 230  228                          uint64_t n = 0;
 231  229  
 232  230                          (void) zap_remove(mos, jumpobj, perm, tx);
 233  231                          if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
 234  232                                  (void) zap_remove(mos, zapobj,
 235  233                                      whokey, tx);
 236  234                                  VERIFY(0 == zap_destroy(mos,
 237  235                                      jumpobj, tx));
 238  236                          }
 239  237                          spa_history_log_internal(LOG_DS_PERM_REMOVE,
 240  238                              dd->dd_pool->dp_spa, tx,
 241  239                              "%s %s dataset = %llu", whokey, perm,
 242  240                              dd->dd_phys->dd_head_dataset_obj);
 243  241                  }
 244  242          }
 245  243  }
 246  244  
 247  245  int
 248  246  dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
 249  247  {
 250  248          dsl_dir_t *dd;
 251  249          int error;
 252  250          nvpair_t *whopair = NULL;
 253  251          int blocks_modified = 0;
 254  252  
 255  253          error = dsl_dir_open(ddname, FTAG, &dd, NULL);
 256  254          if (error)
 257  255                  return (error);
 258  256  
 259  257          if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) <
 260  258              SPA_VERSION_DELEGATED_PERMS) {
 261  259                  dsl_dir_close(dd, FTAG);
 262  260                  return (ENOTSUP);
 263  261          }
 264  262  
 265  263          while (whopair = nvlist_next_nvpair(nvp, whopair))
 266  264                  blocks_modified++;
 267  265  
 268  266          error = dsl_sync_task_do(dd->dd_pool, NULL,
 269  267              unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
 270  268              dd, nvp, blocks_modified);
 271  269          dsl_dir_close(dd, FTAG);
 272  270  
 273  271          return (error);
 274  272  }
 275  273  
 276  274  /*
 277  275   * Find all 'allow' permissions from a given point and then continue
 278  276   * traversing up to the root.
 279  277   *
 280  278   * This function constructs an nvlist of nvlists.
 281  279   * each setpoint is an nvlist composed of an nvlist of an nvlist
 282  280   * of the individual * users/groups/everyone/create
 283  281   * permissions.
 284  282   *
 285  283   * The nvlist will look like this.
 286  284   *
 287  285   * { source fsname -> { whokeys { permissions,...}, ...}}
 288  286   *
 289  287   * The fsname nvpairs will be arranged in a bottom up order.  For example,
 290  288   * if we have the following structure a/b/c then the nvpairs for the fsnames
 291  289   * will be ordered a/b/c, a/b, a.
 292  290   */
 293  291  int
 294  292  dsl_deleg_get(const char *ddname, nvlist_t **nvp)
 295  293  {
 296  294          dsl_dir_t *dd, *startdd;
 297  295          dsl_pool_t *dp;
 298  296          int error;
 299  297          objset_t *mos;
 300  298  
 301  299          error = dsl_dir_open(ddname, FTAG, &startdd, NULL);
 302  300          if (error)
 303  301                  return (error);
 304  302  
 305  303          dp = startdd->dd_pool;
 306  304          mos = dp->dp_meta_objset;
 307  305  
 308  306          VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
 309  307  
 310  308          rw_enter(&dp->dp_config_rwlock, RW_READER);
 311  309          for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
 312  310                  zap_cursor_t basezc;
 313  311                  zap_attribute_t baseza;
 314  312                  nvlist_t *sp_nvp;
 315  313                  uint64_t n;
 316  314                  char source[MAXNAMELEN];
 317  315  
 318  316                  if (dd->dd_phys->dd_deleg_zapobj &&
 319  317                      (zap_count(mos, dd->dd_phys->dd_deleg_zapobj,
 320  318                      &n) == 0) && n) {
 321  319                          VERIFY(nvlist_alloc(&sp_nvp,
 322  320                              NV_UNIQUE_NAME, KM_SLEEP) == 0);
 323  321                  } else {
 324  322                          continue;
 325  323                  }
 326  324  
 327  325                  for (zap_cursor_init(&basezc, mos,
 328  326                      dd->dd_phys->dd_deleg_zapobj);
 329  327                      zap_cursor_retrieve(&basezc, &baseza) == 0;
 330  328                      zap_cursor_advance(&basezc)) {
 331  329                          zap_cursor_t zc;
 332  330                          zap_attribute_t za;
 333  331                          nvlist_t *perms_nvp;
 334  332  
 335  333                          ASSERT(baseza.za_integer_length == 8);
 336  334                          ASSERT(baseza.za_num_integers == 1);
 337  335  
 338  336                          VERIFY(nvlist_alloc(&perms_nvp,
 339  337                              NV_UNIQUE_NAME, KM_SLEEP) == 0);
 340  338                          for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
 341  339                              zap_cursor_retrieve(&zc, &za) == 0;
 342  340                              zap_cursor_advance(&zc)) {
 343  341                                  VERIFY(nvlist_add_boolean(perms_nvp,
 344  342                                      za.za_name) == 0);
 345  343                          }
 346  344                          zap_cursor_fini(&zc);
 347  345                          VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name,
 348  346                              perms_nvp) == 0);
 349  347                          nvlist_free(perms_nvp);
 350  348                  }
 351  349  
 352  350                  zap_cursor_fini(&basezc);
 353  351  
 354  352                  dsl_dir_name(dd, source);
 355  353                  VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0);
 356  354                  nvlist_free(sp_nvp);
 357  355          }
 358  356          rw_exit(&dp->dp_config_rwlock);
 359  357  
 360  358          dsl_dir_close(startdd, FTAG);
 361  359          return (0);
 362  360  }
 363  361  
 364  362  /*
 365  363   * Routines for dsl_deleg_access() -- access checking.
 366  364   */
 367  365  typedef struct perm_set {
 368  366          avl_node_t      p_node;
 369  367          boolean_t       p_matched;
 370  368          char            p_setname[ZFS_MAX_DELEG_NAME];
 371  369  } perm_set_t;
 372  370  
 373  371  static int
 374  372  perm_set_compare(const void *arg1, const void *arg2)
 375  373  {
 376  374          const perm_set_t *node1 = arg1;
 377  375          const perm_set_t *node2 = arg2;
 378  376          int val;
 379  377  
 380  378          val = strcmp(node1->p_setname, node2->p_setname);
 381  379          if (val == 0)
 382  380                  return (0);
 383  381          return (val > 0 ? 1 : -1);
 384  382  }
 385  383  
 386  384  /*
 387  385   * Determine whether a specified permission exists.
 388  386   *
 389  387   * First the base attribute has to be retrieved.  i.e. ul$12
 390  388   * Once the base object has been retrieved the actual permission
 391  389   * is lookup up in the zap object the base object points to.
 392  390   *
 393  391   * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
 394  392   * there is no perm in that jumpobj.
 395  393   */
 396  394  static int
 397  395  dsl_check_access(objset_t *mos, uint64_t zapobj,
 398  396      char type, char checkflag, void *valp, const char *perm)
 399  397  {
 400  398          int error;
 401  399          uint64_t jumpobj, zero;
 402  400          char whokey[ZFS_MAX_DELEG_NAME];
 403  401  
 404  402          zfs_deleg_whokey(whokey, type, checkflag, valp);
 405  403          error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
 406  404          if (error == 0) {
 407  405                  error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
 408  406                  if (error == ENOENT)
 409  407                          error = EPERM;
 410  408          }
 411  409          return (error);
 412  410  }
 413  411  
 414  412  /*
 415  413   * check a specified user/group for a requested permission
 416  414   */
 417  415  static int
 418  416  dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
 419  417      int checkflag, cred_t *cr)
 420  418  {
 421  419          const   gid_t *gids;
 422  420          int     ngids;
 423  421          int     i;
 424  422          uint64_t id;
 425  423  
 426  424          /* check for user */
 427  425          id = crgetuid(cr);
 428  426          if (dsl_check_access(mos, zapobj,
 429  427              ZFS_DELEG_USER, checkflag, &id, perm) == 0)
 430  428                  return (0);
 431  429  
 432  430          /* check for users primary group */
 433  431          id = crgetgid(cr);
 434  432          if (dsl_check_access(mos, zapobj,
 435  433              ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
 436  434                  return (0);
 437  435  
 438  436          /* check for everyone entry */
 439  437          id = -1;
 440  438          if (dsl_check_access(mos, zapobj,
 441  439              ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
 442  440                  return (0);
 443  441  
 444  442          /* check each supplemental group user is a member of */
 445  443          ngids = crgetngroups(cr);
 446  444          gids = crgetgroups(cr);
 447  445          for (i = 0; i != ngids; i++) {
 448  446                  id = gids[i];
 449  447                  if (dsl_check_access(mos, zapobj,
 450  448                      ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
 451  449                          return (0);
 452  450          }
 453  451  
 454  452          return (EPERM);
 455  453  }
 456  454  
 457  455  /*
 458  456   * Iterate over the sets specified in the specified zapobj
 459  457   * and load them into the permsets avl tree.
 460  458   */
 461  459  static int
 462  460  dsl_load_sets(objset_t *mos, uint64_t zapobj,
 463  461      char type, char checkflag, void *valp, avl_tree_t *avl)
 464  462  {
 465  463          zap_cursor_t zc;
 466  464          zap_attribute_t za;
 467  465          perm_set_t *permnode;
 468  466          avl_index_t idx;
 469  467          uint64_t jumpobj;
 470  468          int error;
 471  469          char whokey[ZFS_MAX_DELEG_NAME];
 472  470  
 473  471          zfs_deleg_whokey(whokey, type, checkflag, valp);
 474  472  
 475  473          error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
 476  474          if (error != 0)
 477  475                  return (error);
 478  476  
 479  477          for (zap_cursor_init(&zc, mos, jumpobj);
 480  478              zap_cursor_retrieve(&zc, &za) == 0;
 481  479              zap_cursor_advance(&zc)) {
 482  480                  permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
 483  481                  (void) strlcpy(permnode->p_setname, za.za_name,
 484  482                      sizeof (permnode->p_setname));
 485  483                  permnode->p_matched = B_FALSE;
 486  484  
 487  485                  if (avl_find(avl, permnode, &idx) == NULL) {
 488  486                          avl_insert(avl, permnode, idx);
 489  487                  } else {
 490  488                          kmem_free(permnode, sizeof (perm_set_t));
 491  489                  }
 492  490          }
 493  491          zap_cursor_fini(&zc);
 494  492          return (0);
 495  493  }
 496  494  
 497  495  /*
 498  496   * Load all permissions user based on cred belongs to.
 499  497   */
 500  498  static void
 501  499  dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
 502  500      char checkflag, cred_t *cr)
 503  501  {
 504  502          const   gid_t *gids;
 505  503          int     ngids, i;
 506  504          uint64_t id;
 507  505  
 508  506          id = crgetuid(cr);
 509  507          (void) dsl_load_sets(mos, zapobj,
 510  508              ZFS_DELEG_USER_SETS, checkflag, &id, avl);
 511  509  
 512  510          id = crgetgid(cr);
 513  511          (void) dsl_load_sets(mos, zapobj,
 514  512              ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
 515  513  
 516  514          (void) dsl_load_sets(mos, zapobj,
 517  515              ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
 518  516  
 519  517          ngids = crgetngroups(cr);
 520  518          gids = crgetgroups(cr);
 521  519          for (i = 0; i != ngids; i++) {
 522  520                  id = gids[i];
 523  521                  (void) dsl_load_sets(mos, zapobj,
 524  522                      ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
 525  523          }
 526  524  }
 527  525  
 528  526  /*
 529  527   * Check if user has requested permission.  If descendent is set, must have
 530  528   * descendent perms.
 531  529   */
 532  530  int
 533  531  dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
 534  532      cred_t *cr)
 535  533  {
 536  534          dsl_dir_t *dd;
 537  535          dsl_pool_t *dp;
 538  536          void *cookie;
 539  537          int     error;
 540  538          char    checkflag;
 541  539          objset_t *mos;
 542  540          avl_tree_t permsets;
 543  541          perm_set_t *setnode;
 544  542  
 545  543          dp = ds->ds_dir->dd_pool;
 546  544          mos = dp->dp_meta_objset;
 547  545  
 548  546          if (dsl_delegation_on(mos) == B_FALSE)
 549  547                  return (ECANCELED);
 550  548  
 551  549          if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
 552  550              SPA_VERSION_DELEGATED_PERMS)
 553  551                  return (EPERM);
 554  552  
 555  553          if (dsl_dataset_is_snapshot(ds) || descendent) {
 556  554                  /*
 557  555                   * Snapshots are treated as descendents only,
 558  556                   * local permissions do not apply.
 559  557                   */
 560  558                  checkflag = ZFS_DELEG_DESCENDENT;
 561  559          } else {
 562  560                  checkflag = ZFS_DELEG_LOCAL;
 563  561          }
 564  562  
 565  563          avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
 566  564              offsetof(perm_set_t, p_node));
 567  565  
 568  566          rw_enter(&dp->dp_config_rwlock, RW_READER);
 569  567          for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
 570  568              checkflag = ZFS_DELEG_DESCENDENT) {
 571  569                  uint64_t zapobj;
 572  570                  boolean_t expanded;
 573  571  
 574  572                  /*
 575  573                   * If not in global zone then make sure
 576  574                   * the zoned property is set
 577  575                   */
 578  576                  if (!INGLOBALZONE(curproc)) {
 579  577                          uint64_t zoned;
 580  578  
 581  579                          if (dsl_prop_get_dd(dd,
 582  580                              zfs_prop_to_name(ZFS_PROP_ZONED),
 583  581                              8, 1, &zoned, NULL, B_FALSE) != 0)
 584  582                                  break;
 585  583                          if (!zoned)
 586  584                                  break;
 587  585                  }
 588  586                  zapobj = dd->dd_phys->dd_deleg_zapobj;
 589  587  
 590  588                  if (zapobj == 0)
 591  589                          continue;
 592  590  
 593  591                  dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
 594  592  again:
 595  593                  expanded = B_FALSE;
 596  594                  for (setnode = avl_first(&permsets); setnode;
 597  595                      setnode = AVL_NEXT(&permsets, setnode)) {
 598  596                          if (setnode->p_matched == B_TRUE)
 599  597                                  continue;
 600  598  
 601  599                          /* See if this set directly grants this permission */
 602  600                          error = dsl_check_access(mos, zapobj,
 603  601                              ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
 604  602                          if (error == 0)
 605  603                                  goto success;
 606  604                          if (error == EPERM)
 607  605                                  setnode->p_matched = B_TRUE;
 608  606  
 609  607                          /* See if this set includes other sets */
 610  608                          error = dsl_load_sets(mos, zapobj,
 611  609                              ZFS_DELEG_NAMED_SET_SETS, 0,
 612  610                              setnode->p_setname, &permsets);
 613  611                          if (error == 0)
 614  612                                  setnode->p_matched = expanded = B_TRUE;
 615  613                  }
 616  614                  /*
 617  615                   * If we expanded any sets, that will define more sets,
 618  616                   * which we need to check.
 619  617                   */
 620  618                  if (expanded)
 621  619                          goto again;
 622  620  
 623  621                  error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
 624  622                  if (error == 0)
 625  623                          goto success;
 626  624          }
 627  625          error = EPERM;
 628  626  success:
 629  627          rw_exit(&dp->dp_config_rwlock);
 630  628  
 631  629          cookie = NULL;
 632  630          while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
 633  631                  kmem_free(setnode, sizeof (perm_set_t));
 634  632  
 635  633          return (error);
 636  634  }
 637  635  
 638  636  int
 639  637  dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
 640  638  {
 641  639          dsl_dataset_t *ds;
 642  640          int error;
 643  641  
 644  642          error = dsl_dataset_hold(dsname, FTAG, &ds);
 645  643          if (error)
 646  644                  return (error);
 647  645  
 648  646          error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
 649  647          dsl_dataset_rele(ds, FTAG);
 650  648  
 651  649          return (error);
 652  650  }
 653  651  
 654  652  /*
 655  653   * Other routines.
 656  654   */
 657  655  
 658  656  static void
 659  657  copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
 660  658      boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
 661  659  {
 662  660          objset_t *mos = dd->dd_pool->dp_meta_objset;
 663  661          uint64_t jumpobj, pjumpobj;
 664  662          uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
 665  663          zap_cursor_t zc;
 666  664          zap_attribute_t za;
 667  665          char whokey[ZFS_MAX_DELEG_NAME];
 668  666  
 669  667          zfs_deleg_whokey(whokey,
 670  668              dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
 671  669              ZFS_DELEG_LOCAL, NULL);
 672  670          if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
 673  671                  return;
 674  672  
 675  673          if (zapobj == 0) {
 676  674                  dmu_buf_will_dirty(dd->dd_dbuf, tx);
 677  675                  zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos,
 678  676                      DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
 679  677          }
 680  678  
 681  679          zfs_deleg_whokey(whokey,
 682  680              dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
 683  681              ZFS_DELEG_LOCAL, &uid);
 684  682          if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
 685  683                  jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
 686  684                  VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
 687  685          }
 688  686  
 689  687          for (zap_cursor_init(&zc, mos, pjumpobj);
 690  688              zap_cursor_retrieve(&zc, &za) == 0;
 691  689              zap_cursor_advance(&zc)) {
 692  690                  uint64_t zero = 0;
 693  691                  ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
 694  692  
 695  693                  VERIFY(zap_update(mos, jumpobj, za.za_name,
 696  694                      8, 1, &zero, tx) == 0);
 697  695          }
 698  696          zap_cursor_fini(&zc);
 699  697  }
 700  698  
 701  699  /*
 702  700   * set all create time permission on new dataset.
 703  701   */
 704  702  void
 705  703  dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
 706  704  {
 707  705          dsl_dir_t *dd;
 708  706          uint64_t uid = crgetuid(cr);
 709  707  
 710  708          if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
 711  709              SPA_VERSION_DELEGATED_PERMS)
 712  710                  return;
 713  711  
 714  712          for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
 715  713                  uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj;
 716  714  
 717  715                  if (pzapobj == 0)
 718  716                          continue;
 719  717  
 720  718                  copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
 721  719                  copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
 722  720          }
 723  721  }
 724  722  
 725  723  int
 726  724  dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
 727  725  {
 728  726          zap_cursor_t zc;
 729  727          zap_attribute_t za;
 730  728  
 731  729          if (zapobj == 0)
 732  730                  return (0);
 733  731  
 734  732          for (zap_cursor_init(&zc, mos, zapobj);
 735  733              zap_cursor_retrieve(&zc, &za) == 0;
 736  734              zap_cursor_advance(&zc)) {
 737  735                  ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
 738  736                  VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx));
 739  737          }
 740  738          zap_cursor_fini(&zc);
 741  739          VERIFY(0 == zap_destroy(mos, zapobj, tx));
 742  740          return (0);
 743  741  }
 744  742  
 745  743  boolean_t
 746  744  dsl_delegation_on(objset_t *os)
 747  745  {
 748  746          return (!!spa_delegation(os->os_spa));
 749  747  }
  
    | 
      ↓ open down ↓ | 
    562 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX