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