Home | History | Annotate | Line # | 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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
     23  * Copyright (c) 2011, 2015 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 (SET_ERROR(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 (SET_ERROR(EPERM));
    143 
    144 		if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
    145 			return (SET_ERROR(EPERM));
    146 	}
    147 	return (0);
    148 }
    149 
    150 typedef struct dsl_deleg_arg {
    151 	const char *dda_name;
    152 	nvlist_t *dda_nvlist;
    153 } dsl_deleg_arg_t;
    154 
    155 static void
    156 dsl_deleg_set_sync(void *arg, dmu_tx_t *tx)
    157 {
    158 	dsl_deleg_arg_t *dda = arg;
    159 	dsl_dir_t *dd;
    160 	dsl_pool_t *dp = dmu_tx_pool(tx);
    161 	objset_t *mos = dp->dp_meta_objset;
    162 	nvpair_t *whopair = NULL;
    163 	uint64_t zapobj;
    164 
    165 	VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
    166 
    167 	zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
    168 	if (zapobj == 0) {
    169 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
    170 		zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
    171 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
    172 	}
    173 
    174 	while (whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair)) {
    175 		const char *whokey = nvpair_name(whopair);
    176 		nvlist_t *perms;
    177 		nvpair_t *permpair = NULL;
    178 		uint64_t jumpobj;
    179 
    180 		perms = fnvpair_value_nvlist(whopair);
    181 
    182 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
    183 			jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
    184 			    zapobj, whokey, tx);
    185 		}
    186 
    187 		while (permpair = nvlist_next_nvpair(perms, permpair)) {
    188 			const char *perm = nvpair_name(permpair);
    189 			uint64_t n = 0;
    190 
    191 			VERIFY(zap_update(mos, jumpobj,
    192 			    perm, 8, 1, &n, tx) == 0);
    193 			spa_history_log_internal_dd(dd, "permission update", tx,
    194 			    "%s %s", whokey, perm);
    195 		}
    196 	}
    197 	dsl_dir_rele(dd, FTAG);
    198 }
    199 
    200 static void
    201 dsl_deleg_unset_sync(void *arg, dmu_tx_t *tx)
    202 {
    203 	dsl_deleg_arg_t *dda = arg;
    204 	dsl_dir_t *dd;
    205 	dsl_pool_t *dp = dmu_tx_pool(tx);
    206 	objset_t *mos = dp->dp_meta_objset;
    207 	nvpair_t *whopair = NULL;
    208 	uint64_t zapobj;
    209 
    210 	VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
    211 	zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
    212 	if (zapobj == 0) {
    213 		dsl_dir_rele(dd, FTAG);
    214 		return;
    215 	}
    216 
    217 	while (whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair)) {
    218 		const char *whokey = nvpair_name(whopair);
    219 		nvlist_t *perms;
    220 		nvpair_t *permpair = NULL;
    221 		uint64_t jumpobj;
    222 
    223 		if (nvpair_value_nvlist(whopair, &perms) != 0) {
    224 			if (zap_lookup(mos, zapobj, whokey, 8,
    225 			    1, &jumpobj) == 0) {
    226 				(void) zap_remove(mos, zapobj, whokey, tx);
    227 				VERIFY(0 == zap_destroy(mos, jumpobj, tx));
    228 			}
    229 			spa_history_log_internal_dd(dd, "permission who remove",
    230 			    tx, "%s", whokey);
    231 			continue;
    232 		}
    233 
    234 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
    235 			continue;
    236 
    237 		while (permpair = nvlist_next_nvpair(perms, permpair)) {
    238 			const char *perm = nvpair_name(permpair);
    239 			uint64_t n = 0;
    240 
    241 			(void) zap_remove(mos, jumpobj, perm, tx);
    242 			if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
    243 				(void) zap_remove(mos, zapobj,
    244 				    whokey, tx);
    245 				VERIFY(0 == zap_destroy(mos,
    246 				    jumpobj, tx));
    247 			}
    248 			spa_history_log_internal_dd(dd, "permission remove", tx,
    249 			    "%s %s", whokey, perm);
    250 		}
    251 	}
    252 	dsl_dir_rele(dd, FTAG);
    253 }
    254 
    255 static int
    256 dsl_deleg_check(void *arg, dmu_tx_t *tx)
    257 {
    258 	dsl_deleg_arg_t *dda = arg;
    259 	dsl_dir_t *dd;
    260 	int error;
    261 
    262 	if (spa_version(dmu_tx_pool(tx)->dp_spa) <
    263 	    SPA_VERSION_DELEGATED_PERMS) {
    264 		return (SET_ERROR(ENOTSUP));
    265 	}
    266 
    267 	error = dsl_dir_hold(dmu_tx_pool(tx), dda->dda_name, FTAG, &dd, NULL);
    268 	if (error == 0)
    269 		dsl_dir_rele(dd, FTAG);
    270 	return (error);
    271 }
    272 
    273 int
    274 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
    275 {
    276 	dsl_deleg_arg_t dda;
    277 
    278 	/* nvp must already have been verified to be valid */
    279 
    280 	dda.dda_name = ddname;
    281 	dda.dda_nvlist = nvp;
    282 
    283 	return (dsl_sync_task(ddname, dsl_deleg_check,
    284 	    unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
    285 	    &dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
    286 }
    287 
    288 /*
    289  * Find all 'allow' permissions from a given point and then continue
    290  * traversing up to the root.
    291  *
    292  * This function constructs an nvlist of nvlists.
    293  * each setpoint is an nvlist composed of an nvlist of an nvlist
    294  * of the individual * users/groups/everyone/create
    295  * permissions.
    296  *
    297  * The nvlist will look like this.
    298  *
    299  * { source fsname -> { whokeys { permissions,...}, ...}}
    300  *
    301  * The fsname nvpairs will be arranged in a bottom up order.  For example,
    302  * if we have the following structure a/b/c then the nvpairs for the fsnames
    303  * will be ordered a/b/c, a/b, a.
    304  */
    305 int
    306 dsl_deleg_get(const char *ddname, nvlist_t **nvp)
    307 {
    308 	dsl_dir_t *dd, *startdd;
    309 	dsl_pool_t *dp;
    310 	int error;
    311 	objset_t *mos;
    312 
    313 	error = dsl_pool_hold(ddname, FTAG, &dp);
    314 	if (error != 0)
    315 		return (error);
    316 
    317 	error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
    318 	if (error != 0) {
    319 		dsl_pool_rele(dp, FTAG);
    320 		return (error);
    321 	}
    322 
    323 	dp = startdd->dd_pool;
    324 	mos = dp->dp_meta_objset;
    325 
    326 	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
    327 
    328 	for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
    329 		zap_cursor_t basezc;
    330 		zap_attribute_t baseza;
    331 		nvlist_t *sp_nvp;
    332 		uint64_t n;
    333 		char source[ZFS_MAX_DATASET_NAME_LEN];
    334 
    335 		if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
    336 		    zap_count(mos,
    337 		    dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
    338 			continue;
    339 
    340 		sp_nvp = fnvlist_alloc();
    341 		for (zap_cursor_init(&basezc, mos,
    342 		    dsl_dir_phys(dd)->dd_deleg_zapobj);
    343 		    zap_cursor_retrieve(&basezc, &baseza) == 0;
    344 		    zap_cursor_advance(&basezc)) {
    345 			zap_cursor_t zc;
    346 			zap_attribute_t za;
    347 			nvlist_t *perms_nvp;
    348 
    349 			ASSERT(baseza.za_integer_length == 8);
    350 			ASSERT(baseza.za_num_integers == 1);
    351 
    352 			perms_nvp = fnvlist_alloc();
    353 			for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
    354 			    zap_cursor_retrieve(&zc, &za) == 0;
    355 			    zap_cursor_advance(&zc)) {
    356 				fnvlist_add_boolean(perms_nvp, za.za_name);
    357 			}
    358 			zap_cursor_fini(&zc);
    359 			fnvlist_add_nvlist(sp_nvp, baseza.za_name, perms_nvp);
    360 			fnvlist_free(perms_nvp);
    361 		}
    362 
    363 		zap_cursor_fini(&basezc);
    364 
    365 		dsl_dir_name(dd, source);
    366 		fnvlist_add_nvlist(*nvp, source, sp_nvp);
    367 		nvlist_free(sp_nvp);
    368 	}
    369 
    370 	dsl_dir_rele(startdd, FTAG);
    371 	dsl_pool_rele(dp, FTAG);
    372 	return (0);
    373 }
    374 
    375 /*
    376  * Routines for dsl_deleg_access() -- access checking.
    377  */
    378 typedef struct perm_set {
    379 	avl_node_t	p_node;
    380 	boolean_t	p_matched;
    381 	char		p_setname[ZFS_MAX_DELEG_NAME];
    382 } perm_set_t;
    383 
    384 static int
    385 perm_set_compare(const void *arg1, const void *arg2)
    386 {
    387 	const perm_set_t *node1 = arg1;
    388 	const perm_set_t *node2 = arg2;
    389 	int val;
    390 
    391 	val = strcmp(node1->p_setname, node2->p_setname);
    392 	if (val == 0)
    393 		return (0);
    394 	return (val > 0 ? 1 : -1);
    395 }
    396 
    397 /*
    398  * Determine whether a specified permission exists.
    399  *
    400  * First the base attribute has to be retrieved.  i.e. ul$12
    401  * Once the base object has been retrieved the actual permission
    402  * is lookup up in the zap object the base object points to.
    403  *
    404  * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
    405  * there is no perm in that jumpobj.
    406  */
    407 static int
    408 dsl_check_access(objset_t *mos, uint64_t zapobj,
    409     char type, char checkflag, void *valp, const char *perm)
    410 {
    411 	int error;
    412 	uint64_t jumpobj, zero;
    413 	char whokey[ZFS_MAX_DELEG_NAME];
    414 
    415 	zfs_deleg_whokey(whokey, type, checkflag, valp);
    416 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
    417 	if (error == 0) {
    418 		error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
    419 		if (error == ENOENT)
    420 			error = SET_ERROR(EPERM);
    421 	}
    422 	return (error);
    423 }
    424 
    425 /*
    426  * check a specified user/group for a requested permission
    427  */
    428 static int
    429 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
    430     int checkflag, cred_t *cr)
    431 {
    432 	const	gid_t *gids;
    433 	int	ngids;
    434 	int	i;
    435 	uint64_t id;
    436 
    437 	/* check for user */
    438 	id = crgetuid(cr);
    439 	if (dsl_check_access(mos, zapobj,
    440 	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
    441 		return (0);
    442 
    443 	/* check for users primary group */
    444 	id = crgetgid(cr);
    445 	if (dsl_check_access(mos, zapobj,
    446 	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
    447 		return (0);
    448 
    449 	/* check for everyone entry */
    450 	id = -1;
    451 	if (dsl_check_access(mos, zapobj,
    452 	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
    453 		return (0);
    454 
    455 	/* check each supplemental group user is a member of */
    456 	ngids = crgetngroups(cr);
    457 	gids = crgetgroups(cr);
    458 	for (i = 0; i != ngids; i++) {
    459 		id = gids[i];
    460 		if (dsl_check_access(mos, zapobj,
    461 		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
    462 			return (0);
    463 	}
    464 
    465 	return (SET_ERROR(EPERM));
    466 }
    467 
    468 /*
    469  * Iterate over the sets specified in the specified zapobj
    470  * and load them into the permsets avl tree.
    471  */
    472 static int
    473 dsl_load_sets(objset_t *mos, uint64_t zapobj,
    474     char type, char checkflag, void *valp, avl_tree_t *avl)
    475 {
    476 	zap_cursor_t zc;
    477 	zap_attribute_t za;
    478 	perm_set_t *permnode;
    479 	avl_index_t idx;
    480 	uint64_t jumpobj;
    481 	int error;
    482 	char whokey[ZFS_MAX_DELEG_NAME];
    483 
    484 	zfs_deleg_whokey(whokey, type, checkflag, valp);
    485 
    486 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
    487 	if (error != 0)
    488 		return (error);
    489 
    490 	for (zap_cursor_init(&zc, mos, jumpobj);
    491 	    zap_cursor_retrieve(&zc, &za) == 0;
    492 	    zap_cursor_advance(&zc)) {
    493 		permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
    494 		(void) strlcpy(permnode->p_setname, za.za_name,
    495 		    sizeof (permnode->p_setname));
    496 		permnode->p_matched = B_FALSE;
    497 
    498 		if (avl_find(avl, permnode, &idx) == NULL) {
    499 			avl_insert(avl, permnode, idx);
    500 		} else {
    501 			kmem_free(permnode, sizeof (perm_set_t));
    502 		}
    503 	}
    504 	zap_cursor_fini(&zc);
    505 	return (0);
    506 }
    507 
    508 /*
    509  * Load all permissions user based on cred belongs to.
    510  */
    511 static void
    512 dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
    513     char checkflag, cred_t *cr)
    514 {
    515 	const	gid_t *gids;
    516 	int	ngids, i;
    517 	uint64_t id;
    518 
    519 	id = crgetuid(cr);
    520 	(void) dsl_load_sets(mos, zapobj,
    521 	    ZFS_DELEG_USER_SETS, checkflag, &id, avl);
    522 
    523 	id = crgetgid(cr);
    524 	(void) dsl_load_sets(mos, zapobj,
    525 	    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
    526 
    527 	(void) dsl_load_sets(mos, zapobj,
    528 	    ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
    529 
    530 	ngids = crgetngroups(cr);
    531 	gids = crgetgroups(cr);
    532 	for (i = 0; i != ngids; i++) {
    533 		id = gids[i];
    534 		(void) dsl_load_sets(mos, zapobj,
    535 		    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
    536 	}
    537 }
    538 
    539 /*
    540  * Check if user has requested permission.
    541  */
    542 int
    543 dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
    544 {
    545 	dsl_dir_t *dd;
    546 	dsl_pool_t *dp;
    547 	void *cookie;
    548 	int	error;
    549 	char	checkflag;
    550 	objset_t *mos;
    551 	avl_tree_t permsets;
    552 	perm_set_t *setnode;
    553 
    554 	dp = ds->ds_dir->dd_pool;
    555 	mos = dp->dp_meta_objset;
    556 
    557 	if (dsl_delegation_on(mos) == B_FALSE)
    558 		return (SET_ERROR(ECANCELED));
    559 
    560 	if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
    561 	    SPA_VERSION_DELEGATED_PERMS)
    562 		return (SET_ERROR(EPERM));
    563 
    564 	if (ds->ds_is_snapshot) {
    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 	ASSERT(dsl_pool_config_held(dp));
    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(curthread)) {
    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, B_FALSE) != 0)
    593 				break;
    594 			if (!zoned)
    595 				break;
    596 		}
    597 		zapobj = dsl_dir_phys(dd)->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 = SET_ERROR(EPERM);
    637 success:
    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 int
    647 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
    648 {
    649 	dsl_pool_t *dp;
    650 	dsl_dataset_t *ds;
    651 	int error;
    652 
    653 	error = dsl_pool_hold(dsname, FTAG, &dp);
    654 	if (error != 0)
    655 		return (error);
    656 	error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
    657 	if (error == 0) {
    658 		error = dsl_deleg_access_impl(ds, perm, cr);
    659 		dsl_dataset_rele(ds, FTAG);
    660 	}
    661 	dsl_pool_rele(dp, FTAG);
    662 
    663 	return (error);
    664 }
    665 
    666 /*
    667  * Other routines.
    668  */
    669 
    670 static void
    671 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
    672     boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
    673 {
    674 	objset_t *mos = dd->dd_pool->dp_meta_objset;
    675 	uint64_t jumpobj, pjumpobj;
    676 	uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
    677 	zap_cursor_t zc;
    678 	zap_attribute_t za;
    679 	char whokey[ZFS_MAX_DELEG_NAME];
    680 
    681 	zfs_deleg_whokey(whokey,
    682 	    dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
    683 	    ZFS_DELEG_LOCAL, NULL);
    684 	if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
    685 		return;
    686 
    687 	if (zapobj == 0) {
    688 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
    689 		zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
    690 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
    691 	}
    692 
    693 	zfs_deleg_whokey(whokey,
    694 	    dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
    695 	    ZFS_DELEG_LOCAL, &uid);
    696 	if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
    697 		jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
    698 		VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
    699 	}
    700 
    701 	for (zap_cursor_init(&zc, mos, pjumpobj);
    702 	    zap_cursor_retrieve(&zc, &za) == 0;
    703 	    zap_cursor_advance(&zc)) {
    704 		uint64_t zero = 0;
    705 		ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
    706 
    707 		VERIFY(zap_update(mos, jumpobj, za.za_name,
    708 		    8, 1, &zero, tx) == 0);
    709 	}
    710 	zap_cursor_fini(&zc);
    711 }
    712 
    713 /*
    714  * set all create time permission on new dataset.
    715  */
    716 void
    717 dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
    718 {
    719 	dsl_dir_t *dd;
    720 	uint64_t uid = crgetuid(cr);
    721 
    722 	if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
    723 	    SPA_VERSION_DELEGATED_PERMS)
    724 		return;
    725 
    726 	for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
    727 		uint64_t pzapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
    728 
    729 		if (pzapobj == 0)
    730 			continue;
    731 
    732 		copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
    733 		copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
    734 	}
    735 }
    736 
    737 int
    738 dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
    739 {
    740 	zap_cursor_t zc;
    741 	zap_attribute_t za;
    742 
    743 	if (zapobj == 0)
    744 		return (0);
    745 
    746 	for (zap_cursor_init(&zc, mos, zapobj);
    747 	    zap_cursor_retrieve(&zc, &za) == 0;
    748 	    zap_cursor_advance(&zc)) {
    749 		ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
    750 		VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx));
    751 	}
    752 	zap_cursor_fini(&zc);
    753 	VERIFY(0 == zap_destroy(mos, zapobj, tx));
    754 	return (0);
    755 }
    756 
    757 boolean_t
    758 dsl_delegation_on(objset_t *os)
    759 {
    760 	return (!!spa_delegation(os->os_spa));
    761 }
    762