#include "fileio.h"
#include "fs-util.h"
#include "fsck-util.h"
+#include "home-util.h"
#include "homework-luks.h"
#include "homework-mount.h"
#include "id128-util.h"
* strictly round disk sizes down to the next 1K boundary.*/
#define DISK_SIZE_ROUND_DOWN(x) ((x) & ~UINT64_C(1023))
-static bool supported_fstype(const char *fstype) {
- /* Limit the set of supported file systems a bit, as protection against little tested kernel file
- * systems. Also, we only support the resize ioctls for these file systems. */
- return STR_IN_SET(fstype, "ext4", "btrfs", "xfs");
-}
-
static int probe_file_system_by_fd(
int fd,
char **ret_fstype,
const char *cipher_mode,
uint64_t volume_key_size,
char **passwords,
- char **pkcs11_decrypted_passwords,
+ const PasswordCache *cache,
bool discard,
struct crypt_device **ret,
sd_id128_t *ret_found_uuid,
_cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p;
size_t vks;
+ char **list;
int r;
assert(node);
if (!vk)
return log_oom();
- r = luks_try_passwords(cd, pkcs11_decrypted_passwords, vk, &vks);
- if (r == -ENOKEY) {
- r = luks_try_passwords(cd, passwords, vk, &vks);
- if (r == -ENOKEY)
- return log_error_errno(r, "No valid password for LUKS superblock.");
+ r = -ENOKEY;
+ FOREACH_POINTER(list, cache->pkcs11_passwords, cache->fido2_passwords, passwords) {
+ r = luks_try_passwords(cd, list, vk, &vks);
+ if (r != -ENOKEY)
+ break;
}
+ if (r == -ENOKEY)
+ return log_error_errno(r, "No valid password for LUKS superblock.");
if (r < 0)
return log_error_errno(r, "Failed to unlocks LUKS superblock: %m");
static int luks_open(
const char *dm_name,
char **passwords,
- char **pkcs11_decrypted_passwords,
+ PasswordCache *cache,
struct crypt_device **ret,
sd_id128_t *ret_found_uuid,
void **ret_volume_key,
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p;
+ char **list;
size_t vks;
int r;
if (!vk)
return log_oom();
- r = luks_try_passwords(cd, pkcs11_decrypted_passwords, vk, &vks);
- if (r == -ENOKEY) {
- r = luks_try_passwords(cd, passwords, vk, &vks);
- if (r == -ENOKEY)
- return log_error_errno(r, "No valid password for LUKS superblock.");
+ r = -ENOKEY;
+ FOREACH_POINTER(list, cache->pkcs11_passwords, cache->fido2_passwords, passwords) {
+ r = luks_try_passwords(cd, list, vk, &vks);
+ if (r != -ENOKEY)
+ break;
}
+ if (r == -ENOKEY)
+ return log_error_errno(r, "No valid password for LUKS superblock.");
if (r < 0)
return log_error_errno(r, "Failed to unlocks LUKS superblock: %m");
struct crypt_device *cd,
UserRecord *h,
const void *volume_key,
- char ***pkcs11_decrypted_passwords,
+ PasswordCache *cache,
UserRecord **ret_luks_home_record) {
int r, token;
if (!user_record_compatible(h, lhr))
return log_error_errno(SYNTHETIC_ERRNO(EREMCHG), "LUKS home record not compatible with host record, refusing.");
- r = user_record_authenticate(lhr, h, pkcs11_decrypted_passwords);
+ r = user_record_authenticate(lhr, h, cache, /* strict_verify= */ true);
if (r < 0)
return r;
+ assert(r > 0); /* Insist that a password was verified */
*ret_luks_home_record = TAKE_PTR(lhr);
return 0;
UserRecord *h,
bool already_activated,
const char *force_image_path,
- char ***pkcs11_decrypted_passwords,
+ PasswordCache *cache,
HomeSetup *setup,
UserRecord **ret_luks_home) {
r = luks_open(setup->dm_name,
h->password,
- pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL,
+ cache,
&cd,
&found_luks_uuid,
&volume_key,
if (r < 0)
return r;
- r = luks_validate_home_record(cd, h, volume_key, pkcs11_decrypted_passwords, &luks_home);
+ r = luks_validate_home_record(cd, h, volume_key, cache, &luks_home);
if (r < 0)
return r;
h->luks_cipher_mode,
h->luks_volume_key_size,
h->password,
- pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL,
+ cache,
user_record_luks_discard(h) || user_record_luks_offline_discard(h),
&cd,
&found_luks_uuid,
dm_activated = true;
- r = luks_validate_home_record(cd, h, volume_key, pkcs11_decrypted_passwords, &luks_home);
+ r = luks_validate_home_record(cd, h, volume_key, cache, &luks_home);
if (r < 0)
goto fail;
if (r < 0)
goto fail;
- r = home_unshare_and_mount(setup->dm_node, fstype, user_record_luks_discard(h));
+ r = home_unshare_and_mount(setup->dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
goto fail;
int home_activate_luks(
UserRecord *h,
- char ***pkcs11_decrypted_passwords,
+ PasswordCache *cache,
UserRecord **ret_home) {
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL, *luks_home_record = NULL;
h,
false,
NULL,
- pkcs11_decrypted_passwords,
+ cache,
&setup,
&luks_home_record);
if (r < 0)
h,
&setup,
luks_home_record,
- pkcs11_decrypted_passwords,
+ cache,
&sfs,
&new_home);
if (r < 0)
loop_device_relinquish(setup.loop);
- r = dm_deferred_remove(setup.dm_name);
+ r = crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED);
if (r < 0)
log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
const char *dm_name,
sd_id128_t uuid,
const char *label,
- char **pkcs11_decrypted_passwords,
+ const PasswordCache *cache,
char **effective_passwords,
bool discard,
UserRecord *hr,
STRV_FOREACH(pp, effective_passwords) {
- if (strv_contains(pkcs11_decrypted_passwords, *pp)) {
+ if (strv_contains(cache->pkcs11_passwords, *pp) ||
+ strv_contains(cache->fido2_passwords, *pp)) {
log_debug("Using minimal PBKDF for slot %i", slot);
r = crypt_set_pbkdf_type(cd, &minimal_pbkdf);
} else {
usec_t until;
int r;
- /* let's wait for a device link to show up in /dev, with a time-out. This is good to do since we
+ /* let's wait for a device link to show up in /dev, with a timeout. This is good to do since we
* return a /dev/disk/by-uuid/… link to our callers and they likely want to access it right-away,
* hence let's wait until udev has caught up with our changes, and wait for the symlink to be
* created. */
int home_create_luks(
UserRecord *h,
- char **pkcs11_decrypted_passwords,
+ PasswordCache *cache,
char **effective_passwords,
UserRecord **ret_home) {
dm_name,
luks_uuid,
user_record_user_name_and_realm(h),
- pkcs11_decrypted_passwords,
+ cache,
effective_passwords,
user_record_luks_discard(h) || user_record_luks_offline_discard(h),
h,
log_info("Formatting file system completed.");
- r = home_unshare_and_mount(dm_node, fstype, user_record_luks_discard(h));
+ r = home_unshare_and_mount(dm_node, fstype, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
goto fail;
return CAN_RESIZE_ONLINE;
}
-static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool discard) {
+static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool discard, unsigned long flags) {
_cleanup_free_ char *size_str = NULL;
bool re_open = false, re_mount = false;
pid_t resize_pid, fsck_pid;
/* Re-establish mounts and reopen the directory */
if (re_mount) {
- r = home_mount_node(setup->dm_node, "ext4", discard);
+ r = home_mount_node(setup->dm_node, "ext4", discard, flags);
if (r < 0)
return r;
int home_resize_luks(
UserRecord *h,
bool already_activated,
- char ***pkcs11_decrypted_passwords,
+ PasswordCache *cache,
HomeSetup *setup,
UserRecord **ret_home) {
}
}
- r = home_prepare_luks(h, already_activated, whole_disk, pkcs11_decrypted_passwords, setup, &header_home);
+ r = home_prepare_luks(h, already_activated, whole_disk, cache, setup, &header_home);
if (r < 0)
return r;
- r = home_load_embedded_identity(h, setup->root_fd, header_home, USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL, pkcs11_decrypted_passwords, &embedded_home, &new_home);
+ r = home_load_embedded_identity(h, setup->root_fd, header_home, USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL, cache, &embedded_home, &new_home);
if (r < 0)
return r;
if (resize_type == CAN_RESIZE_ONLINE)
r = resize_fs(setup->root_fd, new_fs_size, NULL);
else
- r = ext4_offline_resize_fs(setup, new_fs_size, user_record_luks_discard(h));
+ r = ext4_offline_resize_fs(setup, new_fs_size, user_record_luks_discard(h), user_record_mount_flags(h));
if (r < 0)
return log_error_errno(r, "Failed to resize file system: %m");
int home_passwd_luks(
UserRecord *h,
HomeSetup *setup,
- char **pkcs11_decrypted_passwords, /* the passwords acquired via PKCS#11 security tokens */
- char **effective_passwords /* new passwords */) {
+ PasswordCache *cache, /* the passwords acquired via PKCS#11/FIDO2 security tokens */
+ char **effective_passwords /* new passwords */) {
size_t volume_key_size, i, max_key_slots, n_effective;
_cleanup_(erase_and_freep) void *volume_key = NULL;
struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf;
const char *type;
+ char **list;
int r;
assert(h);
if (!volume_key)
return log_oom();
- r = luks_try_passwords(setup->crypt_device, pkcs11_decrypted_passwords, volume_key, &volume_key_size);
- if (r == -ENOKEY) {
- r = luks_try_passwords(setup->crypt_device, h->password, volume_key, &volume_key_size);
- if (r == -ENOKEY)
- return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Failed to unlock LUKS superblock with supplied passwords.");
+ r = -ENOKEY;
+ FOREACH_POINTER(list, cache->pkcs11_passwords, cache->fido2_passwords, h->password) {
+ r = luks_try_passwords(setup->crypt_device, list, volume_key, &volume_key_size);
+ if (r != -ENOKEY)
+ break;
}
+ if (r == -ENOKEY)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), "Failed to unlock LUKS superblock with supplied passwords.");
if (r < 0)
return log_error_errno(r, "Failed to unlocks LUKS superblock: %m");
continue;
}
- if (strv_find(pkcs11_decrypted_passwords, effective_passwords[i])) {
+ if (strv_contains(cache->pkcs11_passwords, effective_passwords[i]) ||
+ strv_contains(cache->fido2_passwords, effective_passwords[i])) {
log_debug("Using minimal PBKDF for slot %zu", i);
r = crypt_set_pbkdf_type(setup->crypt_device, &minimal_pbkdf);
} else {
return -ENOKEY;
}
-int home_unlock_luks(UserRecord *h, char ***pkcs11_decrypted_passwords) {
+int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ char **list;
int r;
assert(h);
log_info("Discovered used LUKS device %s.", dm_node);
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
- r = luks_try_resume(cd, dm_name, pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL);
- if (r == -ENOKEY) {
- r = luks_try_resume(cd, dm_name, h->password);
- if (r == -ENOKEY)
- return log_error_errno(r, "No valid password for LUKS superblock.");
+ r = -ENOKEY;
+ FOREACH_POINTER(list, cache->pkcs11_passwords, cache->fido2_passwords, h->password) {
+ r = luks_try_resume(cd, dm_name, list);
+ if (r != -ENOKEY)
+ break;
}
+ if (r == -ENOKEY)
+ return log_error_errno(r, "No valid password for LUKS superblock.");
if (r < 0)
return log_error_errno(r, "Failed to resume LUKS superblock: %m");