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