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