xref: /illumos-gate/usr/src/uts/common/fs/zfs/dsl_deleg.c (revision 4eaa471005973e11a6110b69fe990530b3b95a38)
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 2009 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 #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/spa_impl.h>
79 #include <sys/zio_checksum.h> /* for the default checksum value */
80 #include <sys/zap.h>
81 #include <sys/fs/zfs.h>
82 #include <sys/cred.h>
83 #include <sys/sunddi.h>
84 
85 #include "zfs_deleg.h"
86 
87 /*
88  * Validate that user is allowed to delegate specified permissions.
89  *
90  * In order to delegate "create" you must have "create"
91  * and "allow".
92  */
93 int
94 dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
95 {
96 	nvpair_t *whopair = NULL;
97 	int error;
98 
99 	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
100 		return (error);
101 
102 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
103 		nvlist_t *perms;
104 		nvpair_t *permpair = NULL;
105 
106 		VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
107 
108 		while (permpair = nvlist_next_nvpair(perms, permpair)) {
109 			const char *perm = nvpair_name(permpair);
110 
111 			if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
112 				return (EPERM);
113 
114 			if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
115 				return (error);
116 		}
117 	}
118 	return (0);
119 }
120 
121 /*
122  * Validate that user is allowed to unallow specified permissions.  They
123  * must have the 'allow' permission, and even then can only unallow
124  * perms for their uid.
125  */
126 int
127 dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
128 {
129 	nvpair_t *whopair = NULL;
130 	int error;
131 	char idstr[32];
132 
133 	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
134 		return (error);
135 
136 	(void) snprintf(idstr, sizeof (idstr), "%lld",
137 	    (longlong_t)crgetuid(cr));
138 
139 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
140 		zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
141 
142 		if (type != ZFS_DELEG_USER &&
143 		    type != ZFS_DELEG_USER_SETS)
144 			return (EPERM);
145 
146 		if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
147 			return (EPERM);
148 	}
149 	return (0);
150 }
151 
152 static void
153 dsl_deleg_set_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
154 {
155 	dsl_dir_t *dd = arg1;
156 	nvlist_t *nvp = arg2;
157 	objset_t *mos = dd->dd_pool->dp_meta_objset;
158 	nvpair_t *whopair = NULL;
159 	uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
160 
161 	if (zapobj == 0) {
162 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
163 		zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos,
164 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
165 	}
166 
167 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
168 		const char *whokey = nvpair_name(whopair);
169 		nvlist_t *perms;
170 		nvpair_t *permpair = NULL;
171 		uint64_t jumpobj;
172 
173 		VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
174 
175 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
176 			jumpobj = zap_create(mos, DMU_OT_DSL_PERMS,
177 			    DMU_OT_NONE, 0, tx);
178 			VERIFY(zap_update(mos, zapobj,
179 			    whokey, 8, 1, &jumpobj, tx) == 0);
180 		}
181 
182 		while (permpair = nvlist_next_nvpair(perms, permpair)) {
183 			const char *perm = nvpair_name(permpair);
184 			uint64_t n = 0;
185 
186 			VERIFY(zap_update(mos, jumpobj,
187 			    perm, 8, 1, &n, tx) == 0);
188 			spa_history_internal_log(LOG_DS_PERM_UPDATE,
189 			    dd->dd_pool->dp_spa, tx, cr,
190 			    "%s %s dataset = %llu", whokey, perm,
191 			    dd->dd_phys->dd_head_dataset_obj);
192 		}
193 	}
194 }
195 
196 static void
197 dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx)
198 {
199 	dsl_dir_t *dd = arg1;
200 	nvlist_t *nvp = arg2;
201 	objset_t *mos = dd->dd_pool->dp_meta_objset;
202 	nvpair_t *whopair = NULL;
203 	uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
204 
205 	if (zapobj == 0)
206 		return;
207 
208 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
209 		const char *whokey = nvpair_name(whopair);
210 		nvlist_t *perms;
211 		nvpair_t *permpair = NULL;
212 		uint64_t jumpobj;
213 
214 		if (nvpair_value_nvlist(whopair, &perms) != 0) {
215 			if (zap_lookup(mos, zapobj, whokey, 8,
216 			    1, &jumpobj) == 0) {
217 				(void) zap_remove(mos, zapobj, whokey, tx);
218 				VERIFY(0 == zap_destroy(mos, jumpobj, tx));
219 			}
220 			spa_history_internal_log(LOG_DS_PERM_WHO_REMOVE,
221 			    dd->dd_pool->dp_spa, tx, cr,
222 			    "%s dataset = %llu", whokey,
223 			    dd->dd_phys->dd_head_dataset_obj);
224 			continue;
225 		}
226 
227 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
228 			continue;
229 
230 		while (permpair = nvlist_next_nvpair(perms, permpair)) {
231 			const char *perm = nvpair_name(permpair);
232 			uint64_t n = 0;
233 
234 			(void) zap_remove(mos, jumpobj, perm, tx);
235 			if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
236 				(void) zap_remove(mos, zapobj,
237 				    whokey, tx);
238 				VERIFY(0 == zap_destroy(mos,
239 				    jumpobj, tx));
240 			}
241 			spa_history_internal_log(LOG_DS_PERM_REMOVE,
242 			    dd->dd_pool->dp_spa, tx, cr,
243 			    "%s %s dataset = %llu", whokey, perm,
244 			    dd->dd_phys->dd_head_dataset_obj);
245 		}
246 	}
247 }
248 
249 int
250 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
251 {
252 	dsl_dir_t *dd;
253 	int error;
254 	nvpair_t *whopair = NULL;
255 	int blocks_modified = 0;
256 
257 	error = dsl_dir_open(ddname, FTAG, &dd, NULL);
258 	if (error)
259 		return (error);
260 
261 	if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) <
262 	    SPA_VERSION_DELEGATED_PERMS) {
263 		dsl_dir_close(dd, FTAG);
264 		return (ENOTSUP);
265 	}
266 
267 	while (whopair = nvlist_next_nvpair(nvp, whopair))
268 		blocks_modified++;
269 
270 	error = dsl_sync_task_do(dd->dd_pool, NULL,
271 	    unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
272 	    dd, nvp, blocks_modified);
273 	dsl_dir_close(dd, FTAG);
274 
275 	return (error);
276 }
277 
278 /*
279  * Find all 'allow' permissions from a given point and then continue
280  * traversing up to the root.
281  *
282  * This function constructs an nvlist of nvlists.
283  * each setpoint is an nvlist composed of an nvlist of an nvlist
284  * of the individual * users/groups/everyone/create
285  * permissions.
286  *
287  * The nvlist will look like this.
288  *
289  * { source fsname -> { whokeys { permissions,...}, ...}}
290  *
291  * The fsname nvpairs will be arranged in a bottom up order.  For example,
292  * if we have the following structure a/b/c then the nvpairs for the fsnames
293  * will be ordered a/b/c, a/b, a.
294  */
295 int
296 dsl_deleg_get(const char *ddname, nvlist_t **nvp)
297 {
298 	dsl_dir_t *dd, *startdd;
299 	dsl_pool_t *dp;
300 	int error;
301 	objset_t *mos;
302 
303 	error = dsl_dir_open(ddname, FTAG, &startdd, NULL);
304 	if (error)
305 		return (error);
306 
307 	dp = startdd->dd_pool;
308 	mos = dp->dp_meta_objset;
309 
310 	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
311 
312 	rw_enter(&dp->dp_config_rwlock, RW_READER);
313 	for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
314 		zap_cursor_t basezc;
315 		zap_attribute_t baseza;
316 		nvlist_t *sp_nvp;
317 		uint64_t n;
318 		char source[MAXNAMELEN];
319 
320 		if (dd->dd_phys->dd_deleg_zapobj &&
321 		    (zap_count(mos, dd->dd_phys->dd_deleg_zapobj,
322 		    &n) == 0) && n) {
323 			VERIFY(nvlist_alloc(&sp_nvp,
324 			    NV_UNIQUE_NAME, KM_SLEEP) == 0);
325 		} else {
326 			continue;
327 		}
328 
329 		for (zap_cursor_init(&basezc, mos,
330 		    dd->dd_phys->dd_deleg_zapobj);
331 		    zap_cursor_retrieve(&basezc, &baseza) == 0;
332 		    zap_cursor_advance(&basezc)) {
333 			zap_cursor_t zc;
334 			zap_attribute_t za;
335 			nvlist_t *perms_nvp;
336 
337 			ASSERT(baseza.za_integer_length == 8);
338 			ASSERT(baseza.za_num_integers == 1);
339 
340 			VERIFY(nvlist_alloc(&perms_nvp,
341 			    NV_UNIQUE_NAME, KM_SLEEP) == 0);
342 			for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
343 			    zap_cursor_retrieve(&zc, &za) == 0;
344 			    zap_cursor_advance(&zc)) {
345 				VERIFY(nvlist_add_boolean(perms_nvp,
346 				    za.za_name) == 0);
347 			}
348 			zap_cursor_fini(&zc);
349 			VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name,
350 			    perms_nvp) == 0);
351 			nvlist_free(perms_nvp);
352 		}
353 
354 		zap_cursor_fini(&basezc);
355 
356 		dsl_dir_name(dd, source);
357 		VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0);
358 		nvlist_free(sp_nvp);
359 	}
360 	rw_exit(&dp->dp_config_rwlock);
361 
362 	dsl_dir_close(startdd, FTAG);
363 	return (0);
364 }
365 
366 /*
367  * Routines for dsl_deleg_access() -- access checking.
368  */
369 typedef struct perm_set {
370 	avl_node_t	p_node;
371 	boolean_t	p_matched;
372 	char		p_setname[ZFS_MAX_DELEG_NAME];
373 } perm_set_t;
374 
375 static int
376 perm_set_compare(const void *arg1, const void *arg2)
377 {
378 	const perm_set_t *node1 = arg1;
379 	const perm_set_t *node2 = arg2;
380 	int val;
381 
382 	val = strcmp(node1->p_setname, node2->p_setname);
383 	if (val == 0)
384 		return (0);
385 	return (val > 0 ? 1 : -1);
386 }
387 
388 /*
389  * Determine whether a specified permission exists.
390  *
391  * First the base attribute has to be retrieved.  i.e. ul$12
392  * Once the base object has been retrieved the actual permission
393  * is lookup up in the zap object the base object points to.
394  *
395  * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
396  * there is no perm in that jumpobj.
397  */
398 static int
399 dsl_check_access(objset_t *mos, uint64_t zapobj,
400     char type, char checkflag, void *valp, const char *perm)
401 {
402 	int error;
403 	uint64_t jumpobj, zero;
404 	char whokey[ZFS_MAX_DELEG_NAME];
405 
406 	zfs_deleg_whokey(whokey, type, checkflag, valp);
407 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
408 	if (error == 0) {
409 		error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
410 		if (error == ENOENT)
411 			error = EPERM;
412 	}
413 	return (error);
414 }
415 
416 /*
417  * check a specified user/group for a requested permission
418  */
419 static int
420 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
421     int checkflag, cred_t *cr)
422 {
423 	const	gid_t *gids;
424 	int	ngids;
425 	int	i;
426 	uint64_t id;
427 
428 	/* check for user */
429 	id = crgetuid(cr);
430 	if (dsl_check_access(mos, zapobj,
431 	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
432 		return (0);
433 
434 	/* check for users primary group */
435 	id = crgetgid(cr);
436 	if (dsl_check_access(mos, zapobj,
437 	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
438 		return (0);
439 
440 	/* check for everyone entry */
441 	id = -1;
442 	if (dsl_check_access(mos, zapobj,
443 	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
444 		return (0);
445 
446 	/* check each supplemental group user is a member of */
447 	ngids = crgetngroups(cr);
448 	gids = crgetgroups(cr);
449 	for (i = 0; i != ngids; i++) {
450 		id = gids[i];
451 		if (dsl_check_access(mos, zapobj,
452 		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
453 			return (0);
454 	}
455 
456 	return (EPERM);
457 }
458 
459 /*
460  * Iterate over the sets specified in the specified zapobj
461  * and load them into the permsets avl tree.
462  */
463 static int
464 dsl_load_sets(objset_t *mos, uint64_t zapobj,
465     char type, char checkflag, void *valp, avl_tree_t *avl)
466 {
467 	zap_cursor_t zc;
468 	zap_attribute_t za;
469 	perm_set_t *permnode;
470 	avl_index_t idx;
471 	uint64_t jumpobj;
472 	int error;
473 	char whokey[ZFS_MAX_DELEG_NAME];
474 
475 	zfs_deleg_whokey(whokey, type, checkflag, valp);
476 
477 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
478 	if (error != 0)
479 		return (error);
480 
481 	for (zap_cursor_init(&zc, mos, jumpobj);
482 	    zap_cursor_retrieve(&zc, &za) == 0;
483 	    zap_cursor_advance(&zc)) {
484 		permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
485 		(void) strlcpy(permnode->p_setname, za.za_name,
486 		    sizeof (permnode->p_setname));
487 		permnode->p_matched = B_FALSE;
488 
489 		if (avl_find(avl, permnode, &idx) == NULL) {
490 			avl_insert(avl, permnode, idx);
491 		} else {
492 			kmem_free(permnode, sizeof (perm_set_t));
493 		}
494 	}
495 	zap_cursor_fini(&zc);
496 	return (0);
497 }
498 
499 /*
500  * Load all permissions user based on cred belongs to.
501  */
502 static void
503 dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
504     char checkflag, cred_t *cr)
505 {
506 	const	gid_t *gids;
507 	int	ngids, i;
508 	uint64_t id;
509 
510 	id = crgetuid(cr);
511 	(void) dsl_load_sets(mos, zapobj,
512 	    ZFS_DELEG_USER_SETS, checkflag, &id, avl);
513 
514 	id = crgetgid(cr);
515 	(void) dsl_load_sets(mos, zapobj,
516 	    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
517 
518 	(void) dsl_load_sets(mos, zapobj,
519 	    ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
520 
521 	ngids = crgetngroups(cr);
522 	gids = crgetgroups(cr);
523 	for (i = 0; i != ngids; i++) {
524 		id = gids[i];
525 		(void) dsl_load_sets(mos, zapobj,
526 		    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
527 	}
528 }
529 
530 /*
531  * Check if user has requested permission.
532  */
533 int
534 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
535 {
536 	dsl_dataset_t *ds;
537 	dsl_dir_t *dd;
538 	dsl_pool_t *dp;
539 	void *cookie;
540 	int	error;
541 	char	checkflag;
542 	objset_t *mos;
543 	avl_tree_t permsets;
544 	perm_set_t *setnode;
545 
546 	error = dsl_dataset_hold(dsname, FTAG, &ds);
547 	if (error)
548 		return (error);
549 
550 	dp = ds->ds_dir->dd_pool;
551 	mos = dp->dp_meta_objset;
552 
553 	if (dsl_delegation_on(mos) == B_FALSE) {
554 		dsl_dataset_rele(ds, FTAG);
555 		return (ECANCELED);
556 	}
557 
558 	if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
559 	    SPA_VERSION_DELEGATED_PERMS) {
560 		dsl_dataset_rele(ds, FTAG);
561 		return (EPERM);
562 	}
563 
564 	if (dsl_dataset_is_snapshot(ds)) {
565 		/*
566 		 * Snapshots are treated as descendents only,
567 		 * local permissions do not apply.
568 		 */
569 		checkflag = ZFS_DELEG_DESCENDENT;
570 	} else {
571 		checkflag = ZFS_DELEG_LOCAL;
572 	}
573 
574 	avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
575 	    offsetof(perm_set_t, p_node));
576 
577 	rw_enter(&dp->dp_config_rwlock, RW_READER);
578 	for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
579 	    checkflag = ZFS_DELEG_DESCENDENT) {
580 		uint64_t zapobj;
581 		boolean_t expanded;
582 
583 		/*
584 		 * If not in global zone then make sure
585 		 * the zoned property is set
586 		 */
587 		if (!INGLOBALZONE(curproc)) {
588 			uint64_t zoned;
589 
590 			if (dsl_prop_get_dd(dd,
591 			    zfs_prop_to_name(ZFS_PROP_ZONED),
592 			    8, 1, &zoned, NULL) != 0)
593 				break;
594 			if (!zoned)
595 				break;
596 		}
597 		zapobj = dd->dd_phys->dd_deleg_zapobj;
598 
599 		if (zapobj == 0)
600 			continue;
601 
602 		dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
603 again:
604 		expanded = B_FALSE;
605 		for (setnode = avl_first(&permsets); setnode;
606 		    setnode = AVL_NEXT(&permsets, setnode)) {
607 			if (setnode->p_matched == B_TRUE)
608 				continue;
609 
610 			/* See if this set directly grants this permission */
611 			error = dsl_check_access(mos, zapobj,
612 			    ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
613 			if (error == 0)
614 				goto success;
615 			if (error == EPERM)
616 				setnode->p_matched = B_TRUE;
617 
618 			/* See if this set includes other sets */
619 			error = dsl_load_sets(mos, zapobj,
620 			    ZFS_DELEG_NAMED_SET_SETS, 0,
621 			    setnode->p_setname, &permsets);
622 			if (error == 0)
623 				setnode->p_matched = expanded = B_TRUE;
624 		}
625 		/*
626 		 * If we expanded any sets, that will define more sets,
627 		 * which we need to check.
628 		 */
629 		if (expanded)
630 			goto again;
631 
632 		error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
633 		if (error == 0)
634 			goto success;
635 	}
636 	error = EPERM;
637 success:
638 	rw_exit(&dp->dp_config_rwlock);
639 	dsl_dataset_rele(ds, FTAG);
640 
641 	cookie = NULL;
642 	while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
643 		kmem_free(setnode, sizeof (perm_set_t));
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 (os->os_spa->spa_delegation);
743 }
744