Beispiel #1
0
int
dsl_dataset_get_holds(const char *dsname, nvlist_t *nvl)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(dsname, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}

	if (ds->ds_phys->ds_userrefs_obj != 0) {
		zap_attribute_t *za;
		zap_cursor_t zc;

		za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
		for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset,
		    ds->ds_phys->ds_userrefs_obj);
		    zap_cursor_retrieve(&zc, za) == 0;
		    zap_cursor_advance(&zc)) {
			fnvlist_add_uint64(nvl, za->za_name,
			    za->za_first_integer);
		}
		zap_cursor_fini(&zc);
		kmem_free(za, sizeof (zap_attribute_t));
	}
	dsl_dataset_rele(ds, FTAG);
	dsl_pool_rele(dp, FTAG);
	return (0);
}
Beispiel #2
0
/*
 * dsl_pool must not be held when this is called.
 * Upon successful return, there will be a longhold on the dataset,
 * and the dsl_pool will not be held.
 */
int
dmu_objset_own(const char *name, dmu_objset_type_t type,
    boolean_t readonly, void *tag, objset_t **osp)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(name, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_own(dp, name, tag, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}

	err = dmu_objset_from_ds(ds, osp);
	dsl_pool_rele(dp, FTAG);
	if (err != 0) {
		dsl_dataset_disown(ds, tag);
	} else if (type != DMU_OST_ANY && type != (*osp)->os_phys->os_type) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EINVAL));
	} else if (!readonly && dsl_dataset_is_snapshot(ds)) {
		dsl_dataset_disown(ds, tag);
		return (SET_ERROR(EROFS));
	}
	return (err);
}
Beispiel #3
0
int
dsl_deleg_access(const char *dsname, const char *perm, cred_t *cr)
{
    dsl_pool_t *dp;
    dsl_dataset_t *ds;
    int error;

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);
    error = dsl_dataset_hold(dp, dsname, FTAG, &ds);
    if (error == 0) {
        error = dsl_deleg_access_impl(ds, perm, cr);
        dsl_dataset_rele(ds, FTAG);
    }
    dsl_pool_rele(dp, FTAG);

    return (error);
}
Beispiel #4
0
/*
 * dsl_pool must not be held when this is called.
 * Upon successful return, there will be a longhold on the dataset,
 * and the dsl_pool will not be held.
 */
int
dmu_objset_own(const char *name, dmu_objset_type_t type,
    boolean_t readonly, void *tag, objset_t **osp)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(name, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_own(dp, name, tag, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}
	err = dmu_objset_own_impl(ds, type, readonly, tag, osp);
	dsl_pool_rele(dp, FTAG);

	return (err);
}
Beispiel #5
0
/*
 * Retrieve the bookmarks that exist in the specified dataset, and the
 * requested properties of each bookmark.
 *
 * The "props" nvlist specifies which properties are requested.
 * See lzc_get_bookmarks() for the list of valid properties.
 */
int
dsl_get_bookmarks(const char *dsname, nvlist_t *props, nvlist_t *outnvl)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(dsname, FTAG, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_hold(dp, dsname, FTAG, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, FTAG);
		return (err);
	}

	err = dsl_get_bookmarks_impl(ds, props, outnvl);

	dsl_dataset_rele(ds, FTAG);
	dsl_pool_rele(dp, FTAG);
	return (err);
}
Beispiel #6
0
/*
 * Holds the pool while the objset is held.  Therefore only one objset
 * can be held at a time.
 */
