164
165 while (whopair = nvlist_next_nvpair(nvp, whopair)) {
166 const char *whokey = nvpair_name(whopair);
167 nvlist_t *perms;
168 nvpair_t *permpair = NULL;
169 uint64_t jumpobj;
170
171 VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
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 VERIFY(zap_update(mos, jumpobj,
183 perm, 8, 1, &n, tx) == 0);
184 spa_history_log_internal(LOG_DS_PERM_UPDATE,
185 dd->dd_pool->dp_spa, tx,
186 "%s %s dataset = %llu", whokey, perm,
187 dd->dd_phys->dd_head_dataset_obj);
188 }
189 }
190 }
191
192 static void
193 dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
194 {
195 dsl_dir_t *dd = arg1;
196 nvlist_t *nvp = arg2;
197 objset_t *mos = dd->dd_pool->dp_meta_objset;
198 nvpair_t *whopair = NULL;
199 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
200
201 if (zapobj == 0)
202 return;
203
204 while (whopair = nvlist_next_nvpair(nvp, whopair)) {
205 const char *whokey = nvpair_name(whopair);
206 nvlist_t *perms;
207 nvpair_t *permpair = NULL;
208 uint64_t jumpobj;
209
210 if (nvpair_value_nvlist(whopair, &perms) != 0) {
211 if (zap_lookup(mos, zapobj, whokey, 8,
212 1, &jumpobj) == 0) {
213 (void) zap_remove(mos, zapobj, whokey, tx);
214 VERIFY(0 == zap_destroy(mos, jumpobj, tx));
215 }
216 spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE,
217 dd->dd_pool->dp_spa, tx,
218 "%s dataset = %llu", whokey,
219 dd->dd_phys->dd_head_dataset_obj);
220 continue;
221 }
222
223 if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
224 continue;
225
226 while (permpair = nvlist_next_nvpair(perms, permpair)) {
227 const char *perm = nvpair_name(permpair);
228 uint64_t n = 0;
229
230 (void) zap_remove(mos, jumpobj, perm, tx);
231 if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
232 (void) zap_remove(mos, zapobj,
233 whokey, tx);
234 VERIFY(0 == zap_destroy(mos,
235 jumpobj, tx));
236 }
237 spa_history_log_internal(LOG_DS_PERM_REMOVE,
238 dd->dd_pool->dp_spa, tx,
239 "%s %s dataset = %llu", whokey, perm,
240 dd->dd_phys->dd_head_dataset_obj);
241 }
242 }
243 }
244
245 int
246 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
247 {
248 dsl_dir_t *dd;
249 int error;
250 nvpair_t *whopair = NULL;
251 int blocks_modified = 0;
252
253 error = dsl_dir_open(ddname, FTAG, &dd, NULL);
254 if (error)
255 return (error);
256
257 if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) <
258 SPA_VERSION_DELEGATED_PERMS) {
259 dsl_dir_close(dd, FTAG);
260 return (ENOTSUP);
507 (void) dsl_load_sets(mos, zapobj,
508 ZFS_DELEG_USER_SETS, checkflag, &id, avl);
509
510 id = crgetgid(cr);
511 (void) dsl_load_sets(mos, zapobj,
512 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
513
514 (void) dsl_load_sets(mos, zapobj,
515 ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
516
517 ngids = crgetngroups(cr);
518 gids = crgetgroups(cr);
519 for (i = 0; i != ngids; i++) {
520 id = gids[i];
521 (void) dsl_load_sets(mos, zapobj,
522 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
523 }
524 }
525
526 /*
527 * Check if user has requested permission. If descendent is set, must have
528 * descendent perms.
529 */
530 int
531 dsl_deleg_access_impl(dsl_dataset_t *ds, boolean_t descendent, const char *perm,
532 cred_t *cr)
533 {
534 dsl_dir_t *dd;
535 dsl_pool_t *dp;
536 void *cookie;
537 int error;
538 char checkflag;
539 objset_t *mos;
540 avl_tree_t permsets;
541 perm_set_t *setnode;
542
543 dp = ds->ds_dir->dd_pool;
544 mos = dp->dp_meta_objset;
545
546 if (dsl_delegation_on(mos) == B_FALSE)
547 return (ECANCELED);
548
549 if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
550 SPA_VERSION_DELEGATED_PERMS)
551 return (EPERM);
552
553 if (dsl_dataset_is_snapshot(ds) || descendent) {
554 /*
555 * Snapshots are treated as descendents only,
556 * local permissions do not apply.
557 */
558 checkflag = ZFS_DELEG_DESCENDENT;
559 } else {
560 checkflag = ZFS_DELEG_LOCAL;
561 }
562
563 avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
564 offsetof(perm_set_t, p_node));
565
566 rw_enter(&dp->dp_config_rwlock, RW_READER);
567 for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
568 checkflag = ZFS_DELEG_DESCENDENT) {
569 uint64_t zapobj;
570 boolean_t expanded;
571
572 /*
573 * If not in global zone then make sure
626 success:
627 rw_exit(&dp->dp_config_rwlock);
628
629 cookie = NULL;
630 while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
631 kmem_free(setnode, sizeof (perm_set_t));
632
633 return (error);
634 }
635
636 int
637 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
638 {
639 dsl_dataset_t *ds;
640 int error;
641
642 error = dsl_dataset_hold(dsname, FTAG, &ds);
643 if (error)
644 return (error);
645
646 error = dsl_deleg_access_impl(ds, B_FALSE, perm, cr);
647 dsl_dataset_rele(ds, FTAG);
648
649 return (error);
650 }
651
652 /*
653 * Other routines.
654 */
655
656 static void
657 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
658 boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
659 {
660 objset_t *mos = dd->dd_pool->dp_meta_objset;
661 uint64_t jumpobj, pjumpobj;
662 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
663 zap_cursor_t zc;
664 zap_attribute_t za;
665 char whokey[ZFS_MAX_DELEG_NAME];
666
|
164
165 while (whopair = nvlist_next_nvpair(nvp, whopair)) {
166 const char *whokey = nvpair_name(whopair);
167 nvlist_t *perms;
168 nvpair_t *permpair = NULL;
169 uint64_t jumpobj;
170
171 VERIFY(nvpair_value_nvlist(whopair, &perms) == 0);
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 VERIFY(zap_update(mos, jumpobj,
183 perm, 8, 1, &n, tx) == 0);
184 spa_history_log_internal_dd(dd, "permission update", tx,
185 "%s %s", whokey, perm);
186 }
187 }
188 }
189
190 static void
191 dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx)
192 {
193 dsl_dir_t *dd = arg1;
194 nvlist_t *nvp = arg2;
195 objset_t *mos = dd->dd_pool->dp_meta_objset;
196 nvpair_t *whopair = NULL;
197 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
198
199 if (zapobj == 0)
200 return;
201
202 while (whopair = nvlist_next_nvpair(nvp, whopair)) {
203 const char *whokey = nvpair_name(whopair);
204 nvlist_t *perms;
205 nvpair_t *permpair = NULL;
206 uint64_t jumpobj;
207
208 if (nvpair_value_nvlist(whopair, &perms) != 0) {
209 if (zap_lookup(mos, zapobj, whokey, 8,
210 1, &jumpobj) == 0) {
211 (void) zap_remove(mos, zapobj, whokey, tx);
212 VERIFY(0 == zap_destroy(mos, jumpobj, tx));
213 }
214 spa_history_log_internal_dd(dd, "permission who remove",
215 tx, "%s", whokey);
216 continue;
217 }
218
219 if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
220 continue;
221
222 while (permpair = nvlist_next_nvpair(perms, permpair)) {
223 const char *perm = nvpair_name(permpair);
224 uint64_t n = 0;
225
226 (void) zap_remove(mos, jumpobj, perm, tx);
227 if (zap_count(mos, jumpobj, &n) == 0 && n == 0) {
228 (void) zap_remove(mos, zapobj,
229 whokey, tx);
230 VERIFY(0 == zap_destroy(mos,
231 jumpobj, tx));
232 }
233 spa_history_log_internal_dd(dd, "permission remove", tx,
234 "%s %s", whokey, perm);
235 }
236 }
237 }
238
239 int
240 dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
241 {
242 dsl_dir_t *dd;
243 int error;
244 nvpair_t *whopair = NULL;
245 int blocks_modified = 0;
246
247 error = dsl_dir_open(ddname, FTAG, &dd, NULL);
248 if (error)
249 return (error);
250
251 if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) <
252 SPA_VERSION_DELEGATED_PERMS) {
253 dsl_dir_close(dd, FTAG);
254 return (ENOTSUP);
501 (void) dsl_load_sets(mos, zapobj,
502 ZFS_DELEG_USER_SETS, checkflag, &id, avl);
503
504 id = crgetgid(cr);
505 (void) dsl_load_sets(mos, zapobj,
506 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
507
508 (void) dsl_load_sets(mos, zapobj,
509 ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl);
510
511 ngids = crgetngroups(cr);
512 gids = crgetgroups(cr);
513 for (i = 0; i != ngids; i++) {
514 id = gids[i];
515 (void) dsl_load_sets(mos, zapobj,
516 ZFS_DELEG_GROUP_SETS, checkflag, &id, avl);
517 }
518 }
519
520 /*
521 * Check if user has requested permission.
522 */
523 int
524 dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
525 {
526 dsl_dir_t *dd;
527 dsl_pool_t *dp;
528 void *cookie;
529 int error;
530 char checkflag;
531 objset_t *mos;
532 avl_tree_t permsets;
533 perm_set_t *setnode;
534
535 dp = ds->ds_dir->dd_pool;
536 mos = dp->dp_meta_objset;
537
538 if (dsl_delegation_on(mos) == B_FALSE)
539 return (ECANCELED);
540
541 if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) <
542 SPA_VERSION_DELEGATED_PERMS)
543 return (EPERM);
544
545 if (dsl_dataset_is_snapshot(ds)) {
546 /*
547 * Snapshots are treated as descendents only,
548 * local permissions do not apply.
549 */
550 checkflag = ZFS_DELEG_DESCENDENT;
551 } else {
552 checkflag = ZFS_DELEG_LOCAL;
553 }
554
555 avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
556 offsetof(perm_set_t, p_node));
557
558 rw_enter(&dp->dp_config_rwlock, RW_READER);
559 for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
560 checkflag = ZFS_DELEG_DESCENDENT) {
561 uint64_t zapobj;
562 boolean_t expanded;
563
564 /*
565 * If not in global zone then make sure
618 success:
619 rw_exit(&dp->dp_config_rwlock);
620
621 cookie = NULL;
622 while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
623 kmem_free(setnode, sizeof (perm_set_t));
624
625 return (error);
626 }
627
628 int
629 dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
630 {
631 dsl_dataset_t *ds;
632 int error;
633
634 error = dsl_dataset_hold(dsname, FTAG, &ds);
635 if (error)
636 return (error);
637
638 error = dsl_deleg_access_impl(ds, perm, cr);
639 dsl_dataset_rele(ds, FTAG);
640
641 return (error);
642 }
643
644 /*
645 * Other routines.
646 */
647
648 static void
649 copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
650 boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
651 {
652 objset_t *mos = dd->dd_pool->dp_meta_objset;
653 uint64_t jumpobj, pjumpobj;
654 uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
655 zap_cursor_t zc;
656 zap_attribute_t za;
657 char whokey[ZFS_MAX_DELEG_NAME];
658
|