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