int
dmu_objset_hold(const char *name, void *tag, objset_t **osp)
{
	dsl_pool_t *dp;
	dsl_dataset_t *ds;
	int err;

	err = dsl_pool_hold(name, tag, &dp);
	if (err != 0)
		return (err);
	err = dsl_dataset_hold(dp, name, tag, &ds);
	if (err != 0) {
		dsl_pool_rele(dp, tag);
		return (err);
	}

	err = dmu_objset_from_ds(ds, osp);
	if (err != 0) {
		dsl_dataset_rele(ds, tag);
		dsl_pool_rele(dp, tag);
	}

	return (err);
}
Beispiel #7
0
int
dsl_crypto_key_change(char *dsname, zcrypt_key_t *newkey, nvlist_t *props)
{
    struct wkey_change_arg *ca;
    struct kcnode *kcn;
    dsl_dataset_t *ds;
    dsl_props_arg_t pa;
    spa_t *spa;
    int err;
    //dsl_sync_task_group_t *dstg;
    zcrypt_key_t *oldkey;
    dsl_pool_t *dp;

    ASSERT(newkey != NULL);
    ASSERT(dsname != NULL);

    err = dsl_pool_hold(dsname, FTAG, &dp);
    if (err != 0)
        return (err);

    if ((err = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (err);
    }

    /*
     * Take the spa lock here so that new datasets can't get
     * created below us while we are doing a wrapping key change.
     * This is to avoid them being created with the wrong inherited
     * wrapping key.
     */
    err = spa_open(dsname, &spa, FTAG);
    if (err)
        return (err);

    oldkey = zcrypt_key_copy(zcrypt_keystore_find_wrappingkey(spa,
                             ds->ds_object));
    if (oldkey == NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        spa_close(spa, FTAG);
        return (ENOENT);
    }
    ca = kmem_alloc(sizeof (struct wkey_change_arg), KM_SLEEP);
    ca->ca_new_key = newkey;
    ca->ca_old_key = oldkey;
    ca->ca_parent = dsname;
    ca->ca_props = props;

    list_create(&ca->ca_nodes, sizeof (struct kcnode),
                offsetof(struct kcnode, kc_node));

    zcrypt_key_hold(ca->ca_old_key, FTAG);
    zcrypt_key_hold(ca->ca_new_key, FTAG);

    //ca->ca_ds = dsl_sync_task_group_create(spa_get_dsl(spa));

    err = dmu_objset_find(dsname, dsl_crypto_key_change_find,
                          ca, DS_FIND_CHILDREN);

    /*
     * If this is the "top" dataset in this keychange it gets
     * the keysource and salt properties updated.
     */
    pa.pa_props = props;
    pa.pa_source = ZPROP_SRC_LOCAL;
    //pa.pa_flags = 0;
    //pa.pa_zone = curzone;
    //dsl_sync_task_create(ca->ca_dstg, NULL, dsl_props_set_sync, ds, &pa, 2);

    dsl_props_set(dsname, ZPROP_SRC_LOCAL, props);

    //if (err == 0)
    //err = dsl_sync_task_group_wait(dstg);

    while ((kcn = list_head(&ca->ca_nodes))) {
        list_remove(&ca->ca_nodes, kcn);
        dsl_dataset_rele(kcn->kc_ds, kcn);
        kmem_free(kcn, sizeof (struct kcnode));
    }

    //dsl_sync_task_group_destroy(ca->ca_dstg);

    /*
     * We are finished so release and free both the old and new keys.
     * We can free even the new key because everyone got a copy of it
     * not a reference to this one.
     */
    zcrypt_key_release(ca->ca_old_key, FTAG);
    zcrypt_key_free(ca->ca_old_key);
    zcrypt_key_release(ca->ca_new_key, FTAG);
    zcrypt_key_free(ca->ca_new_key);

    kmem_free(ca, sizeof (struct wkey_change_arg));
    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);

    spa_close(spa, FTAG);

    return (err);
}
Beispiel #8
0
static int
dsl_crypto_key_change_find(const char *dsname, void *arg)
{
    struct wkey_change_arg *ca = arg;
    struct kcnode *kcn;
    dsl_dataset_t *ds;
    objset_t *os;
    uint64_t crypt;
    char caource[MAXNAMELEN];
    char setpoint[MAXNAMELEN];
    int err;
    dsl_pool_t *dp;

    err = dsl_pool_hold(dsname, FTAG, &dp);
    if (err != 0)
        return (err);

    kcn = kmem_alloc(sizeof (struct kcnode), KM_SLEEP);
    if ((err = dsl_dataset_hold(dp, dsname, kcn, &ds)) != 0) {
        kmem_free(kcn, sizeof (struct kcnode));
        dsl_pool_rele(dp, FTAG);
        return (err);
    }

    if ((err = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, kcn);
        dsl_pool_rele(dp, FTAG);
        kmem_free(kcn, sizeof (struct kcnode));
        return (err);
    }

    /*
     * Check that this child dataset of ca->parent
     * is actually inheriting keysource from ca->parent and
     * not somewhere else (eg local, or some other dataset).
     */
    rrw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER, FTAG);
    VERIFY(dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                           8, 1, &crypt, NULL/*, DSL_PROP_GET_EFFECTIVE*/) == 0);
    VERIFY(dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_KEYSOURCE), 1,
                           sizeof (caource), &caource, setpoint/*, DSL_PROP_GET_EFFECTIVE*/) == 0);
    rrw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock, FTAG);
    if (crypt == ZIO_CRYPT_OFF ||
            ((strcmp(ca->ca_parent, setpoint) != 0 &&
              strcmp(ca->ca_parent, dsname) != 0))) {
        dsl_dataset_rele(ds, kcn);
        dsl_pool_rele(dp, FTAG);
        kmem_free(kcn, sizeof (struct kcnode));
        return (0);
    }

    //dsl_sync_task_create(ca->ca_dstg, dsl_crypto_key_change_check,
    //  dsl_crypto_key_change_sync, ds, arg, 1);
    ca->ca_ds = ds;
    err = dsl_sync_task(dsname, dsl_crypto_key_change_check,
                        dsl_crypto_key_change_sync, arg,
                        1, ZFS_SPACE_CHECK_NONE);

    kcn->kc_ds = ds;
    list_insert_tail(&ca->ca_nodes, kcn);

    return (0);
}
Beispiel #9
0
int
dsl_crypto_key_new(const char *dsname)
{
    dsl_dataset_t *ds;
    objset_t *os;
    zcrypt_keystore_node_t *skn;
    spa_t *spa;
    struct knarg arg;
    int error;
    dsl_pool_t *dp;
    void *cookie;

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

    if ((error = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (dsl_dataset_is_snapshot(ds)) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    if ((error = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (os->os_crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(os->os_crypt != ZIO_CRYPT_INHERIT);

    /*
     * Need the keychain and wrapping key to already be available.
     */
    spa = dsl_dataset_get_spa(ds);
    skn = zcrypt_keystore_find_node(spa, ds->ds_object, B_FALSE);
    if (skn == NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOENT);
    }

    ASSERT(ds != NULL);
    ASSERT(ds->ds_objset != NULL);

    //zil_suspend_dmu_sync(dmu_objset_zil(os));
    zil_suspend(dsname, &cookie);

    arg.kn_skn = skn;
    arg.kn_txgkey = zcrypt_key_gen(os->os_crypt);
    arg.kn_ds = ds;
    zcrypt_key_hold(skn->skn_wrapkey, FTAG);
    VERIFY(zcrypt_wrap_key(skn->skn_wrapkey, arg.kn_txgkey,
                           &arg.kn_wkeybuf, &arg.kn_wkeylen,
                           zio_crypt_select_wrap(os->os_crypt)) == 0);

    error = dsl_sync_task(spa->spa_name, dsl_crypto_key_new_check,
                          dsl_crypto_key_new_sync, &arg, 1,
                          ZFS_SPACE_CHECK_NONE);

    kmem_free(arg.kn_wkeybuf, arg.kn_wkeylen);

    zcrypt_key_release(skn->skn_wrapkey, FTAG);

    //zil_resume_dmu_sync(dmu_objset_zil(os));
    zil_resume(os);

    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);

    if (error)
        zcrypt_key_free(arg.kn_txgkey);
    return (error);
}
Beispiel #10
0
int
dsl_crypto_key_inherit(const char *dsname)
{
    char keysource[MAXNAMELEN];
    char setpoint[MAXNAMELEN];
    dsl_dataset_t *ids;
    int error;
    zcrypt_key_t *wrappingkey;
    zfs_crypt_key_status_t keystatus;
    spa_t *spa;
    dsl_pool_t *dp;

    /*
     * Try inheriting the wrapping key from our parent
     */
    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

    error = dsl_dataset_keystatus_byname(dp, dsname, &keystatus);
    if (error != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }
    if (keystatus == ZFS_CRYPT_KEY_NONE) {
        dsl_pool_rele(dp, FTAG);
        return (0);
    }
    if (keystatus == ZFS_CRYPT_KEY_AVAILABLE) {
        dsl_pool_rele(dp, FTAG);
        return (EEXIST);
    }

    error = dsl_prop_get(dsname, zfs_prop_to_name(ZFS_PROP_KEYSOURCE), 1,
                         sizeof (keysource), &keysource, setpoint);
    if (error != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (strcmp(setpoint, dsname) == 0) {
        dsl_pool_rele(dp, FTAG);
        return (ENOENT);
    }

    error = dsl_dataset_hold(dp, setpoint, FTAG, &ids);
    if (error != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    spa = dsl_dataset_get_spa(ids);
    wrappingkey = zcrypt_key_copy(zcrypt_keystore_find_wrappingkey(spa,
                                  ids->ds_object));
    dsl_dataset_rele(ids, FTAG);
    dsl_pool_rele(dp, FTAG);

    if (wrappingkey == NULL)
        return (ENOENT);

    error = dsl_crypto_key_load(dsname, wrappingkey);

    return (error);
}
Beispiel #11
0
int
dsl_crypto_key_load(const char *dsname, zcrypt_key_t *wrappingkey)
{
    dsl_dataset_t *ds;
    uint64_t crypt;
    int error;
    dsl_pool_t *dp;

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

    if ((error = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    /*
     * This is key load not key change so if ds->ds_key is already
     * set we fail.
     */
    if (zcrypt_keystore_find_node(dsl_dataset_get_spa(ds),
                                  ds->ds_object, B_FALSE) != NULL) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (EEXIST);
    }

    /*
     * Find out what size of key we expect.
     *
     * For now the wrapping key size (and type) matches the size
     * of the dataset key, this may not always be the case
     * (particularly if we ever support wrapping dataset keys
     * with asymmetric keys (eg RSA)).
     *
     * When alternate wrapping keys are added it maybe done using
     * a index property.
     */
    rrw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER, FTAG);
    error = dsl_prop_get_ds(ds, zfs_prop_to_name(ZFS_PROP_ENCRYPTION),
                            8, 1, &crypt, NULL/*, DSL_PROP_GET_EFFECTIVE*/);
    rrw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock, FTAG);
    if (error != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if (crypt == ZIO_CRYPT_OFF) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (ENOTSUP);
    }

    ASSERT(crypt != ZIO_CRYPT_INHERIT);

    error = dsl_keychain_load(ds, crypt, wrappingkey);
    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (error);
}
Beispiel #12
0
/*
 * dsl_crypto_key_unload
 *
 * Remove the key from the in memory keystore.
 *
 * First we have to remove the minor node for a ZVOL or unmount
 * the filesystem.  This is so that we flush all pending IO for it to disk
 * so we won't need to encrypt anything with this key.  Anything in flight
 * should already have a lock on the keys it needs.
 * We can't assume that userland has already successfully unmounted the
 * dataset though in many cases it will have.
 *
 * If the key can't be removed return the failure back to our caller.
 */
int
dsl_crypto_key_unload(const char *dsname)
{
    dsl_dataset_t *ds;
    objset_t *os;
    int error;
    spa_t *spa;
    dsl_pool_t *dp;
#ifdef _KERNEL
    dmu_objset_type_t os_type;
    //vfs_t *vfsp;
    struct vfsmount *vfsp;
#endif /* _KERNEL */

    error = dsl_pool_hold(dsname, FTAG, &dp);
    if (error != 0)
        return (error);

    /* XXX - should we use own_exclusive() here? */
    if ((error = dsl_dataset_hold(dp, dsname, FTAG, &ds)) != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    if ((error = dmu_objset_from_ds(ds, &os)) != 0) {
        dsl_dataset_rele(ds, FTAG);
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

#ifdef _KERNEL
    /*
     * Make sure that the device node has gone for ZVOLs
     * and that filesystems are umounted.
     */
#if 0 // FIXME
    os_type = dmu_objset_type(os);
    if (os_type == DMU_OST_ZVOL) {
        error = zvol_remove_minor(dsname);
        if (error == ENXIO)
            error = 0;
    } else if (os_type == DMU_OST_ZFS) {
        vfsp = zfs_get_vfs(dsname);
        if (vfsp != NULL) {
            error = vn_vfswlock(vfsp->vfs_vnodecovered);
            VFS_RELE(vfsp);
            if (error == 0)
                error = dounmount(vfsp, 0, CRED());
        }
    }
    if (error != 0) {
        dsl_dataset_rele(ds, FTAG);
        return (error);
    }
#endif

#endif /* _KERNEL */

    /*
     * Make sure all dbufs are synced.
     *
     * It is essential for encrypted datasets to ensure that
     * there is no further pending IO before removing the key.
     */
    if (dmu_objset_is_dirty(os, 0)) // FIXME, 0?
        txg_wait_synced(dmu_objset_pool(os), 0);
    dmu_objset_evict_dbufs(os);

    spa = dsl_dataset_get_spa(ds);
    error = zcrypt_keystore_remove(spa, ds->ds_object);

    dsl_dataset_rele(ds, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (error);
}
Beispiel #13
0
/*
 * Find all 'allow' permissions from a given point and then continue
 * traversing up to the root.
 *
 * This function constructs an nvlist of nvlists.
 * each setpoint is an nvlist composed of an nvlist of an nvlist
 * of the individual * users/groups/everyone/create
 * permissions.
 *
 * The nvlist will look like this.
 *
 * { source fsname -> { whokeys { permissions,...}, ...}}
 *
 * The fsname nvpairs will be arranged in a bottom up order.  For example,
 * if we have the following structure a/b/c then the nvpairs for the fsnames
 * will be ordered a/b/c, a/b, a.
 */
int
dsl_deleg_get(const char *ddname, nvlist_t **nvp)
{
    dsl_dir_t *dd, *startdd;
    dsl_pool_t *dp;
    int error;
    objset_t *mos;
    zap_cursor_t *basezc, *zc;
    zap_attribute_t *baseza, *za;
    char *source;

    error = dsl_pool_hold(ddname, FTAG, &dp);
    if (error != 0)
        return (error);

    error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
    if (error != 0) {
        dsl_pool_rele(dp, FTAG);
        return (error);
    }

    dp = startdd->dd_pool;
    mos = dp->dp_meta_objset;

    zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
    za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
    basezc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP);
    baseza = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP);
    source = kmem_alloc(MAXNAMELEN + strlen(MOS_DIR_NAME) + 1, KM_SLEEP);
    VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);

    for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
        nvlist_t *sp_nvp;
        uint64_t n;

        if (dd->dd_phys->dd_deleg_zapobj == 0 ||
                zap_count(mos, dd->dd_phys->dd_deleg_zapobj, &n) != 0 ||
                n == 0)
            continue;

        sp_nvp = fnvlist_alloc();
        for (zap_cursor_init(basezc, mos,
                             dd->dd_phys->dd_deleg_zapobj);
                zap_cursor_retrieve(basezc, baseza) == 0;
                zap_cursor_advance(basezc)) {
            nvlist_t *perms_nvp;

            ASSERT(baseza->za_integer_length == 8);
            ASSERT(baseza->za_num_integers == 1);

            perms_nvp = fnvlist_alloc();
            for (zap_cursor_init(zc, mos, baseza->za_first_integer);
                    zap_cursor_retrieve(zc, za) == 0;
                    zap_cursor_advance(zc)) {
                fnvlist_add_boolean(perms_nvp, za->za_name);
            }
            zap_cursor_fini(zc);
            fnvlist_add_nvlist(sp_nvp, baseza->za_name, perms_nvp);
            fnvlist_free(perms_nvp);
        }

        zap_cursor_fini(basezc);

        dsl_dir_name(dd, source);
        fnvlist_add_nvlist(*nvp, source, sp_nvp);
        nvlist_free(sp_nvp);
    }

    kmem_free(source, MAXNAMELEN + strlen(MOS_DIR_NAME) + 1);
    kmem_free(baseza, sizeof (zap_attribute_t));
    kmem_free(basezc, sizeof (zap_cursor_t));
    kmem_free(za, sizeof (zap_attribute_t));
    kmem_free(zc, sizeof (zap_cursor_t));

    dsl_dir_rele(startdd, FTAG);
    dsl_pool_rele(dp, FTAG);
    return (0);
}
Beispiel #14
0
/*
 * Find all 'allow' permissions from a given point and then continue
 * traversing up to the root.
 *
 * This function constructs an nvlist of nvlists.
 * each setpoint is an nvlist composed of an nvlist of an nvlist
 * of the individual * users/groups/everyone/create
 * permissions.
 *
 * The nvlist will look like this.
 *
 * { source fsname -> { whokeys { permissions,...}, ...}}
 *
 * The fsname nvpairs will be arranged in a bottom up order.  For example,
 * if we have the following structure a/b/c then the nvpairs for the fsnames
 * will be ordered a/b/c, a/b, a.
 */
int
dsl_deleg_get(const char *ddname, nvlist_t **nvp)
{
	dsl_dir_t *dd, *startdd;
	dsl_pool_t *dp;
	int error;
	objset_t *mos;

	error = dsl_pool_hold(ddname, FTAG, &dp);
	if (error != 0)
		return (error);

	error = dsl_dir_hold(dp, ddname, FTAG, &startdd, NULL);
	if (error != 0) {
		dsl_pool_rele(dp, FTAG);
		return (error);
	}

	dp = startdd->dd_pool;
	mos = dp->dp_meta_objset;

	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);

	for (dd = startdd; dd != NULL; dd = dd->dd_parent) {
		zap_cursor_t basezc;
		zap_attribute_t baseza;
		nvlist_t *sp_nvp;
		uint64_t n;
		char source[ZFS_MAX_DATASET_NAME_LEN];

		if (dsl_dir_phys(dd)->dd_deleg_zapobj == 0 ||
		    zap_count(mos,
		    dsl_dir_phys(dd)->dd_deleg_zapobj, &n) != 0 || n == 0)
			continue;

		sp_nvp = fnvlist_alloc();
		for (zap_cursor_init(&basezc, mos,
		    dsl_dir_phys(dd)->dd_deleg_zapobj);
		    zap_cursor_retrieve(&basezc, &baseza) == 0;
		    zap_cursor_advance(&basezc)) {
			zap_cursor_t zc;
			zap_attribute_t za;
			nvlist_t *perms_nvp;

			ASSERT(baseza.za_integer_length == 8);
			ASSERT(baseza.za_num_integers == 1);

			perms_nvp = fnvlist_alloc();
			for (zap_cursor_init(&zc, mos, baseza.za_first_integer);
			    zap_cursor_retrieve(&zc, &za) == 0;
			    zap_cursor_advance(&zc)) {
				fnvlist_add_boolean(perms_nvp, za.za_name);
			}
			zap_cursor_fini(&zc);
			fnvlist_add_nvlist(sp_nvp, baseza.za_name, perms_nvp);
			fnvlist_free(perms_nvp);
		}

		zap_cursor_fini(&basezc);

		dsl_dir_name(dd, source);
		fnvlist_add_nvlist(*nvp, source, sp_nvp);
		nvlist_free(sp_nvp);
	}

	dsl_dir_rele(startdd, FTAG);
	dsl_pool_rele(dp, FTAG);
	return (0);
}