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 }