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