xref: /freebsd/sys/contrib/openzfs/module/zfs/dsl_deleg.c (revision 22649d4dba730d46244fd2dff4fd174903c8379f)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * This file and its contents are supplied under the terms of the
4  * Common Development and Distribution License ("CDDL"), version 1.0.
5  * You may only use this file in accordance with the terms of version
6  * 1.0 of the CDDL.
7  *
8  * A full copy of the text of the CDDL should have accompanied this
9  * source.  A copy of the CDDL is also available via the Internet at
10  * https://opensource.org/license/CDDL-1.0.
11  */
12 /*
13  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
14  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
15  */
16 
17 /*
18  * DSL permissions are stored in a two level zap attribute
19  * mechanism.   The first level identifies the "class" of
20  * entry.  The class is identified by the first 2 letters of
21  * the attribute.  The second letter "l" or "d" identifies whether
22  * it is a local or descendent permission.  The first letter
23  * identifies the type of entry.
24  *
25  * ul$<id>    identifies permissions granted locally for this userid.
26  * ud$<id>    identifies permissions granted on descendent datasets for
27  *            this userid.
28  * Ul$<id>    identifies permission sets granted locally for this userid.
29  * Ud$<id>    identifies permission sets granted on descendent datasets for
30  *            this userid.
31  * gl$<id>    identifies permissions granted locally for this groupid.
32  * gd$<id>    identifies permissions granted on descendent datasets for
33  *            this groupid.
34  * Gl$<id>    identifies permission sets granted locally for this groupid.
35  * Gd$<id>    identifies permission sets granted on descendent datasets for
36  *            this groupid.
37  * el$        identifies permissions granted locally for everyone.
38  * ed$        identifies permissions granted on descendent datasets
39  *            for everyone.
40  * El$        identifies permission sets granted locally for everyone.
41  * Ed$        identifies permission sets granted to descendent datasets for
42  *            everyone.
43  * c-$        identifies permission to create at dataset creation time.
44  * C-$        identifies permission sets to grant locally at dataset creation
45  *            time.
46  * s-$@<name> permissions defined in specified set @<name>
47  * S-$@<name> Sets defined in named set @<name>
48  *
49  * Each of the above entities points to another zap attribute that contains one
50  * attribute for each allowed permission, such as create, destroy,...
51  * All of the "upper" case class types will specify permission set names
52  * rather than permissions.
53  *
54  * Basically it looks something like this:
55  * ul$12 -> ZAP OBJ -> permissions...
56  *
57  * The ZAP OBJ is referred to as the jump object.
58  */
59 
60 #include <sys/dmu.h>
61 #include <sys/dmu_objset.h>
62 #include <sys/dmu_tx.h>
63 #include <sys/dsl_dataset.h>
64 #include <sys/dsl_dir.h>
65 #include <sys/dsl_prop.h>
66 #include <sys/dsl_synctask.h>
67 #include <sys/dsl_deleg.h>
68 #include <sys/spa.h>
69 #include <sys/zap.h>
70 #include <sys/fs/zfs.h>
71 #include <sys/cred.h>
72 #include <sys/sunddi.h>
73 
74 #include "zfs_deleg.h"
75 
76 /*
77  * Validate that user is allowed to delegate specified permissions.
78  *
79  * In order to delegate "create" you must have "create"
80  * and "allow".
81  */
82 int
dsl_deleg_can_allow(char * ddname,nvlist_t * nvp,cred_t * cr)83 dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
84 {
85 	nvpair_t *whopair = NULL;
86 	int error;
87 
88 	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
89 		return (error);
90 
91 	while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
92 		nvlist_t *perms;
93 		nvpair_t *permpair = NULL;
94 
95 		VERIFY0(nvpair_value_nvlist(whopair, &perms));
96 
97 		while ((permpair = nvlist_next_nvpair(perms, permpair))) {
98 			const char *perm = nvpair_name(permpair);
99 
100 			if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
101 				return (SET_ERROR(EPERM));
102 
103 			if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
104 				return (error);
105 		}
106 	}
107 	return (0);
108 }
109 
110 /*
111  * Validate that user is allowed to unallow specified permissions.  They
112  * must have the 'allow' permission, and even then can only unallow
113  * perms for their uid.
114  */
115 int
dsl_deleg_can_unallow(char * ddname,nvlist_t * nvp,cred_t * cr)116 dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
117 {
118 	nvpair_t *whopair = NULL;
119 	int error;
120 	char idstr[32];
121 
122 	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
123 		return (error);
124 
125 	(void) snprintf(idstr, sizeof (idstr), "%lld",
126 	    (longlong_t)crgetuid(cr));
127 
128 	while ((whopair = nvlist_next_nvpair(nvp, whopair))) {
129 		zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
130 
131 		if (type != ZFS_DELEG_USER &&
132 		    type != ZFS_DELEG_USER_SETS)
133 			return (SET_ERROR(EPERM));
134 
135 		if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
136 			return (SET_ERROR(EPERM));
137 	}
138 	return (0);
139 }
140 
141 typedef struct dsl_deleg_arg {
142 	const char *dda_name;
143 	nvlist_t *dda_nvlist;
144 } dsl_deleg_arg_t;
145 
146 static void
dsl_deleg_set_sync(void * arg,dmu_tx_t * tx)147 dsl_deleg_set_sync(void *arg, dmu_tx_t *tx)
148 {
149 	dsl_deleg_arg_t *dda = arg;
150 	dsl_dir_t *dd;
151 	dsl_pool_t *dp = dmu_tx_pool(tx);
152 	objset_t *mos = dp->dp_meta_objset;
153 	nvpair_t *whopair = NULL;
154 	uint64_t zapobj;
155 
156 	VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
157 
158 	zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
159 	if (zapobj == 0) {
160 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
161 		zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
162 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
163 	}
164 
165 	while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) {
166 		const char *whokey = nvpair_name(whopair);
167 		nvlist_t *perms;
168 		nvpair_t *permpair = NULL;
169 		uint64_t jumpobj;
170 
171 		perms = fnvpair_value_nvlist(whopair);
172 
173 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
174 			jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
175 			    zapobj, whokey, tx);
176 		}
177 
178 		while ((permpair = nvlist_next_nvpair(perms, permpair))) {
179 			const char *perm = nvpair_name(permpair);
180 			uint64_t n = 0;
181 
182 			VERIFY0(zap_update(mos, jumpobj, perm, 8, 1, &n, tx));
183 			spa_history_log_internal_dd(dd, "permission update", tx,
184 			    "%s %s", whokey, perm);
185 		}
186 	}
187 	dsl_dir_rele(dd, FTAG);
188 }
189 
190 static void
dsl_deleg_unset_sync(void * arg,dmu_tx_t * tx)191 dsl_deleg_unset_sync(void *arg, dmu_tx_t *tx)
192 {
193 	dsl_deleg_arg_t *dda = arg;
194 	dsl_dir_t *dd;
195 	dsl_pool_t *dp = dmu_tx_pool(tx);
196 	objset_t *mos = dp->dp_meta_objset;
197 	nvpair_t *whopair = NULL;
198 	uint64_t zapobj;
199 
200 	VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
201 	zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
202 	if (zapobj == 0) {
203 		dsl_dir_rele(dd, FTAG);
204 		return;
205 	}
206 
207 	while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) {
208 		const char *whokey = nvpair_name(whopair);
209 		nvlist_t *perms;
210 		nvpair_t *permpair = NULL;
211 		uint64_t jumpobj;
212 
213 		if (nvpair_value_nvlist(whopair, &perms) != 0) {
214 			if (zap_lookup(mos, zapobj, whokey, 8,
215 			    1, &jumpobj) == 0) {
216 				(void) zap_remove(mos, zapobj, whokey, tx);
217 				VERIFY0(zap_destroy(mos, jumpobj, tx));
218 			}
219 			spa_history_log_internal_dd(dd, "permission who remove",
220 			    tx, "%s", whokey);
221 			continue;
222 		}
223 
224 		if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
225 			continue;
226 
227 		while ((permpair = nvlist_next_nvpair(perms, permpair))) {
228 			const char *perm = nvpair_name(permpair);
229 			uint64_t n = 0;
230 
231 			(void) zap_remove(mos, jumpobj, perm, tx);
232 			if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
233 				(void) zap_remove(mos, zapobj,
234 				    whokey, tx);
235 				VERIFY0(zap_destroy(mos,
236 				    jumpobj, tx));
237 			}
238 			spa_history_log_internal_dd(dd, "permission remove", tx,
239 			    "%s %s", whokey, perm);
240 		}
241 	}
242 	dsl_dir_rele(dd, FTAG);
243 }
244 
245 static int
dsl_deleg_check(void * arg,dmu_tx_t * tx)246 dsl_deleg_check(void *arg, dmu_tx_t *tx)
247 {
248 	dsl_deleg_arg_t *dda = arg;
249 	dsl_dir_t *dd;
250 	int error;
251 
252 	if (spa_version(dmu_tx_pool(tx)->dp_spa) <
253 	    SPA_VERSION_DELEGATED_PERMS) {
254 		return (SET_ERROR(ENOTSUP));
255 	}
256 
257 	error = dsl_dir_hold(dmu_tx_pool(tx), dda->dda_name, FTAG, &dd, NULL);
258 	if (error == 0)
259 		dsl_dir_rele(dd, FTAG);
260 	return (error);
261 }
262 
263 int
dsl_deleg_set(const char * ddname,nvlist_t * nvp,boolean_t unset)264 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
265 {
266 	dsl_deleg_arg_t dda;
267 
268 	/* nvp must already have been verified to be valid */
269 
270 	dda.dda_name = ddname;
271 	dda.dda_nvlist = nvp;
272 
273 	return (dsl_sync_task(ddname, dsl_deleg_check,
274 	    unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
275 	    &dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
276 }
277 
278 /*
279  * Find all 'allow' permissions from a given point and then continue
280  * traversing up to the root.
281  *
282  * This function constructs an nvlist of nvlists.
283  * each setpoint is an nvlist composed of an nvlist of an nvlist
284  * of the individual * users/groups/everyone/create
285  * permissions.
286  *
287  * The nvlist will look like this.
288  *
289  * { source fsname -> { whokeys { permissions,...}, ...}}
290  *
291  * The fsname nvpairs will be arranged in a bottom up order.  For example,
292  * if we have the following structure a/b/c then the nvpairs for the fsnames
293  * will be ordered a/b/c, a/b, a.
294  */
295 int
dsl_deleg_get(const char * ddname,nvlist_t ** nvp)296 dsl_deleg_get(const char *ddname, nvlist_t **nvp)
297 {
298 	dsl_dir_t *dd, *startdd;
299 	dsl_pool_t *dp;
300 	int error;
301 	objset_t *mos;
302 	zap_cursor_t *basezc, *zc;
303 	zap_attribute_t *baseza, *za;
304 	char *source;
305 
306 	error = dsl_pool_hold(ddname, FTAG, &dp);
307 	if (error != 0)
308 		return (error);
309 
310 	error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
311 	if (error != 0) {
312 		dsl_pool_rele(dp, FTAG);
313 		return (error);
314 	}
315 
316 	dp = startdd->dd_pool;
317 	mos = dp->dp_meta_objset;
318 
319 	zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
320 	za = zap_attribute_alloc();
321 	basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
322 	baseza = zap_attribute_alloc();
323 	source = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
324 	VERIFY0(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP));
325 
326 	for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
327 		nvlist_t *sp_nvp;
328 		uint64_t n;
329 
330 		if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
331 		    zap_count(mos,
332 		    dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
333 			continue;
334 
335 		sp_nvp = fnvlist_alloc();
336 		for (zap_cursor_init(basezc, mos,
337 		    dsl_dir_phys(dd)->dd_deleg_zapobj);
338 		    zap_cursor_retrieve(basezc, baseza) == 0;
339 		    zap_cursor_advance(basezc)) {
340 			nvlist_t *perms_nvp;
341 
342 			ASSERT(baseza->za_integer_length == 8);
343 			ASSERT(baseza->za_num_integers == 1);
344 
345 			perms_nvp = fnvlist_alloc();
346 			for (zap_cursor_init(zc, mos, baseza->za_first_integer);
347 			    zap_cursor_retrieve(zc, za) == 0;
348 			    zap_cursor_advance(zc)) {
349 				fnvlist_add_boolean(perms_nvp, za->za_name);
350 			}
351 			zap_cursor_fini(zc);
352 			fnvlist_add_nvlist(sp_nvp, baseza->za_name, perms_nvp);
353 			fnvlist_free(perms_nvp);
354 		}
355 
356 		zap_cursor_fini(basezc);
357 
358 		dsl_dir_name(dd, source);
359 		fnvlist_add_nvlist(*nvp, source, sp_nvp);
360 		nvlist_free(sp_nvp);
361 	}
362 
363 	kmem_free(source, ZFS_MAX_DATASET_NAME_LEN);
364 	zap_attribute_free(baseza);
365 	kmem_free(basezc, sizeof (zap_cursor_t));
366 	zap_attribute_free(za);
367 	kmem_free(zc, sizeof (zap_cursor_t));
368 
369 	dsl_dir_rele(startdd, FTAG);
370 	dsl_pool_rele(dp, FTAG);
371 	return (0);
372 }
373 
374 /*
375  * Routines for dsl_deleg_access() -- access checking.
376  */
377 typedef struct perm_set {
378 	avl_node_t	p_node;
379 	boolean_t	p_matched;
380 	char		p_setname[ZFS_MAX_DELEG_NAME];
381 } perm_set_t;
382 
383 static int
perm_set_compare(const void * arg1,const void * arg2)384 perm_set_compare(const void *arg1, const void *arg2)
385 {
386 	const perm_set_t *node1 = (const perm_set_t *)arg1;
387 	const perm_set_t *node2 = (const perm_set_t *)arg2;
388 	return (TREE_ISIGN(strcmp(node1->p_setname, node2->p_setname)));
389 }
390 
391 /*
392  * Determine whether a specified permission exists.
393  *
394  * First the base attribute has to be retrieved.  i.e. ul$12
395  * Once the base object has been retrieved the actual permission
396  * is lookup up in the zap object the base object points to.
397  *
398  * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
399  * there is no perm in that jumpobj.
400  */
401 static int
dsl_check_access(objset_t * mos,uint64_t zapobj,char type,char checkflag,void * valp,const char * perm)402 dsl_check_access(objset_t *mos, uint64_t zapobj,
403     char type, char checkflag, void *valp, const char *perm)
404 {
405 	int error;
406 	uint64_t jumpobj, zero;
407 	char whokey[ZFS_MAX_DELEG_NAME];
408 
409 	zfs_deleg_whokey(whokey, type, checkflag, valp);
410 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
411 	if (error == 0) {
412 		error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
413 		if (error == ENOENT)
414 			error = SET_ERROR(EPERM);
415 	}
416 	return (error);
417 }
418 
419 /*
420  * check a specified user/group for a requested permission
421  */
422 static int
dsl_check_user_access(objset_t * mos,uint64_t zapobj,const char * perm,int checkflag,cred_t * cr)423 dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
424     int checkflag, cred_t *cr)
425 {
426 	const	gid_t *gids;
427 	int	ngids;
428 	int	i;
429 	uint64_t id;
430 
431 	/* check for user */
432 	id = crgetuid(cr);
433 	if (dsl_check_access(mos, zapobj,
434 	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
435 		return (0);
436 
437 	/* check for users primary group */
438 	id = crgetgid(cr);
439 	if (dsl_check_access(mos, zapobj,
440 	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
441 		return (0);
442 
443 	/* check for everyone entry */
444 	id = -1;
445 	if (dsl_check_access(mos, zapobj,
446 	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
447 		return (0);
448 
449 	/* check each supplemental group user is a member of */
450 	ngids = crgetngroups(cr);
451 	gids = crgetgroups(cr);
452 	for (i = 0; i != ngids; i++) {
453 		id = gids[i];
454 		if (dsl_check_access(mos, zapobj,
455 		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
456 			return (0);
457 	}
458 
459 	return (SET_ERROR(EPERM));
460 }
461 
462 /*
463  * Iterate over the sets specified in the specified zapobj
464  * and load them into the permsets avl tree.
465  */
466 static int
dsl_load_sets(objset_t * mos,uint64_t zapobj,char type,char checkflag,void * valp,avl_tree_t * avl)467 dsl_load_sets(objset_t *mos, uint64_t zapobj,
468     char type, char checkflag, void *valp, avl_tree_t *avl)
469 {
470 	zap_cursor_t zc;
471 	zap_attribute_t *za;
472 	perm_set_t *permnode;
473 	avl_index_t idx;
474 	uint64_t jumpobj;
475 	int error;
476 	char whokey[ZFS_MAX_DELEG_NAME];
477 
478 	zfs_deleg_whokey(whokey, type, checkflag, valp);
479 
480 	error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
481 	if (error != 0)
482 		return (error);
483 
484 	za = zap_attribute_alloc();
485 	for (zap_cursor_init(&zc, mos, jumpobj);
486 	    zap_cursor_retrieve(&zc, za) == 0;
487 	    zap_cursor_advance(&zc)) {
488 		permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
489 		(void) strlcpy(permnode->p_setname, za->za_name,
490 		    sizeof (permnode->p_setname));
491 		permnode->p_matched = B_FALSE;
492 
493 		if (avl_find(avl, permnode, &idx) == NULL) {
494 			avl_insert(avl, permnode, idx);
495 		} else {
496 			kmem_free(permnode, sizeof (perm_set_t));
497 		}
498 	}
499 	zap_cursor_fini(&zc);
500 	zap_attribute_free(za);
501 	return (0);
502 }
503 
504 /*
505  * Load all permissions user based on cred belongs to.
506  */
507 static void
dsl_load_user_sets(objset_t * mos,uint64_t zapobj,avl_tree_t * avl,char checkflag,cred_t * cr)508 dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
509     char checkflag, cred_t *cr)
510 {
511 	const	gid_t *gids;
512 	int	ngids, i;
513 	uint64_t id;
514 
515 	id = crgetuid(cr);
516 	(void) dsl_load_sets(mos, zapobj,
517 	    ZFS_DELEG_USER_SETS, checkflag, &id, avl);
518 
519 	id = crgetgid(cr);
520 	(void) dsl_load_sets(mos, zapobj,
521 	    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
522 
523 	(void) dsl_load_sets(mos, zapobj,
524 	    ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
525 
526 	ngids = crgetngroups(cr);
527 	gids = crgetgroups(cr);
528 	for (i = 0; i != ngids; i++) {
529 		id = gids[i];
530 		(void) dsl_load_sets(mos, zapobj,
531 		    ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
532 	}
533 }
534 
535 /*
536  * Check if user has requested permission.
537  */
538 int
dsl_deleg_access_impl(dsl_dataset_t * ds,const char * perm,cred_t * cr)539 dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
540 {
541 	dsl_dir_t *dd;
542 	dsl_pool_t *dp;
543 	void *cookie;
544 	int	error;
545 	char	checkflag;
546 	objset_t *mos;
547 	avl_tree_t permsets;
548 	perm_set_t *setnode;
549 
550 	dp = ds->ds_dir->dd_pool;
551 	mos = dp->dp_meta_objset;
552 
553 	if (dsl_delegation_on(mos) == B_FALSE)
554 		return (SET_ERROR(ECANCELED));
555 
556 	if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
557 	    SPA_VERSION_DELEGATED_PERMS)
558 		return (SET_ERROR(EPERM));
559 
560 	if (ds->ds_is_snapshot) {
561 		/*
562 		 * Snapshots are treated as descendents only,
563 		 * local permissions do not apply.
564 		 */
565 		checkflag = ZFS_DELEG_DESCENDENT;
566 	} else {
567 		checkflag = ZFS_DELEG_LOCAL;
568 	}
569 
570 	avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
571 	    offsetof(perm_set_t, p_node));
572 
573 	ASSERT(dsl_pool_config_held(dp));
574 	for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
575 	    checkflag = ZFS_DELEG_DESCENDENT) {
576 		uint64_t zapobj;
577 		boolean_t expanded;
578 
579 		/*
580 		 * If not in global zone then make sure
581 		 * the zoned property is set
582 		 */
583 		if (!INGLOBALZONE(curproc)) {
584 			uint64_t zoned = 0;
585 			uint64_t zoned_uid_val = 0;
586 
587 			(void) dsl_prop_get_dd(dd,
588 			    zfs_prop_to_name(ZFS_PROP_ZONED),
589 			    8, 1, &zoned, NULL, B_FALSE);
590 			(void) dsl_prop_get_dd(dd,
591 			    zfs_prop_to_name(ZFS_PROP_ZONED_UID),
592 			    8, 1, &zoned_uid_val, NULL, B_FALSE);
593 			if (!zoned && zoned_uid_val == 0)
594 				break;
595 		}
596 		zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
597 
598 		if (zapobj == 0)
599 			continue;
600 
601 		dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
602 again:
603 		expanded = B_FALSE;
604 		for (setnode = avl_first(&permsets); setnode;
605 		    setnode = AVL_NEXT(&permsets, setnode)) {
606 			if (setnode->p_matched == B_TRUE)
607 				continue;
608 
609 			/* See if this set directly grants this permission */
610 			error = dsl_check_access(mos, zapobj,
611 			    ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
612 			if (error == 0)
613 				goto success;
614 			if (error == EPERM)
615 				setnode->p_matched = B_TRUE;
616 
617 			/* See if this set includes other sets */
618 			error = dsl_load_sets(mos, zapobj,
619 			    ZFS_DELEG_NAMED_SET_SETS, 0,
620 			    setnode->p_setname, &permsets);
621 			if (error == 0)
622 				setnode->p_matched = expanded = B_TRUE;
623 		}
624 		/*
625 		 * If we expanded any sets, that will define more sets,
626 		 * which we need to check.
627 		 */
628 		if (expanded)
629 			goto again;
630 
631 		error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
632 		if (error == 0)
633 			goto success;
634 	}
635 	error = SET_ERROR(EPERM);
636 success:
637 
638 	cookie = NULL;
639 	while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
640 		kmem_free(setnode, sizeof (perm_set_t));
641 
642 	return (error);
643 }
644 
645 int
dsl_deleg_access(const char * dsname,const char * perm,cred_t * cr)646 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
647 {
648 	dsl_pool_t *dp;
649 	dsl_dataset_t *ds;
650 	int error;
651 
652 	error = dsl_pool_hold(dsname, FTAG, &dp);
653 	if (error != 0)
654 		return (error);
655 	error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
656 	if (error == 0) {
657 		error = dsl_deleg_access_impl(ds, perm, cr);
658 		dsl_dataset_rele(ds, FTAG);
659 	}
660 	dsl_pool_rele(dp, FTAG);
661 
662 	return (error);
663 }
664 
665 /*
666  * Other routines.
667  */
668 
669 static void
copy_create_perms(dsl_dir_t * dd,uint64_t pzapobj,boolean_t dosets,uint64_t uid,dmu_tx_t * tx)670 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
671     boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
672 {
673 	objset_t *mos = dd->dd_pool->dp_meta_objset;
674 	uint64_t jumpobj, pjumpobj;
675 	uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
676 	zap_cursor_t zc;
677 	zap_attribute_t *za;
678 	char whokey[ZFS_MAX_DELEG_NAME];
679 
680 	zfs_deleg_whokey(whokey,
681 	    dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
682 	    ZFS_DELEG_LOCAL, NULL);
683 	if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
684 		return;
685 
686 	if (zapobj == 0) {
687 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
688 		zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
689 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
690 	}
691 
692 	zfs_deleg_whokey(whokey,
693 	    dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
694 	    ZFS_DELEG_LOCAL, &uid);
695 	if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
696 		jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
697 		VERIFY0(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx));
698 	}
699 
700 	za = zap_attribute_alloc();
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 		VERIFY0(zap_update(mos, jumpobj, za->za_name, 8, 1, &zero, tx));
708 	}
709 	zap_cursor_fini(&zc);
710 	zap_attribute_free(za);
711 }
712 
713 /*
714  * set all create time permission on new dataset.
715  */
716 void
dsl_deleg_set_create_perms(dsl_dir_t * sdd,dmu_tx_t * tx,cred_t * cr)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
dsl_deleg_destroy(objset_t * mos,uint64_t zapobj,dmu_tx_t * tx)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 	za = zap_attribute_alloc();
747 	for (zap_cursor_init(&zc, mos, zapobj);
748 	    zap_cursor_retrieve(&zc, za) == 0;
749 	    zap_cursor_advance(&zc)) {
750 		ASSERT(za->za_integer_length == 8 && za->za_num_integers == 1);
751 		VERIFY0(zap_destroy(mos, za->za_first_integer, tx));
752 	}
753 	zap_cursor_fini(&zc);
754 	VERIFY0(zap_destroy(mos, zapobj, tx));
755 	zap_attribute_free(za);
756 	return (0);
757 }
758 
759 boolean_t
dsl_delegation_on(objset_t * os)760 dsl_delegation_on(objset_t *os)
761 {
762 	return (!!spa_delegation(os->os_spa));
763 }
764 
765 #if defined(_KERNEL)
766 EXPORT_SYMBOL(dsl_deleg_get);
767 EXPORT_SYMBOL(dsl_deleg_set);
768 #endif
769