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