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