ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * CDDL HEADER START
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * The contents of this file are subject to the terms of the
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Common Development and Distribution License (the "License").
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * You may not use this file except in compliance with the License.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * See the License for the specific language governing permissions
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * and limitations under the License.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * When distributing Covered Code, include this CDDL HEADER in each
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * If applicable, add the following below this CDDL HEADER, with the
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * fields enclosed by brackets "[]" replaced with your own identifying
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * information: Portions Copyright [yyyy] [name of copyright owner]
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * CDDL HEADER END
99d5e173470cf967aa87653364ed614299e7b511Tim Haley * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
9adfa60d484ce2435f5af77cc99dcd4e692b6660Matthew Ahrens * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * DSL permissions are stored in a two level zap attribute
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * mechanism. The first level identifies the "class" of
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * entry. The class is identified by the first 2 letters of
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * the attribute. The second letter "l" or "d" identifies whether
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * it is a local or descendent permission. The first letter
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * identifies the type of entry.
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * ul$<id> identifies permissions granted locally for this userid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * ud$<id> identifies permissions granted on descendent datasets for
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * this userid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Ul$<id> identifies permission sets granted locally for this userid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Ud$<id> identifies permission sets granted on descendent datasets for
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * this userid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * gl$<id> identifies permissions granted locally for this groupid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * gd$<id> identifies permissions granted on descendent datasets for
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * this groupid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Gl$<id> identifies permission sets granted locally for this groupid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Gd$<id> identifies permission sets granted on descendent datasets for
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * this groupid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * el$ identifies permissions granted locally for everyone.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * ed$ identifies permissions granted on descendent datasets
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * for everyone.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * El$ identifies permission sets granted locally for everyone.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Ed$ identifies permission sets granted to descendent datasets for
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * everyone.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * c-$ identifies permission to create at dataset creation time.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * C-$ identifies permission sets to grant locally at dataset creation
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * s-$@<name> permissions defined in specified set @<name>
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * S-$@<name> Sets defined in named set @<name>
da6c28aaf62fa55f0fdb8004aa40f88f23bf53f0amw * Each of the above entities points to another zap attribute that contains one
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * attribute for each allowed permission, such as create, destroy,...
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * All of the "upper" case class types will specify permission set names
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * rather than permissions.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Basically it looks something like this:
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * ul$12 -> ZAP OBJ -> permissions...
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * The ZAP OBJ is referred to as the jump object.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Validate that user is allowed to delegate specified permissions.
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens * In order to delegate "create" you must have "create"
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * and "allow".
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksdsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks while (permpair = nvlist_next_nvpair(perms, permpair)) {
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Validate that user is allowed to unallow specified permissions. They
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * must have the 'allow' permission, and even then can only unallow
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * perms for their uid.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksdsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr)
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks if (zapobj == 0) {
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens while (whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair)) {
3cb34c601f3ef3016f638574f5982e80c3735c71ahrens if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden jumpobj = zap_create_link(mos, DMU_OT_DSL_PERMS,
3cb34c601f3ef3016f638574f5982e80c3735c71ahrens while (permpair = nvlist_next_nvpair(perms, permpair)) {
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens spa_history_log_internal_dd(dd, "permission update", tx,
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL));
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens while (whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair)) {
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens spa_history_log_internal_dd(dd, "permission who remove",
3cb34c601f3ef3016f638574f5982e80c3735c71ahrens if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks while (permpair = nvlist_next_nvpair(perms, permpair)) {
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens spa_history_log_internal_dd(dd, "permission remove", tx,
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens error = dsl_dir_hold(dmu_tx_pool(tx), dda->dda_name, FTAG, &dd, NULL);
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrensdsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset)
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens /* nvp must already have been verified to be valid */
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens return (dsl_sync_task(ddname, dsl_deleg_check,
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens unset ? dsl_deleg_unset_sync : dsl_deleg_set_sync,
7d46dc6ca63a6f3f0d51aa655bfcf10cf2405a9eMatthew Ahrens &dda, fnvlist_num_pairs(nvp), ZFS_SPACE_CHECK_RESERVED));
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Find all 'allow' permissions from a given point and then continue
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * traversing up to the root.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * This function constructs an nvlist of nvlists.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * each setpoint is an nvlist composed of an nvlist of an nvlist
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * permissions.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * The nvlist will look like this.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * { source fsname -> { whokeys { permissions,...}, ...}}
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * The fsname nvpairs will be arranged in a bottom up order. For example,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * if we have the following structure a/b/c then the nvpairs for the fsnames
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * will be ordered a/b/c, a/b, a.
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens fnvlist_add_nvlist(sp_nvp, baseza.za_name, perms_nvp);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Routines for dsl_deleg_access() -- access checking.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Determine whether a specified permission exists.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * First the base attribute has to be retrieved. i.e. ul$12
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Once the base object has been retrieved the actual permission
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * is lookup up in the zap object the base object points to.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Return 0 if permission exists, ENOENT if there is no whokey, EPERM if
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * there is no perm in that jumpobj.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks char type, char checkflag, void *valp, const char *perm)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks if (error == 0) {
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * check a specified user/group for a requested permission
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrensdsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* check for user */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* check for users primary group */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* check for everyone entry */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* check each supplemental group user is a member of */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks for (i = 0; i != ngids; i++) {
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Iterate over the sets specified in the specified zapobj
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * and load them into the permsets avl tree.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks char type, char checkflag, void *valp, avl_tree_t *avl)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks error = zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Load all permissions user based on cred belongs to.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksdsl_load_user_sets(objset_t *mos, uint64_t zapobj, avl_tree_t *avl,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks for (i = 0; i != ngids; i++) {
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens * Check if user has requested permission.
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrensdsl_deleg_access_impl(dsl_dataset_t *ds, const char *perm, cred_t *cr)
8b33e2134db3b64f2e6c6eae17656c335ad99addWilliam Gorrell * Snapshots are treated as descendents only,
8b33e2134db3b64f2e6c6eae17656c335ad99addWilliam Gorrell * local permissions do not apply.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks avl_create(&permsets, perm_set_compare, sizeof (perm_set_t),
bb0ade0978a02d3fe0b0165cd4725fdcb593fbfbahrens for (dd = ds->ds_dir; dd != NULL; dd = dd->dd_parent,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * If not in global zone then make sure
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * the zoned property is set
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* See if this set directly grants this permission */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks /* See if this set includes other sets */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * If we expanded any sets, that will define more sets,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * which we need to check.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks error = dsl_check_user_access(mos, zapobj, perm, checkflag, cr);
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
a7f53a5629374ca27c5696ace9a1946c2ca050f4Chris Kirbydsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
3b2aab18808792cbd248a12f1edf139b89833c13Matthew Ahrens error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Other routines.
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs uint64_t zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
91ebeef555ce7f899b6270a3c2df47b51f7ad59aahrens if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks if (zapobj == 0) {
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs zapobj = dsl_dir_phys(dd)->dd_deleg_zapobj = zap_create(mos,
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * set all create time permission on new dataset.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksdsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
c1379625401dfbe1c39b79136dd384a571d47fdeJustin T. Gibbs uint64_t pzapobj = dsl_dir_phys(dd)->dd_deleg_zapobj;
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksdsl_deleg_destroy(objset_t *mos, uint64_t zapobj, dmu_tx_t *tx)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks VERIFY(0 == zap_destroy(mos, za.za_first_integer, tx));
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks return (0);