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