14543Smarks /* 24543Smarks * CDDL HEADER START 34543Smarks * 44543Smarks * The contents of this file are subject to the terms of the 54543Smarks * Common Development and Distribution License (the "License"). 64543Smarks * You may not use this file except in compliance with the License. 74543Smarks * 84543Smarks * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94543Smarks * or http://www.opensolaris.org/os/licensing. 104543Smarks * See the License for the specific language governing permissions 114543Smarks * and limitations under the License. 124543Smarks * 134543Smarks * When distributing Covered Code, include this CDDL HEADER in each 144543Smarks * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154543Smarks * If applicable, add the following below this CDDL HEADER, with the 164543Smarks * fields enclosed by brackets "[]" replaced with your own identifying 174543Smarks * information: Portions Copyright [yyyy] [name of copyright owner] 184543Smarks * 194543Smarks * CDDL HEADER END 204543Smarks */ 214543Smarks /* 2212296SLin.Ling@Sun.COM * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 234543Smarks */ 244543Smarks 254543Smarks /* 264543Smarks * DSL permissions are stored in a two level zap attribute 274543Smarks * mechanism. The first level identifies the "class" of 284543Smarks * entry. The class is identified by the first 2 letters of 294543Smarks * the attribute. The second letter "l" or "d" identifies whether 304543Smarks * it is a local or descendent permission. The first letter 314543Smarks * identifies the type of entry. 324543Smarks * 335331Samw * ul$<id> identifies permissions granted locally for this userid. 344543Smarks * ud$<id> identifies permissions granted on descendent datasets for 354543Smarks * this userid. 364543Smarks * Ul$<id> identifies permission sets granted locally for this userid. 374543Smarks * Ud$<id> identifies permission sets granted on descendent datasets for 384543Smarks * this userid. 394543Smarks * gl$<id> identifies permissions granted locally for this groupid. 404543Smarks * gd$<id> identifies permissions granted on descendent datasets for 414543Smarks * this groupid. 424543Smarks * Gl$<id> identifies permission sets granted locally for this groupid. 434543Smarks * Gd$<id> identifies permission sets granted on descendent datasets for 444543Smarks * this groupid. 454543Smarks * el$ identifies permissions granted locally for everyone. 464543Smarks * ed$ identifies permissions granted on descendent datasets 474543Smarks * for everyone. 484543Smarks * El$ identifies permission sets granted locally for everyone. 494543Smarks * Ed$ identifies permission sets granted to descendent datasets for 504543Smarks * everyone. 514543Smarks * c-$ identifies permission to create at dataset creation time. 524543Smarks * C-$ identifies permission sets to grant locally at dataset creation 534543Smarks * time. 544543Smarks * s-$@<name> permissions defined in specified set @<name> 554543Smarks * S-$@<name> Sets defined in named set @<name> 564543Smarks * 575331Samw * Each of the above entities points to another zap attribute that contains one 584543Smarks * attribute for each allowed permission, such as create, destroy,... 594543Smarks * All of the "upper" case class types will specify permission set names 604543Smarks * rather than permissions. 614543Smarks * 624543Smarks * Basically it looks something like this: 634543Smarks * ul$12 -> ZAP OBJ -> permissions... 644543Smarks * 654543Smarks * The ZAP OBJ is referred to as the jump object. 664543Smarks */ 674543Smarks 684543Smarks #include <sys/dmu.h> 694543Smarks #include <sys/dmu_objset.h> 704543Smarks #include <sys/dmu_tx.h> 714543Smarks #include <sys/dsl_dataset.h> 724543Smarks #include <sys/dsl_dir.h> 734543Smarks #include <sys/dsl_prop.h> 744543Smarks #include <sys/dsl_synctask.h> 754543Smarks #include <sys/dsl_deleg.h> 764543Smarks #include <sys/spa.h> 774543Smarks #include <sys/zap.h> 784543Smarks #include <sys/fs/zfs.h> 794543Smarks #include <sys/cred.h> 804543Smarks #include <sys/sunddi.h> 814543Smarks 824543Smarks #include "zfs_deleg.h" 834543Smarks 844543Smarks /* 854543Smarks * Validate that user is allowed to delegate specified permissions. 864543Smarks * 874787Sahrens * In order to delegate "create" you must have "create" 884543Smarks * and "allow". 894543Smarks */ 904543Smarks int 914543Smarks dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr) 924543Smarks { 934543Smarks nvpair_t *whopair = NULL; 944787Sahrens int error; 954543Smarks 964787Sahrens if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0) 974543Smarks return (error); 984543Smarks 994543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) { 1004543Smarks nvlist_t *perms; 1014543Smarks nvpair_t *permpair = NULL; 1024543Smarks 1034543Smarks VERIFY(nvpair_value_nvlist(whopair, &perms) == 0); 1044543Smarks 1054543Smarks while (permpair = nvlist_next_nvpair(perms, permpair)) { 1064543Smarks const char *perm = nvpair_name(permpair); 1074543Smarks 1084543Smarks if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0) 1094543Smarks return (EPERM); 1104543Smarks 1114787Sahrens if ((error = dsl_deleg_access(ddname, perm, cr)) != 0) 1124543Smarks return (error); 1134543Smarks } 1144543Smarks } 1154787Sahrens return (0); 1164543Smarks } 1174543Smarks 1184543Smarks /* 1194543Smarks * Validate that user is allowed to unallow specified permissions. They 1204543Smarks * must have the 'allow' permission, and even then can only unallow 1214543Smarks * perms for their uid. 1224543Smarks */ 1234543Smarks int 1244543Smarks dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr) 1254543Smarks { 1264543Smarks nvpair_t *whopair = NULL; 1274543Smarks int error; 1284787Sahrens char idstr[32]; 1294543Smarks 1304787Sahrens if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0) 1314543Smarks return (error); 1324543Smarks 1334787Sahrens (void) snprintf(idstr, sizeof (idstr), "%lld", 1344787Sahrens (longlong_t)crgetuid(cr)); 1354787Sahrens 1364543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) { 1374543Smarks zfs_deleg_who_type_t type = nvpair_name(whopair)[0]; 1384543Smarks 1394543Smarks if (type != ZFS_DELEG_USER && 1404543Smarks type != ZFS_DELEG_USER_SETS) 1414543Smarks return (EPERM); 1424543Smarks 1434543Smarks if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0) 1444543Smarks return (EPERM); 1454543Smarks } 1464543Smarks return (0); 1474543Smarks } 1484543Smarks 1494543Smarks static void 15012296SLin.Ling@Sun.COM dsl_deleg_set_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1514543Smarks { 1524543Smarks dsl_dir_t *dd = arg1; 1535367Sahrens nvlist_t *nvp = arg2; 1544543Smarks objset_t *mos = dd->dd_pool->dp_meta_objset; 1554543Smarks nvpair_t *whopair = NULL; 1564543Smarks uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 1574543Smarks 1584543Smarks if (zapobj == 0) { 1594543Smarks dmu_buf_will_dirty(dd->dd_dbuf, tx); 1604543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 1614543Smarks DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 1624543Smarks } 1634543Smarks 1645367Sahrens while (whopair = nvlist_next_nvpair(nvp, whopair)) { 1655367Sahrens const char *whokey = nvpair_name(whopair); 1665367Sahrens nvlist_t *perms; 1675367Sahrens nvpair_t *permpair = NULL; 1685367Sahrens uint64_t jumpobj; 1695367Sahrens 1705367Sahrens VERIFY(nvpair_value_nvlist(whopair, &perms) == 0); 1715367Sahrens 1725367Sahrens if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) { 1735367Sahrens jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, 1745367Sahrens DMU_OT_NONE, 0, tx); 1755367Sahrens VERIFY(zap_update(mos, zapobj, 1765367Sahrens whokey, 8, 1, &jumpobj, tx) == 0); 1775367Sahrens } 1785367Sahrens 1795367Sahrens while (permpair = nvlist_next_nvpair(perms, permpair)) { 1805367Sahrens const char *perm = nvpair_name(permpair); 1815367Sahrens uint64_t n = 0; 1825367Sahrens 1835367Sahrens VERIFY(zap_update(mos, jumpobj, 1845367Sahrens perm, 8, 1, &n, tx) == 0); 18512296SLin.Ling@Sun.COM spa_history_log_internal(LOG_DS_PERM_UPDATE, 18612296SLin.Ling@Sun.COM dd->dd_pool->dp_spa, tx, 1875367Sahrens "%s %s dataset = %llu", whokey, perm, 1885367Sahrens dd->dd_phys->dd_head_dataset_obj); 1895367Sahrens } 1905367Sahrens } 1915367Sahrens } 1925367Sahrens 1935367Sahrens static void 19412296SLin.Ling@Sun.COM dsl_deleg_unset_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1955367Sahrens { 1965367Sahrens dsl_dir_t *dd = arg1; 1975367Sahrens nvlist_t *nvp = arg2; 1985367Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 1995367Sahrens nvpair_t *whopair = NULL; 2005367Sahrens uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 2015367Sahrens 2025367Sahrens if (zapobj == 0) 2035367Sahrens return; 2045367Sahrens 2055367Sahrens while (whopair = nvlist_next_nvpair(nvp, whopair)) { 2064543Smarks const char *whokey = nvpair_name(whopair); 2074543Smarks nvlist_t *perms; 2084543Smarks nvpair_t *permpair = NULL; 2094543Smarks uint64_t jumpobj; 2104543Smarks 2114543Smarks if (nvpair_value_nvlist(whopair, &perms) != 0) { 2124543Smarks if (zap_lookup(mos, zapobj, whokey, 8, 2134543Smarks 1, &jumpobj) == 0) { 2144543Smarks (void) zap_remove(mos, zapobj, whokey, tx); 2154543Smarks VERIFY(0 == zap_destroy(mos, jumpobj, tx)); 2164543Smarks } 21712296SLin.Ling@Sun.COM spa_history_log_internal(LOG_DS_PERM_WHO_REMOVE, 21812296SLin.Ling@Sun.COM dd->dd_pool->dp_spa, tx, 2194543Smarks "%s dataset = %llu", whokey, 2204543Smarks dd->dd_phys->dd_head_dataset_obj); 2214543Smarks continue; 2224543Smarks } 2234543Smarks 2245367Sahrens if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) 2255367Sahrens continue; 2264543Smarks 2274543Smarks while (permpair = nvlist_next_nvpair(perms, permpair)) { 2284543Smarks const char *perm = nvpair_name(permpair); 2294543Smarks uint64_t n = 0; 2304543Smarks 2315367Sahrens (void) zap_remove(mos, jumpobj, perm, tx); 2325367Sahrens if (zap_count(mos, jumpobj, &n) == 0 && n == 0) { 2335367Sahrens (void) zap_remove(mos, zapobj, 2345367Sahrens whokey, tx); 2355367Sahrens VERIFY(0 == zap_destroy(mos, 2365367Sahrens jumpobj, tx)); 2374543Smarks } 23812296SLin.Ling@Sun.COM spa_history_log_internal(LOG_DS_PERM_REMOVE, 23912296SLin.Ling@Sun.COM dd->dd_pool->dp_spa, tx, 2404543Smarks "%s %s dataset = %llu", whokey, perm, 2414543Smarks dd->dd_phys->dd_head_dataset_obj); 2424543Smarks } 2434543Smarks } 2444543Smarks } 2454543Smarks 2464543Smarks int 2474543Smarks dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset) 2484543Smarks { 2494543Smarks dsl_dir_t *dd; 2504543Smarks int error; 2514543Smarks nvpair_t *whopair = NULL; 2524543Smarks int blocks_modified = 0; 2534543Smarks 2544543Smarks error = dsl_dir_open(ddname, FTAG, &dd, NULL); 2554543Smarks if (error) 2564543Smarks return (error); 2574543Smarks 2584543Smarks if (spa_version(dmu_objset_spa(dd->dd_pool->dp_meta_objset)) < 2595094Slling SPA_VERSION_DELEGATED_PERMS) { 2604543Smarks dsl_dir_close(dd, FTAG); 2614543Smarks return (ENOTSUP); 2624543Smarks } 2634543Smarks 2644543Smarks while (whopair = nvlist_next_nvpair(nvp, whopair)) 2654543Smarks blocks_modified++; 2664543Smarks 2675367Sahrens error = dsl_sync_task_do(dd->dd_pool, NULL, 2685367Sahrens unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync, 2695367Sahrens dd, nvp, blocks_modified); 2704543Smarks dsl_dir_close(dd, FTAG); 2714543Smarks 2724543Smarks return (error); 2734543Smarks } 2744543Smarks 2754543Smarks /* 2764543Smarks * Find all 'allow' permissions from a given point and then continue 2774543Smarks * traversing up to the root. 2784543Smarks * 2794543Smarks * This function constructs an nvlist of nvlists. 2804543Smarks * each setpoint is an nvlist composed of an nvlist of an nvlist 2814543Smarks * of the individual * users/groups/everyone/create 2824543Smarks * permissions. 2834543Smarks * 2844543Smarks * The nvlist will look like this. 2854543Smarks * 2864543Smarks * { source fsname -> { whokeys { permissions,...}, ...}} 2874543Smarks * 2884543Smarks * The fsname nvpairs will be arranged in a bottom up order. For example, 2894543Smarks * if we have the following structure a/b/c then the nvpairs for the fsnames 2904543Smarks * will be ordered a/b/c, a/b, a. 2914543Smarks */ 2924543Smarks int 2934543Smarks dsl_deleg_get(const char *ddname, nvlist_t **nvp) 2944543Smarks { 2954543Smarks dsl_dir_t *dd, *startdd; 2964543Smarks dsl_pool_t *dp; 2974543Smarks int error; 2984543Smarks objset_t *mos; 2994543Smarks 3004543Smarks error = dsl_dir_open(ddname, FTAG, &startdd, NULL); 3014543Smarks if (error) 3024543Smarks return (error); 3034543Smarks 3044543Smarks dp = startdd->dd_pool; 3054543Smarks mos = dp->dp_meta_objset; 3064543Smarks 3074543Smarks VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0); 3084543Smarks 3094543Smarks rw_enter(&dp->dp_config_rwlock, RW_READER); 3104543Smarks for (dd = startdd; dd != NULL; dd = dd->dd_parent) { 3114543Smarks zap_cursor_t basezc; 3124543Smarks zap_attribute_t baseza; 3134543Smarks nvlist_t *sp_nvp; 3144543Smarks uint64_t n; 3154543Smarks char source[MAXNAMELEN]; 3164543Smarks 3174543Smarks if (dd->dd_phys->dd_deleg_zapobj && 3184543Smarks (zap_count(mos, dd->dd_phys->dd_deleg_zapobj, 3194543Smarks &n) == 0) && n) { 3204543Smarks VERIFY(nvlist_alloc(&sp_nvp, 3214543Smarks NV_UNIQUE_NAME, KM_SLEEP) == 0); 3224543Smarks } else { 3234543Smarks continue; 3244543Smarks } 3254543Smarks 3264543Smarks for (zap_cursor_init(&basezc, mos, 3274543Smarks dd->dd_phys->dd_deleg_zapobj); 3284543Smarks zap_cursor_retrieve(&basezc, &baseza) == 0; 3294543Smarks zap_cursor_advance(&basezc)) { 3304543Smarks zap_cursor_t zc; 3314543Smarks zap_attribute_t za; 3324543Smarks nvlist_t *perms_nvp; 3334543Smarks 3344543Smarks ASSERT(baseza.za_integer_length == 8); 3354543Smarks ASSERT(baseza.za_num_integers == 1); 3364543Smarks 3374543Smarks VERIFY(nvlist_alloc(&perms_nvp, 3384543Smarks NV_UNIQUE_NAME, KM_SLEEP) == 0); 3394543Smarks for (zap_cursor_init(&zc, mos, baseza.za_first_integer); 3404543Smarks zap_cursor_retrieve(&zc, &za) == 0; 3414543Smarks zap_cursor_advance(&zc)) { 3424543Smarks VERIFY(nvlist_add_boolean(perms_nvp, 3434543Smarks za.za_name) == 0); 3444543Smarks } 3454543Smarks zap_cursor_fini(&zc); 3464543Smarks VERIFY(nvlist_add_nvlist(sp_nvp, baseza.za_name, 3474543Smarks perms_nvp) == 0); 3484543Smarks nvlist_free(perms_nvp); 3494543Smarks } 3504543Smarks 3514543Smarks zap_cursor_fini(&basezc); 3524543Smarks 3534543Smarks dsl_dir_name(dd, source); 3544543Smarks VERIFY(nvlist_add_nvlist(*nvp, source, sp_nvp) == 0); 3554543Smarks nvlist_free(sp_nvp); 3564543Smarks } 3574543Smarks rw_exit(&dp->dp_config_rwlock); 3584543Smarks 3594543Smarks dsl_dir_close(startdd, FTAG); 3604543Smarks return (0); 3614543Smarks } 3624543Smarks 3634543Smarks /* 3644543Smarks * Routines for dsl_deleg_access() -- access checking. 3654543Smarks */ 3664543Smarks typedef struct perm_set { 3674543Smarks avl_node_t p_node; 3684787Sahrens boolean_t p_matched; 3694543Smarks char p_setname[ZFS_MAX_DELEG_NAME]; 3704543Smarks } perm_set_t; 3714543Smarks 3724543Smarks static int 3734543Smarks perm_set_compare(const void *arg1, const void *arg2) 3744543Smarks { 3754543Smarks const perm_set_t *node1 = arg1; 3764543Smarks const perm_set_t *node2 = arg2; 3774543Smarks int val; 3784543Smarks 3794543Smarks val = strcmp(node1->p_setname, node2->p_setname); 3804543Smarks if (val == 0) 3814543Smarks return (0); 3824543Smarks return (val > 0 ? 1 : -1); 3834543Smarks } 3844543Smarks 3854543Smarks /* 3864543Smarks * Determine whether a specified permission exists. 3874543Smarks * 3884543Smarks * First the base attribute has to be retrieved. i.e. ul$12 3894543Smarks * Once the base object has been retrieved the actual permission 3904543Smarks * is lookup up in the zap object the base object points to. 3914543Smarks * 3924543Smarks * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if 3934543Smarks * there is no perm in that jumpobj. 3944543Smarks */ 3954543Smarks static int 3964543Smarks dsl_check_access(objset_t *mos, uint64_t zapobj, 3974543Smarks char type, char checkflag, void *valp, const char *perm) 3984543Smarks { 3994543Smarks int error; 4004543Smarks uint64_t jumpobj, zero; 4014543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 4024543Smarks 4034543Smarks zfs_deleg_whokey(whokey, type, checkflag, valp); 4044543Smarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 4054543Smarks if (error == 0) { 4064543Smarks error = zap_lookup(mos, jumpobj, perm, 8, 1, &zero); 4074543Smarks if (error == ENOENT) 4084543Smarks error = EPERM; 4094543Smarks } 4104543Smarks return (error); 4114543Smarks } 4124543Smarks 4134543Smarks /* 4144543Smarks * check a specified user/group for a requested permission 4154543Smarks */ 4164543Smarks static int 4174787Sahrens dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm, 4184543Smarks int checkflag, cred_t *cr) 4194543Smarks { 4204543Smarks const gid_t *gids; 4214543Smarks int ngids; 4224543Smarks int i; 4234543Smarks uint64_t id; 4244543Smarks 4254543Smarks /* check for user */ 4264543Smarks id = crgetuid(cr); 4274787Sahrens if (dsl_check_access(mos, zapobj, 4284543Smarks ZFS_DELEG_USER, checkflag, &id, perm) == 0) 4294543Smarks return (0); 4304543Smarks 4314543Smarks /* check for users primary group */ 4324543Smarks id = crgetgid(cr); 4334787Sahrens if (dsl_check_access(mos, zapobj, 4344543Smarks ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 4354543Smarks return (0); 4364543Smarks 4374543Smarks /* check for everyone entry */ 4384543Smarks id = -1; 4394787Sahrens if (dsl_check_access(mos, zapobj, 4404543Smarks ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0) 4414543Smarks return (0); 4424543Smarks 4434543Smarks /* check each supplemental group user is a member of */ 4444543Smarks ngids = crgetngroups(cr); 4454543Smarks gids = crgetgroups(cr); 4464543Smarks for (i = 0; i != ngids; i++) { 4474543Smarks id = gids[i]; 4484787Sahrens if (dsl_check_access(mos, zapobj, 4494543Smarks ZFS_DELEG_GROUP, checkflag, &id, perm) == 0) 4504543Smarks return (0); 4514543Smarks } 4524543Smarks 4534543Smarks return (EPERM); 4544543Smarks } 4554543Smarks 4564543Smarks /* 4574543Smarks * Iterate over the sets specified in the specified zapobj 4584543Smarks * and load them into the permsets avl tree. 4594543Smarks */ 4604543Smarks static int 4614543Smarks dsl_load_sets(objset_t *mos, uint64_t zapobj, 4624543Smarks char type, char checkflag, void *valp, avl_tree_t *avl) 4634543Smarks { 4644543Smarks zap_cursor_t zc; 4654543Smarks zap_attribute_t za; 4664543Smarks perm_set_t *permnode; 4674543Smarks avl_index_t idx; 4684543Smarks uint64_t jumpobj; 4694543Smarks int error; 4704543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 4714543Smarks 4724543Smarks zfs_deleg_whokey(whokey, type, checkflag, valp); 4734543Smarks 4744543Smarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj); 4754543Smarks if (error != 0) 4764543Smarks return (error); 4774543Smarks 4784543Smarks for (zap_cursor_init(&zc, mos, jumpobj); 4794543Smarks zap_cursor_retrieve(&zc, &za) == 0; 4804543Smarks zap_cursor_advance(&zc)) { 4814543Smarks permnode = kmem_alloc(sizeof (perm_set_t), KM_SLEEP); 4824543Smarks (void) strlcpy(permnode->p_setname, za.za_name, 4834543Smarks sizeof (permnode->p_setname)); 4844543Smarks permnode->p_matched = B_FALSE; 4854543Smarks 4864543Smarks if (avl_find(avl, permnode, &idx) == NULL) { 4874543Smarks avl_insert(avl, permnode, idx); 4884543Smarks } else { 4894543Smarks kmem_free(permnode, sizeof (perm_set_t)); 4904543Smarks } 4914543Smarks } 4924543Smarks zap_cursor_fini(&zc); 4934543Smarks return (0); 4944543Smarks } 4954543Smarks 4964543Smarks /* 4974543Smarks * Load all permissions user based on cred belongs to. 4984543Smarks */ 4994543Smarks static void 5004543Smarks dsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl, 5014543Smarks char checkflag, cred_t *cr) 5024543Smarks { 5034543Smarks const gid_t *gids; 5044543Smarks int ngids, i; 5054543Smarks uint64_t id; 5064543Smarks 5074543Smarks id = crgetuid(cr); 5084543Smarks (void) dsl_load_sets(mos, zapobj, 5094543Smarks ZFS_DELEG_USER_SETS, checkflag, &id, avl); 5104543Smarks 5114543Smarks id = crgetgid(cr); 5124543Smarks (void) dsl_load_sets(mos, zapobj, 5134543Smarks ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 5144543Smarks 5154543Smarks (void) dsl_load_sets(mos, zapobj, 5164543Smarks ZFS_DELEG_EVERYONE_SETS, checkflag, NULL, avl); 5174543Smarks 5184543Smarks ngids = crgetngroups(cr); 5194543Smarks gids = crgetgroups(cr); 5204543Smarks for (i = 0; i != ngids; i++) { 5214543Smarks id = gids[i]; 5224543Smarks (void) dsl_load_sets(mos, zapobj, 5234543Smarks ZFS_DELEG_GROUP_SETS, checkflag, &id, avl); 5244543Smarks } 5254543Smarks } 5264543Smarks 5274543Smarks /* 5284543Smarks * Check if user has requested permission. 5294543Smarks */ 5304543Smarks int 531*12786SChris.Kirby@oracle.com dsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr) 5324543Smarks { 5337265Sahrens dsl_dir_t *dd; 5344543Smarks dsl_pool_t *dp; 5354543Smarks void *cookie; 5364543Smarks int error; 5379847Swilliam.gorrell@sun.com char checkflag; 5384543Smarks objset_t *mos; 5394543Smarks avl_tree_t permsets; 5404543Smarks perm_set_t *setnode; 5414543Smarks 5427265Sahrens dp = ds->ds_dir->dd_pool; 5434543Smarks mos = dp->dp_meta_objset; 5444543Smarks 545*12786SChris.Kirby@oracle.com if (dsl_delegation_on(mos) == B_FALSE) 5464543Smarks return (ECANCELED); 5474543Smarks 5484543Smarks if (spa_version(dmu_objset_spa(dp->dp_meta_objset)) < 549*12786SChris.Kirby@oracle.com SPA_VERSION_DELEGATED_PERMS) 5504543Smarks return (EPERM); 5514543Smarks 5529847Swilliam.gorrell@sun.com if (dsl_dataset_is_snapshot(ds)) { 5539847Swilliam.gorrell@sun.com /* 5549847Swilliam.gorrell@sun.com * Snapshots are treated as descendents only, 5559847Swilliam.gorrell@sun.com * local permissions do not apply. 5569847Swilliam.gorrell@sun.com */ 5579847Swilliam.gorrell@sun.com checkflag = ZFS_DELEG_DESCENDENT; 5589847Swilliam.gorrell@sun.com } else { 5599847Swilliam.gorrell@sun.com checkflag = ZFS_DELEG_LOCAL; 5609847Swilliam.gorrell@sun.com } 5619847Swilliam.gorrell@sun.com 5624543Smarks avl_create(&permsets, perm_set_compare, sizeof (perm_set_t), 5634543Smarks offsetof(perm_set_t, p_node)); 5644543Smarks 5654543Smarks rw_enter(&dp->dp_config_rwlock, RW_READER); 5667265Sahrens for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent, 5674543Smarks checkflag = ZFS_DELEG_DESCENDENT) { 5684543Smarks uint64_t zapobj; 5694543Smarks boolean_t expanded; 5704543Smarks 5714543Smarks /* 5724543Smarks * If not in global zone then make sure 5734543Smarks * the zoned property is set 5744543Smarks */ 5754543Smarks if (!INGLOBALZONE(curproc)) { 5764543Smarks uint64_t zoned; 5774543Smarks 5787265Sahrens if (dsl_prop_get_dd(dd, 5794543Smarks zfs_prop_to_name(ZFS_PROP_ZONED), 58011022STom.Erickson@Sun.COM 8, 1, &zoned, NULL, B_FALSE) != 0) 5814543Smarks break; 5824543Smarks if (!zoned) 5834543Smarks break; 5844543Smarks } 5854543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj; 5864543Smarks 5874543Smarks if (zapobj == 0) 5884543Smarks continue; 5894543Smarks 5904543Smarks dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr); 5914543Smarks again: 5924543Smarks expanded = B_FALSE; 5934543Smarks for (setnode = avl_first(&permsets); setnode; 5944543Smarks setnode = AVL_NEXT(&permsets, setnode)) { 5954543Smarks if (setnode->p_matched == B_TRUE) 5964543Smarks continue; 5974543Smarks 5984543Smarks /* See if this set directly grants this permission */ 5994543Smarks error = dsl_check_access(mos, zapobj, 6004543Smarks ZFS_DELEG_NAMED_SET, 0, setnode->p_setname, perm); 6014543Smarks if (error == 0) 6024543Smarks goto success; 6034543Smarks if (error == EPERM) 6044543Smarks setnode->p_matched = B_TRUE; 6054543Smarks 6064543Smarks /* See if this set includes other sets */ 6074543Smarks error = dsl_load_sets(mos, zapobj, 6084543Smarks ZFS_DELEG_NAMED_SET_SETS, 0, 6094543Smarks setnode->p_setname, &permsets); 6104543Smarks if (error == 0) 6114543Smarks setnode->p_matched = expanded = B_TRUE; 6124543Smarks } 6134543Smarks /* 6144543Smarks * If we expanded any sets, that will define more sets, 6154543Smarks * which we need to check. 6164543Smarks */ 6174543Smarks if (expanded) 6184543Smarks goto again; 6194543Smarks 6204543Smarks error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr); 6214543Smarks if (error == 0) 6224543Smarks goto success; 6234543Smarks } 6244543Smarks error = EPERM; 6254543Smarks success: 6264543Smarks rw_exit(&dp->dp_config_rwlock); 6274543Smarks 6284543Smarks cookie = NULL; 6294787Sahrens while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) 6304543Smarks kmem_free(setnode, sizeof (perm_set_t)); 6314543Smarks 6324543Smarks return (error); 6334543Smarks } 6344543Smarks 635*12786SChris.Kirby@oracle.com int 636*12786SChris.Kirby@oracle.com dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr) 637*12786SChris.Kirby@oracle.com { 638*12786SChris.Kirby@oracle.com dsl_dataset_t *ds; 639*12786SChris.Kirby@oracle.com int error; 640*12786SChris.Kirby@oracle.com 641*12786SChris.Kirby@oracle.com error = dsl_dataset_hold(dsname, FTAG, &ds); 642*12786SChris.Kirby@oracle.com if (error) 643*12786SChris.Kirby@oracle.com return (error); 644*12786SChris.Kirby@oracle.com 645*12786SChris.Kirby@oracle.com error = dsl_deleg_access_impl(ds, perm, cr); 646*12786SChris.Kirby@oracle.com dsl_dataset_rele(ds, FTAG); 647*12786SChris.Kirby@oracle.com 648*12786SChris.Kirby@oracle.com return (error); 649*12786SChris.Kirby@oracle.com } 650*12786SChris.Kirby@oracle.com 6514543Smarks /* 6524543Smarks * Other routines. 6534543Smarks */ 6544543Smarks 6554543Smarks static void 6564787Sahrens copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj, 6574543Smarks boolean_t dosets, uint64_t uid, dmu_tx_t *tx) 6584543Smarks { 6594787Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 6604543Smarks uint64_t jumpobj, pjumpobj; 6614543Smarks uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; 6624543Smarks zap_cursor_t zc; 6634543Smarks zap_attribute_t za; 6644543Smarks char whokey[ZFS_MAX_DELEG_NAME]; 6654543Smarks 6664543Smarks zfs_deleg_whokey(whokey, 6674543Smarks dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE, 6684543Smarks ZFS_DELEG_LOCAL, NULL); 6694787Sahrens if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0) 6704543Smarks return; 6714543Smarks 6724543Smarks if (zapobj == 0) { 6734543Smarks dmu_buf_will_dirty(dd->dd_dbuf, tx); 6744543Smarks zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos, 6754543Smarks DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 6764543Smarks } 6774543Smarks 6784787Sahrens zfs_deleg_whokey(whokey, 6794787Sahrens dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER, 6804787Sahrens ZFS_DELEG_LOCAL, &uid); 6814543Smarks if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) { 6824543Smarks jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx); 6834543Smarks VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0); 6844543Smarks } 6854543Smarks 6864543Smarks for (zap_cursor_init(&zc, mos, pjumpobj); 6874543Smarks zap_cursor_retrieve(&zc, &za) == 0; 6884543Smarks zap_cursor_advance(&zc)) { 6894787Sahrens uint64_t zero = 0; 6904543Smarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 6914543Smarks 6924543Smarks VERIFY(zap_update(mos, jumpobj, za.za_name, 6934543Smarks 8, 1, &zero, tx) == 0); 6944543Smarks } 6954543Smarks zap_cursor_fini(&zc); 6964543Smarks } 6974543Smarks 6984543Smarks /* 6994543Smarks * set all create time permission on new dataset. 7004543Smarks */ 7014543Smarks void 7024543Smarks dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr) 7034543Smarks { 7044543Smarks dsl_dir_t *dd; 7054787Sahrens uint64_t uid = crgetuid(cr); 7064543Smarks 7074543Smarks if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) < 7085094Slling SPA_VERSION_DELEGATED_PERMS) 7094543Smarks return; 7104543Smarks 7114543Smarks for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) { 7124787Sahrens uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj; 7134543Smarks 7144787Sahrens if (pzapobj == 0) 7154543Smarks continue; 7164543Smarks 7174787Sahrens copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx); 7184787Sahrens copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx); 7194543Smarks } 7204543Smarks } 7214543Smarks 7224543Smarks int 7234543Smarks dsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx) 7244543Smarks { 7254543Smarks zap_cursor_t zc; 7264543Smarks zap_attribute_t za; 7274543Smarks 7284543Smarks if (zapobj == 0) 7294543Smarks return (0); 7304543Smarks 7314543Smarks for (zap_cursor_init(&zc, mos, zapobj); 7324543Smarks zap_cursor_retrieve(&zc, &za) == 0; 7334543Smarks zap_cursor_advance(&zc)) { 7344543Smarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1); 7354543Smarks VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx)); 7364543Smarks } 7374543Smarks zap_cursor_fini(&zc); 7384543Smarks VERIFY(0 == zap_destroy(mos, zapobj, tx)); 7394543Smarks return (0); 7404543Smarks } 7414543Smarks 7424543Smarks boolean_t 7434543Smarks dsl_delegation_on(objset_t *os) 7444543Smarks { 74510922SJeff.Bonwick@Sun.COM return (!!spa_delegation(os->os_spa)); 7464543Smarks } 747