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