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 }