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