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