Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/module/zfs/dsl_deleg.c
48383 views
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
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
VERIFY0(nvpair_value_nvlist(whopair, &perms));
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
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
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
VERIFY0(zap_update(mos, jumpobj, perm, 8, 1, &n, tx));
193
spa_history_log_internal_dd(dd, "permission update", tx,
194
"%s %s", whokey, perm);
195
}
196
}
197
dsl_dir_rele(dd, FTAG);
198
}
199
200
static void
201
dsl_deleg_unset_sync(void *arg, dmu_tx_t *tx)
202
{
203
dsl_deleg_arg_t *dda = arg;
204
dsl_dir_t *dd;
205
dsl_pool_t *dp = dmu_tx_pool(tx);
206
objset_t *mos = dp->dp_meta_objset;
207
nvpair_t *whopair = NULL;
208
uint64_t zapobj;
209
210
VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
211
zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
212
if (zapobj == 0) {
213
dsl_dir_rele(dd, FTAG);
214
return;
215
}
216
217
while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) {
218
const char *whokey = nvpair_name(whopair);
219
nvlist_t *perms;
220
nvpair_t *permpair = NULL;
221
uint64_t jumpobj;
222
223
if (nvpair_value_nvlist(whopair, &perms) != 0) {
224
if (zap_lookup(mos, zapobj, whokey, 8,
225
1, &jumpobj) == 0) {
226
(void) zap_remove(mos, zapobj, whokey, tx);
227
VERIFY0(zap_destroy(mos, jumpobj, tx));
228
}
229
spa_history_log_internal_dd(dd, "permission who remove",
230
tx, "%s", whokey);
231
continue;
232
}
233
234
if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
235
continue;
236
237
while ((permpair = nvlist_next_nvpair(perms, permpair))) {
238
const char *perm = nvpair_name(permpair);
239
uint64_t n = 0;
240
241
(void) zap_remove(mos, jumpobj, perm, tx);
242
if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
243
(void) zap_remove(mos, zapobj,
244
whokey, tx);
245
VERIFY0(zap_destroy(mos,
246
jumpobj, tx));
247
}
248
spa_history_log_internal_dd(dd, "permission remove", tx,
249
"%s %s", whokey, perm);
250
}
251
}
252
dsl_dir_rele(dd, FTAG);
253
}
254
255
static int
256
dsl_deleg_check(void *arg, dmu_tx_t *tx)
257
{
258
dsl_deleg_arg_t *dda = arg;
259
dsl_dir_t *dd;
260
int error;
261
262
if (spa_version(dmu_tx_pool(tx)->dp_spa) <
263
SPA_VERSION_DELEGATED_PERMS) {
264
return (SET_ERROR(ENOTSUP));
265
}
266
267
error = dsl_dir_hold(dmu_tx_pool(tx), dda->dda_name, FTAG, &dd, NULL);
268
if (error == 0)
269
dsl_dir_rele(dd, FTAG);
270
return (error);
271
}
272
273
int
274
dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
275
{
276
dsl_deleg_arg_t dda;
277
278
/* nvp must already have been verified to be valid */
279
280
dda.dda_name = ddname;
281
dda.dda_nvlist = nvp;
282
283
return (dsl_sync_task(ddname, dsl_deleg_check,
284
unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
285
&dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
286
}
287
288
/*
289
* Find all 'allow' permissions from a given point and then continue
290
* traversing up to the root.
291
*
292
* This function constructs an nvlist of nvlists.
293
* each setpoint is an nvlist composed of an nvlist of an nvlist
294
* of the individual * users/groups/everyone/create
295
* permissions.
296
*
297
* The nvlist will look like this.
298
*
299
* { source fsname -> { whokeys { permissions,...}, ...}}
300
*
301
* The fsname nvpairs will be arranged in a bottom up order. For example,
302
* if we have the following structure a/b/c then the nvpairs for the fsnames
303
* will be ordered a/b/c, a/b, a.
304
*/
305
int
306
dsl_deleg_get(const char *ddname, nvlist_t **nvp)
307
{
308
dsl_dir_t *dd, *startdd;
309
dsl_pool_t *dp;
310
int error;
311
objset_t *mos;
312
zap_cursor_t *basezc, *zc;
313
zap_attribute_t *baseza, *za;
314
char *source;
315
316
error = dsl_pool_hold(ddname, FTAG, &dp);
317
if (error != 0)
318
return (error);
319
320
error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
321
if (error != 0) {
322
dsl_pool_rele(dp, FTAG);
323
return (error);
324
}
325
326
dp = startdd->dd_pool;
327
mos = dp->dp_meta_objset;
328
329
zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
330
za = zap_attribute_alloc();
331
basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
332
baseza = zap_attribute_alloc();
333
source = kmem_alloc(ZFS_MAX_DATASET_NAME_LEN, KM_SLEEP);
334
VERIFY0(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP));
335
336
for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
337
nvlist_t *sp_nvp;
338
uint64_t n;
339
340
if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
341
zap_count(mos,
342
dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
343
continue;
344
345
sp_nvp = fnvlist_alloc();
346
for (zap_cursor_init(basezc, mos,
347
dsl_dir_phys(dd)->dd_deleg_zapobj);
348
zap_cursor_retrieve(basezc, baseza) == 0;
349
zap_cursor_advance(basezc)) {
350
nvlist_t *perms_nvp;
351
352
ASSERT(baseza->za_integer_length == 8);
353
ASSERT(baseza->za_num_integers == 1);
354
355
perms_nvp = fnvlist_alloc();
356
for (zap_cursor_init(zc, mos, baseza->za_first_integer);
357
zap_cursor_retrieve(zc, za) == 0;
358
zap_cursor_advance(zc)) {
359
fnvlist_add_boolean(perms_nvp, za->za_name);
360
}
361
zap_cursor_fini(zc);
362
fnvlist_add_nvlist(sp_nvp, baseza->za_name, perms_nvp);
363
fnvlist_free(perms_nvp);
364
}
365
366
zap_cursor_fini(basezc);
367
368
dsl_dir_name(dd, source);
369
fnvlist_add_nvlist(*nvp, source, sp_nvp);
370
nvlist_free(sp_nvp);
371
}
372
373
kmem_free(source, ZFS_MAX_DATASET_NAME_LEN);
374
zap_attribute_free(baseza);
375
kmem_free(basezc, sizeof (zap_cursor_t));
376
zap_attribute_free(za);
377
kmem_free(zc, sizeof (zap_cursor_t));
378
379
dsl_dir_rele(startdd, FTAG);
380
dsl_pool_rele(dp, FTAG);
381
return (0);
382
}
383
384
/*
385
* Routines for dsl_deleg_access() -- access checking.
386
*/
387
typedef struct perm_set {
388
avl_node_t p_node;
389
boolean_t p_matched;
390
char p_setname[ZFS_MAX_DELEG_NAME];
391
} perm_set_t;
392
393
static int
394
perm_set_compare(const void *arg1, const void *arg2)
395
{
396
const perm_set_t *node1 = (const perm_set_t *)arg1;
397
const perm_set_t *node2 = (const perm_set_t *)arg2;
398
int val;
399
400
val = strcmp(node1->p_setname, node2->p_setname);
401
402
return (TREE_ISIGN(val));
403
}
404
405
/*
406
* Determine whether a specified permission exists.
407
*
408
* First the base attribute has to be retrieved. i.e. ul$12
409
* Once the base object has been retrieved the actual permission
410
* is lookup up in the zap object the base object points to.
411
*
412
* Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
413
* there is no perm in that jumpobj.
414
*/
415
static int
416
dsl_check_access(objset_t *mos, uint64_t zapobj,
417
char type, char checkflag, void *valp, const char *perm)
418
{
419
int error;
420
uint64_t jumpobj, zero;
421
char whokey[ZFS_MAX_DELEG_NAME];
422
423
zfs_deleg_whokey(whokey, type, checkflag, valp);
424
error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
425
if (error == 0) {
426
error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero);
427
if (error == ENOENT)
428
error = SET_ERROR(EPERM);
429
}
430
return (error);
431
}
432
433
/*
434
* check a specified user/group for a requested permission
435
*/
436
static int
437
dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
438
int checkflag, cred_t *cr)
439
{
440
const gid_t *gids;
441
int ngids;
442
int i;
443
uint64_t id;
444
445
/* check for user */
446
id = crgetuid(cr);
447
if (dsl_check_access(mos, zapobj,
448
ZFS_DELEG_USER, checkflag, &id, perm) == 0)
449
return (0);
450
451
/* check for users primary group */
452
id = crgetgid(cr);
453
if (dsl_check_access(mos, zapobj,
454
ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
455
return (0);
456
457
/* check for everyone entry */
458
id = -1;
459
if (dsl_check_access(mos, zapobj,
460
ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
461
return (0);
462
463
/* check each supplemental group user is a member of */
464
ngids = crgetngroups(cr);
465
gids = crgetgroups(cr);
466
for (i = 0; i != ngids; i++) {
467
id = gids[i];
468
if (dsl_check_access(mos, zapobj,
469
ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
470
return (0);
471
}
472
473
return (SET_ERROR(EPERM));
474
}
475
476
/*
477
* Iterate over the sets specified in the specified zapobj
478
* and load them into the permsets avl tree.
479
*/
480
static int
481
dsl_load_sets(objset_t *mos, uint64_t zapobj,
482
char type, char checkflag, void *valp, avl_tree_t *avl)
483
{
484
zap_cursor_t zc;
485
zap_attribute_t *za;
486
perm_set_t *permnode;
487
avl_index_t idx;
488
uint64_t jumpobj;
489
int error;
490
char whokey[ZFS_MAX_DELEG_NAME];
491
492
zfs_deleg_whokey(whokey, type, checkflag, valp);
493
494
error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
495
if (error != 0)
496
return (error);
497
498
za = zap_attribute_alloc();
499
for (zap_cursor_init(&zc, mos, jumpobj);
500
zap_cursor_retrieve(&zc, za) == 0;
501
zap_cursor_advance(&zc)) {
502
permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP);
503
(void) strlcpy(permnode->p_setname, za->za_name,
504
sizeof (permnode->p_setname));
505
permnode->p_matched = B_FALSE;
506
507
if (avl_find(avl, permnode, &idx) == NULL) {
508
avl_insert(avl, permnode, idx);
509
} else {
510
kmem_free(permnode, sizeof (perm_set_t));
511
}
512
}
513
zap_cursor_fini(&zc);
514
zap_attribute_free(za);
515
return (0);
516
}
517
518
/*
519
* Load all permissions user based on cred belongs to.
520
*/
521
static void
522
dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
523
char checkflag, cred_t *cr)
524
{
525
const gid_t *gids;
526
int ngids, i;
527
uint64_t id;
528
529
id = crgetuid(cr);
530
(void) dsl_load_sets(mos, zapobj,
531
ZFS_DELEG_USER_SETS, checkflag, &id, avl);
532
533
id = crgetgid(cr);
534
(void) dsl_load_sets(mos, zapobj,
535
ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
536
537
(void) dsl_load_sets(mos, zapobj,
538
ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
539
540
ngids = crgetngroups(cr);
541
gids = crgetgroups(cr);
542
for (i = 0; i != ngids; i++) {
543
id = gids[i];
544
(void) dsl_load_sets(mos, zapobj,
545
ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
546
}
547
}
548
549
/*
550
* Check if user has requested permission.
551
*/
552
int
553
dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
554
{
555
dsl_dir_t *dd;
556
dsl_pool_t *dp;
557
void *cookie;
558
int error;
559
char checkflag;
560
objset_t *mos;
561
avl_tree_t permsets;
562
perm_set_t *setnode;
563
564
dp = ds->ds_dir->dd_pool;
565
mos = dp->dp_meta_objset;
566
567
if (dsl_delegation_on(mos) == B_FALSE)
568
return (SET_ERROR(ECANCELED));
569
570
if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
571
SPA_VERSION_DELEGATED_PERMS)
572
return (SET_ERROR(EPERM));
573
574
if (ds->ds_is_snapshot) {
575
/*
576
* Snapshots are treated as descendents only,
577
* local permissions do not apply.
578
*/
579
checkflag = ZFS_DELEG_DESCENDENT;
580
} else {
581
checkflag = ZFS_DELEG_LOCAL;
582
}
583
584
avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
585
offsetof(perm_set_t, p_node));
586
587
ASSERT(dsl_pool_config_held(dp));
588
for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
589
checkflag = ZFS_DELEG_DESCENDENT) {
590
uint64_t zapobj;
591
boolean_t expanded;
592
593
/*
594
* If not in global zone then make sure
595
* the zoned property is set
596
*/
597
if (!INGLOBALZONE(curproc)) {
598
uint64_t zoned;
599
600
if (dsl_prop_get_dd(dd,
601
zfs_prop_to_name(ZFS_PROP_ZONED),
602
8, 1, &zoned, NULL, B_FALSE) != 0)
603
break;
604
if (!zoned)
605
break;
606
}
607
zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
608
609
if (zapobj == 0)
610
continue;
611
612
dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
613
again:
614
expanded = B_FALSE;
615
for (setnode = avl_first(&permsets); setnode;
616
setnode = AVL_NEXT(&permsets, setnode)) {
617
if (setnode->p_matched == B_TRUE)
618
continue;
619
620
/* See if this set directly grants this permission */
621
error = dsl_check_access(mos, zapobj,
622
ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm);
623
if (error == 0)
624
goto success;
625
if (error == EPERM)
626
setnode->p_matched = B_TRUE;
627
628
/* See if this set includes other sets */
629
error = dsl_load_sets(mos, zapobj,
630
ZFS_DELEG_NAMED_SET_SETS, 0,
631
setnode->p_setname, &permsets);
632
if (error == 0)
633
setnode->p_matched = expanded = B_TRUE;
634
}
635
/*
636
* If we expanded any sets, that will define more sets,
637
* which we need to check.
638
*/
639
if (expanded)
640
goto again;
641
642
error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
643
if (error == 0)
644
goto success;
645
}
646
error = SET_ERROR(EPERM);
647
success:
648
649
cookie = NULL;
650
while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
651
kmem_free(setnode, sizeof (perm_set_t));
652
653
return (error);
654
}
655
656
int
657
dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
658
{
659
dsl_pool_t *dp;
660
dsl_dataset_t *ds;
661
int error;
662
663
error = dsl_pool_hold(dsname, FTAG, &dp);
664
if (error != 0)
665
return (error);
666
error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
667
if (error == 0) {
668
error = dsl_deleg_access_impl(ds, perm, cr);
669
dsl_dataset_rele(ds, FTAG);
670
}
671
dsl_pool_rele(dp, FTAG);
672
673
return (error);
674
}
675
676
/*
677
* Other routines.
678
*/
679
680
static void
681
copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
682
boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
683
{
684
objset_t *mos = dd->dd_pool->dp_meta_objset;
685
uint64_t jumpobj, pjumpobj;
686
uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
687
zap_cursor_t zc;
688
zap_attribute_t *za;
689
char whokey[ZFS_MAX_DELEG_NAME];
690
691
zfs_deleg_whokey(whokey,
692
dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
693
ZFS_DELEG_LOCAL, NULL);
694
if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
695
return;
696
697
if (zapobj == 0) {
698
dmu_buf_will_dirty(dd->dd_dbuf, tx);
699
zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
700
DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
701
}
702
703
zfs_deleg_whokey(whokey,
704
dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
705
ZFS_DELEG_LOCAL, &uid);
706
if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
707
jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
708
VERIFY0(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx));
709
}
710
711
za = zap_attribute_alloc();
712
for (zap_cursor_init(&zc, mos, pjumpobj);
713
zap_cursor_retrieve(&zc, za) == 0;
714
zap_cursor_advance(&zc)) {
715
uint64_t zero = 0;
716
ASSERT(za->za_integer_length == 8 && za->za_num_integers == 1);
717
718
VERIFY0(zap_update(mos, jumpobj, za->za_name, 8, 1, &zero, tx));
719
}
720
zap_cursor_fini(&zc);
721
zap_attribute_free(za);
722
}
723
724
/*
725
* set all create time permission on new dataset.
726
*/
727
void
728
dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
729
{
730
dsl_dir_t *dd;
731
uint64_t uid = crgetuid(cr);
732
733
if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
734
SPA_VERSION_DELEGATED_PERMS)
735
return;
736
737
for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
738
uint64_t pzapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
739
740
if (pzapobj == 0)
741
continue;
742
743
copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
744
copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
745
}
746
}
747
748
int
749
dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
750
{
751
zap_cursor_t zc;
752
zap_attribute_t *za;
753
754
if (zapobj == 0)
755
return (0);
756
757
za = zap_attribute_alloc();
758
for (zap_cursor_init(&zc, mos, zapobj);
759
zap_cursor_retrieve(&zc, za) == 0;
760
zap_cursor_advance(&zc)) {
761
ASSERT(za->za_integer_length == 8 && za->za_num_integers == 1);
762
VERIFY0(zap_destroy(mos, za->za_first_integer, tx));
763
}
764
zap_cursor_fini(&zc);
765
VERIFY0(zap_destroy(mos, zapobj, tx));
766
zap_attribute_free(za);
767
return (0);
768
}
769
770
boolean_t
771
dsl_delegation_on(objset_t *os)
772
{
773
return (!!spa_delegation(os->os_spa));
774
}
775
776
#if defined(_KERNEL)
777
EXPORT_SYMBOL(dsl_deleg_get);
778
EXPORT_SYMBOL(dsl_deleg_set);
779
#endif
780
781