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 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  */
     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, 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 
    194 static void
    195 dsl_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 
    247 int
    248 dsl_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  */
    293 int
    294 dsl_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  */
    367 typedef 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 
    373 static int
    374 perm_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  */
    396 static int
    397 dsl_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  */
    417 static int
    418 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
    419     int checkflag, cred_t *cr)
    420 {
    421 	const	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  */
    461 static int
    462 dsl_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  */
    500 static void
    501 dsl_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  */
    531 int
    532 dsl_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);
    601 again:
    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;
    635 success:
    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 
    650 static void
    651 copy_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  */
    696 void
    697 dsl_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 
    717 int
    718 dsl_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 
    737 boolean_t
    738 dsl_delegation_on(objset_t *os)
    739 {
    740 	return (!!spa_delegation(os->os_spa));
    741 }
    742