blob: 25a90b5905304d7e80528c1456ca94078a55494d [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "ask-password-api.h"
#include "cryptenroll-password.h"
#include "env-util.h"
#include "escape.h"
#include "memory-util.h"
#include "pwquality-util.h"
#include "strv.h"
int load_volume_key_password(
struct crypt_device *cd,
const char *cd_node,
void *ret_vk,
size_t *ret_vks) {
_cleanup_(erase_and_freep) char *envpw = NULL;
int r;
assert_se(cd);
assert_se(cd_node);
assert_se(ret_vk);
assert_se(ret_vks);
r = getenv_steal_erase("PASSWORD", &envpw);
if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r > 0) {
r = crypt_volume_key_get(
cd,
CRYPT_ANY_SLOT,
ret_vk,
ret_vks,
envpw,
strlen(envpw));
if (r < 0)
return log_error_errno(r, "Password from environment variable $PASSWORD did not work.");
} else {
AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED;
_cleanup_free_ char *question = NULL, *disk_path = NULL;
unsigned i = 5;
const char *id;
question = strjoin("Please enter current passphrase for disk ", cd_node, ":");
if (!question)
return log_oom();
disk_path = cescape(cd_node);
if (!disk_path)
return log_oom();
id = strjoina("cryptsetup:", disk_path);
for (;;) {
_cleanup_strv_free_erase_ char **passwords = NULL;
if (--i == 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
"Too many attempts, giving up:");
r = ask_password_auto(
question, "drive-harddisk", id, "cryptenroll", "cryptenroll.passphrase", USEC_INFINITY,
ask_password_flags,
&passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
r = -EPERM;
STRV_FOREACH(p, passwords) {
r = crypt_volume_key_get(
cd,
CRYPT_ANY_SLOT,
ret_vk,
ret_vks,
*p,
strlen(*p));
if (r >= 0)
break;
}
if (r >= 0)
break;
log_error_errno(r, "Password not correct, please try again.");
ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
}
}
return r;
}
int enroll_password(
struct crypt_device *cd,
const void *volume_key,
size_t volume_key_size) {
_cleanup_(erase_and_freep) char *new_password = NULL;
_cleanup_free_ char *error = NULL;
const char *node;
int r, keyslot;
assert_se(node = crypt_get_device_name(cd));
r = getenv_steal_erase("NEWPASSWORD", &new_password);
if (r < 0)
return log_error_errno(r, "Failed to acquire password from environment: %m");
if (r == 0) {
_cleanup_free_ char *disk_path = NULL;
unsigned i = 5;
const char *id;
assert_se(node = crypt_get_device_name(cd));
(void) suggest_passwords();
disk_path = cescape(node);
if (!disk_path)
return log_oom();
id = strjoina("cryptsetup:", disk_path);
for (;;) {
_cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL;
_cleanup_free_ char *question = NULL;
if (--i == 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
"Too many attempts, giving up:");
question = strjoin("Please enter new passphrase for disk ", node, ":");
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
assert(strv_length(passwords) == 1);
free(question);
question = strjoin("Please enter new passphrase for disk ", node, " (repeat):");
if (!question)
return log_oom();
r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", "cryptenroll.new-passphrase", USEC_INFINITY, 0, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
assert(strv_length(passwords2) == 1);
if (strv_equal(passwords, passwords2)) {
new_password = passwords2[0];
passwords2 = mfree(passwords2);
break;
}
log_error("Password didn't match, try again.");
}
}
r = quality_check_password(new_password, NULL, &error);
if (r < 0)
return log_error_errno(r, "Failed to check password for quality: %m");
if (r == 0)
log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", error);
keyslot = crypt_keyslot_add_by_volume_key(
cd,
CRYPT_ANY_SLOT,
volume_key,
volume_key_size,
new_password,
strlen(new_password));
if (keyslot < 0)
return log_error_errno(keyslot, "Failed to add new password to %s: %m", node);
log_info("New password enrolled as key slot %i.", keyslot);
return keyslot;
}