mirror of
https://git.proxmox.com/git/mirror_zfs
synced 2025-04-28 11:40:17 +00:00
Add recursive dataset mounting and unmounting support to pam_zfs_key (#16857)
Introduced functionality to recursively mount datasets with a new config option `mount_recursively`. Adjusted existing functions to handle the recursive behavior and added tests to validate the feature. This enhances support for managing hierarchical ZFS datasets within a PAM context. Signed-off-by: Jerzy Kołosowski <jerzy@kolosowscy.pl> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Tony Hutter <hutter2@llnl.gov>
This commit is contained in:
parent
1e32c57893
commit
387ed5ca41
@ -63,6 +63,7 @@ pam_syslog(pam_handle_t *pamh, int loglevel, const char *fmt, ...)
|
||||
#include <sys/file.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
#include <lib/libzfs/libzfs_impl.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
|
||||
@ -370,67 +371,6 @@ change_key(pam_handle_t *pamh, const char *ds_name,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
decrypt_mount(pam_handle_t *pamh, const char *ds_name,
|
||||
const char *passphrase, boolean_t noop)
|
||||
{
|
||||
zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM);
|
||||
if (ds == NULL) {
|
||||
pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name);
|
||||
return (-1);
|
||||
}
|
||||
pw_password_t *key = prepare_passphrase(pamh, ds, passphrase, NULL);
|
||||
if (key == NULL) {
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
int ret = lzc_load_key(ds_name, noop, (uint8_t *)key->value,
|
||||
WRAPPING_KEY_LEN);
|
||||
pw_free(key);
|
||||
if (ret && ret != EEXIST) {
|
||||
pam_syslog(pamh, LOG_ERR, "load_key failed: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
if (noop) {
|
||||
goto out;
|
||||
}
|
||||
ret = zfs_mount(ds, NULL, 0);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR, "mount failed: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
out:
|
||||
zfs_close(ds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
unmount_unload(pam_handle_t *pamh, const char *ds_name, boolean_t force)
|
||||
{
|
||||
zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM);
|
||||
if (ds == NULL) {
|
||||
pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name);
|
||||
return (-1);
|
||||
}
|
||||
int ret = zfs_unmount(ds, NULL, force ? MS_FORCE : 0);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR, "zfs_unmount failed with: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = lzc_unload_key(ds_name);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR, "unload_key failed with: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
zfs_close(ds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *homes_prefix;
|
||||
char *runstatedir;
|
||||
@ -443,6 +383,7 @@ typedef struct {
|
||||
boolean_t unmount_and_unload;
|
||||
boolean_t force_unmount;
|
||||
boolean_t recursive_homes;
|
||||
boolean_t mount_recursively;
|
||||
} zfs_key_config_t;
|
||||
|
||||
static int
|
||||
@ -481,6 +422,7 @@ zfs_key_config_load(pam_handle_t *pamh, zfs_key_config_t *config,
|
||||
config->unmount_and_unload = B_TRUE;
|
||||
config->force_unmount = B_FALSE;
|
||||
config->recursive_homes = B_FALSE;
|
||||
config->mount_recursively = B_FALSE;
|
||||
config->dsname = NULL;
|
||||
config->homedir = NULL;
|
||||
for (int c = 0; c < argc; c++) {
|
||||
@ -500,6 +442,8 @@ zfs_key_config_load(pam_handle_t *pamh, zfs_key_config_t *config,
|
||||
config->force_unmount = B_TRUE;
|
||||
} else if (strcmp(argv[c], "recursive_homes") == 0) {
|
||||
config->recursive_homes = B_TRUE;
|
||||
} else if (strcmp(argv[c], "mount_recursively") == 0) {
|
||||
config->mount_recursively = B_TRUE;
|
||||
} else if (strcmp(argv[c], "prop_mountpoint") == 0) {
|
||||
if (config->homedir == NULL)
|
||||
config->homedir = strdup(entry->pw_dir);
|
||||
@ -508,6 +452,217 @@ zfs_key_config_load(pam_handle_t *pamh, zfs_key_config_t *config,
|
||||
return (PAM_SUCCESS);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
pam_handle_t *pamh;
|
||||
zfs_key_config_t *target;
|
||||
} mount_umount_dataset_data_t;
|
||||
|
||||
static int
|
||||
mount_dataset(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
mount_umount_dataset_data_t *mount_umount_dataset_data = data;
|
||||
|
||||
zfs_key_config_t *target = mount_umount_dataset_data->target;
|
||||
pam_handle_t *pamh = mount_umount_dataset_data->pamh;
|
||||
|
||||
/* Refresh properties to get the latest key status */
|
||||
zfs_refresh_properties(zhp);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
/* Check if dataset type is filesystem */
|
||||
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) {
|
||||
pam_syslog(pamh, LOG_DEBUG,
|
||||
"dataset is not filesystem: %s, skipping.",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if encryption key is available */
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_KEYSTATUS) ==
|
||||
ZFS_KEYSTATUS_UNAVAILABLE) {
|
||||
pam_syslog(pamh, LOG_WARNING,
|
||||
"key unavailable for: %s, skipping",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Check if prop canmount is on */
|
||||
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) != ZFS_CANMOUNT_ON) {
|
||||
pam_syslog(pamh, LOG_INFO,
|
||||
"canmount is not on for: %s, skipping",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get mountpoint prop for check */
|
||||
char mountpoint[ZFS_MAXPROPLEN];
|
||||
if ((ret = zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint,
|
||||
sizeof (mountpoint), NULL, NULL, 0, 1)) != 0) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"failed to get mountpoint prop: %d", ret);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Check if mountpoint isn't none or legacy */
|
||||
if (strcmp(mountpoint, ZFS_MOUNTPOINT_NONE) == 0 ||
|
||||
strcmp(mountpoint, ZFS_MOUNTPOINT_LEGACY) == 0) {
|
||||
pam_syslog(pamh, LOG_INFO,
|
||||
"mountpoint is none or legacy for: %s, skipping",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Don't mount the dataset if already mounted */
|
||||
if (zfs_is_mounted(zhp, NULL)) {
|
||||
pam_syslog(pamh, LOG_INFO, "already mounted: %s",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Mount the dataset */
|
||||
ret = zfs_mount(zhp, NULL, 0);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"zfs_mount failed for %s with: %d", zfs_get_name(zhp),
|
||||
ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Recursively mount children if the recursive flag is set */
|
||||
if (target->mount_recursively) {
|
||||
ret = zfs_iter_filesystems_v2(zhp, 0, mount_dataset, data);
|
||||
if (ret != 0) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"child iteration failed: %d", ret);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
umount_dataset(zfs_handle_t *zhp, void *data)
|
||||
{
|
||||
mount_umount_dataset_data_t *mount_umount_dataset_data = data;
|
||||
|
||||
zfs_key_config_t *target = mount_umount_dataset_data->target;
|
||||
pam_handle_t *pamh = mount_umount_dataset_data->pamh;
|
||||
|
||||
int ret = 0;
|
||||
/* Recursively umount children if the recursive flag is set */
|
||||
if (target->mount_recursively) {
|
||||
ret = zfs_iter_filesystems_v2(zhp, 0, umount_dataset, data);
|
||||
if (ret != 0) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"child iteration failed: %d", ret);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if dataset type is filesystem */
|
||||
if (zhp->zfs_type != ZFS_TYPE_FILESYSTEM) {
|
||||
pam_syslog(pamh, LOG_DEBUG,
|
||||
"dataset is not filesystem: %s, skipping",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Don't umount the dataset if already unmounted */
|
||||
if (zfs_is_mounted(zhp, NULL) == 0) {
|
||||
pam_syslog(pamh, LOG_INFO, "already unmounted: %s",
|
||||
zfs_get_name(zhp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Unmount the dataset */
|
||||
ret = zfs_unmount(zhp, NULL, target->force_unmount ? MS_FORCE : 0);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"zfs_unmount failed for %s with: %d", zfs_get_name(zhp),
|
||||
ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
decrypt_mount(pam_handle_t *pamh, zfs_key_config_t *config, const char *ds_name,
|
||||
const char *passphrase, boolean_t noop)
|
||||
{
|
||||
zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM);
|
||||
if (ds == NULL) {
|
||||
pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name);
|
||||
return (-1);
|
||||
}
|
||||
pw_password_t *key = prepare_passphrase(pamh, ds, passphrase, NULL);
|
||||
if (key == NULL) {
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
int ret = lzc_load_key(ds_name, noop, (uint8_t *)key->value,
|
||||
WRAPPING_KEY_LEN);
|
||||
pw_free(key);
|
||||
if (ret && ret != EEXIST) {
|
||||
pam_syslog(pamh, LOG_ERR, "load_key failed: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (noop) {
|
||||
zfs_close(ds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
mount_umount_dataset_data_t data;
|
||||
data.pamh = pamh;
|
||||
data.target = config;
|
||||
|
||||
ret = mount_dataset(ds, &data);
|
||||
if (ret != 0) {
|
||||
pam_syslog(pamh, LOG_ERR, "mount failed: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
zfs_close(ds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
unmount_unload(pam_handle_t *pamh, const char *ds_name,
|
||||
zfs_key_config_t *target)
|
||||
{
|
||||
zfs_handle_t *ds = zfs_open(g_zfs, ds_name, ZFS_TYPE_FILESYSTEM);
|
||||
if (ds == NULL) {
|
||||
pam_syslog(pamh, LOG_ERR, "dataset %s not found", ds_name);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
mount_umount_dataset_data_t data;
|
||||
data.pamh = pamh;
|
||||
data.target = target;
|
||||
|
||||
int ret = umount_dataset(ds, &data);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"unmount_dataset failed with: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
ret = lzc_unload_key(ds_name);
|
||||
if (ret) {
|
||||
pam_syslog(pamh, LOG_ERR, "unload_key failed with: %d", ret);
|
||||
zfs_close(ds);
|
||||
return (-1);
|
||||
}
|
||||
zfs_close(ds);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
zfs_key_config_free(zfs_key_config_t *config)
|
||||
{
|
||||
@ -548,7 +703,7 @@ find_dsname_by_prop_value(zfs_handle_t *zhp, void *data)
|
||||
}
|
||||
|
||||
static char *
|
||||
zfs_key_config_get_dataset(zfs_key_config_t *config)
|
||||
zfs_key_config_get_dataset(pam_handle_t *pamh, zfs_key_config_t *config)
|
||||
{
|
||||
if (config->homedir != NULL &&
|
||||
config->homes_prefix != NULL) {
|
||||
@ -559,7 +714,7 @@ zfs_key_config_get_dataset(zfs_key_config_t *config)
|
||||
zfs_handle_t *zhp = zfs_open(g_zfs,
|
||||
config->homes_prefix, ZFS_TYPE_FILESYSTEM);
|
||||
if (zhp == NULL) {
|
||||
pam_syslog(NULL, LOG_ERR,
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"dataset %s not found",
|
||||
config->homes_prefix);
|
||||
return (NULL);
|
||||
@ -697,13 +852,13 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
char *dataset = zfs_key_config_get_dataset(&config);
|
||||
char *dataset = zfs_key_config_get_dataset(pamh, &config);
|
||||
if (!dataset) {
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
if (decrypt_mount(pamh, dataset, token->value, B_TRUE) == -1) {
|
||||
if (decrypt_mount(pamh, &config, dataset, token->value, B_TRUE) == -1) {
|
||||
free(dataset);
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
@ -749,7 +904,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
char *dataset = zfs_key_config_get_dataset(&config);
|
||||
char *dataset = zfs_key_config_get_dataset(pamh, &config);
|
||||
if (!dataset) {
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
@ -763,7 +918,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
if (decrypt_mount(pamh, dataset,
|
||||
if (decrypt_mount(pamh, &config, dataset,
|
||||
old_token->value, B_TRUE) == -1) {
|
||||
pam_syslog(pamh, LOG_ERR,
|
||||
"old token mismatch");
|
||||
@ -784,7 +939,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||
pw_clear(pamh, OLD_PASSWORD_VAR_NAME);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
char *dataset = zfs_key_config_get_dataset(&config);
|
||||
char *dataset = zfs_key_config_get_dataset(pamh, &config);
|
||||
if (!dataset) {
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
@ -793,7 +948,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
int was_loaded = is_key_loaded(pamh, dataset);
|
||||
if (!was_loaded && decrypt_mount(pamh, dataset,
|
||||
if (!was_loaded && decrypt_mount(pamh, &config, dataset,
|
||||
old_token->value, B_FALSE) == -1) {
|
||||
free(dataset);
|
||||
pam_zfs_free();
|
||||
@ -804,7 +959,7 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
|
||||
}
|
||||
int changed = change_key(pamh, dataset, token->value);
|
||||
if (!was_loaded) {
|
||||
unmount_unload(pamh, dataset, config.force_unmount);
|
||||
unmount_unload(pamh, dataset, &config);
|
||||
}
|
||||
free(dataset);
|
||||
pam_zfs_free();
|
||||
@ -856,13 +1011,14 @@ pam_sm_open_session(pam_handle_t *pamh, int flags,
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
char *dataset = zfs_key_config_get_dataset(&config);
|
||||
char *dataset = zfs_key_config_get_dataset(pamh, &config);
|
||||
if (!dataset) {
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
if (decrypt_mount(pamh, dataset, token->value, B_FALSE) == -1) {
|
||||
if (decrypt_mount(pamh, &config, dataset,
|
||||
token->value, B_FALSE) == -1) {
|
||||
free(dataset);
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
@ -910,13 +1066,13 @@ pam_sm_close_session(pam_handle_t *pamh, int flags,
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SERVICE_ERR);
|
||||
}
|
||||
char *dataset = zfs_key_config_get_dataset(&config);
|
||||
char *dataset = zfs_key_config_get_dataset(pamh, &config);
|
||||
if (!dataset) {
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
return (PAM_SESSION_ERR);
|
||||
}
|
||||
if (unmount_unload(pamh, dataset, config.force_unmount) == -1) {
|
||||
if (unmount_unload(pamh, dataset, &config) == -1) {
|
||||
free(dataset);
|
||||
pam_zfs_free();
|
||||
zfs_key_config_free(&config);
|
||||
|
@ -27,8 +27,8 @@ tests = ['zfs_jail_001_pos']
|
||||
tags = ['functional', 'cli_root', 'zfs_jail']
|
||||
|
||||
[tests/functional/pam:FreeBSD]
|
||||
tests = ['pam_basic', 'pam_change_unmounted', 'pam_nounmount', 'pam_recursive',
|
||||
'pam_short_password']
|
||||
tests = ['pam_basic', 'pam_change_unmounted', 'pam_mount_recursively',
|
||||
'pam_nounmount', 'pam_recursive', 'pam_short_password']
|
||||
tags = ['functional', 'pam']
|
||||
|
||||
[tests/functional/direct:FreeBSD]
|
||||
|
@ -169,8 +169,8 @@ tests = ['umount_unlinked_drain']
|
||||
tags = ['functional', 'mount']
|
||||
|
||||
[tests/functional/pam:Linux]
|
||||
tests = ['pam_basic', 'pam_change_unmounted', 'pam_nounmount', 'pam_recursive',
|
||||
'pam_short_password']
|
||||
tests = ['pam_basic', 'pam_change_unmounted', 'pam_mount_recursively',
|
||||
'pam_nounmount', 'pam_recursive', 'pam_short_password']
|
||||
tags = ['functional', 'pam']
|
||||
|
||||
[tests/functional/procfs:Linux]
|
||||
|
@ -1696,6 +1696,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/pam/cleanup.ksh \
|
||||
functional/pam/pam_basic.ksh \
|
||||
functional/pam/pam_change_unmounted.ksh \
|
||||
functional/pam/pam_mount_recursively.ksh \
|
||||
functional/pam/pam_nounmount.ksh \
|
||||
functional/pam/pam_recursive.ksh \
|
||||
functional/pam/pam_short_password.ksh \
|
||||
|
@ -26,5 +26,6 @@ rmconfig
|
||||
destroy_pool $TESTPOOL
|
||||
del_user ${username}
|
||||
del_user ${username}rec
|
||||
del_user ${username}mrec
|
||||
del_group pamtestgroup
|
||||
log_must rm -rf "$runstatedir"
|
||||
|
90
tests/zfs-tests/tests/functional/pam/pam_mount_recursively.ksh
Executable file
90
tests/zfs-tests/tests/functional/pam/pam_mount_recursively.ksh
Executable file
@ -0,0 +1,90 @@
|
||||
#!/bin/ksh -p
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/pam/utilities.kshlib
|
||||
|
||||
if [ -n "$ASAN_OPTIONS" ]; then
|
||||
export LD_PRELOAD=$(ldd "$(command -v zfs)" | awk '/libasan\.so/ {print $3}')
|
||||
fi
|
||||
|
||||
username="${username}mrec"
|
||||
|
||||
# Set up a deeper hierarchy, a mountpoint that doesn't interfere with other tests,
|
||||
# and a user which references that mountpoint
|
||||
log_must zfs create "$TESTPOOL/mrec"
|
||||
log_must zfs create -o mountpoint="$TESTDIR/mrec" "$TESTPOOL/mrec/pam"
|
||||
echo "recurpass" | zfs create -o encryption=aes-256-gcm -o keyformat=passphrase \
|
||||
-o keylocation=prompt "$TESTPOOL/mrec/pam/${username}"
|
||||
log_must zfs create "$TESTPOOL/mrec/pam/${username}/deep"
|
||||
log_must zfs create "$TESTPOOL/mrec/pam/${username}/deep/deeper"
|
||||
log_must zfs create -o mountpoint=none "$TESTPOOL/mrec/pam/${username}/deep/none"
|
||||
log_must zfs create -o canmount=noauto "$TESTPOOL/mrec/pam/${username}/deep/noauto"
|
||||
log_must zfs create -o canmount=off "$TESTPOOL/mrec/pam/${username}/deep/off"
|
||||
log_must zfs unmount "$TESTPOOL/mrec/pam/${username}"
|
||||
log_must zfs unload-key "$TESTPOOL/mrec/pam/${username}"
|
||||
log_must add_user pamtestgroup ${username} "$TESTDIR/mrec"
|
||||
|
||||
function keystatus {
|
||||
log_must [ "$(get_prop keystatus "$TESTPOOL/mrec/pam/${username}")" = "$1" ]
|
||||
}
|
||||
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}"
|
||||
keystatus unavailable
|
||||
|
||||
function test_session {
|
||||
echo "recurpass" | pamtester ${pamservice} ${username} open_session
|
||||
references 1
|
||||
log_must ismounted "$TESTPOOL/mrec/pam/${username}"
|
||||
log_must ismounted "$TESTPOOL/mrec/pam/${username}/deep"
|
||||
log_must ismounted "$TESTPOOL/mrec/pam/${username}/deep/deeper"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/none"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/noauto"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/off"
|
||||
keystatus available
|
||||
|
||||
log_must pamtester ${pamservice} ${username} close_session
|
||||
references 0
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/deeper"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/none"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/noauto"
|
||||
log_mustnot ismounted "$TESTPOOL/mrec/pam/${username}/deep/off"
|
||||
keystatus unavailable
|
||||
}
|
||||
|
||||
genconfig "homes=$TESTPOOL/mrec/pam mount_recursively runstatedir=${runstatedir}"
|
||||
test_session
|
||||
|
||||
genconfig "homes=$TESTPOOL/mrec/pam prop_mountpoint mount_recursively runstatedir=${runstatedir}"
|
||||
test_session
|
||||
|
||||
genconfig "homes=$TESTPOOL/mrec recursive_homes prop_mountpoint mount_recursively runstatedir=${runstatedir}"
|
||||
test_session
|
||||
|
||||
genconfig "homes=$TESTPOOL recursive_homes prop_mountpoint mount_recursively runstatedir=${runstatedir}"
|
||||
test_session
|
||||
|
||||
genconfig "homes=* recursive_homes prop_mountpoint mount_recursively runstatedir=${runstatedir}"
|
||||
test_session
|
||||
|
||||
log_pass "done."
|
Loading…
Reference in New Issue
Block a user