xref: /illumos-gate/usr/src/uts/common/fs/zfs/dsl_deleg.c (revision d95706ae611eae3b5322f74a123e10949d9d7d5d)
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