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