diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index f8499a6ffd..3109f9cdfc 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -802,7 +802,7 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor static int process_root_args(void) { _cleanup_close_ int lock = -1; - struct crypt_data cd = {}; + _cleanup_(erase_and_freep) char *_hashed_password = NULL; const char *password, *hashed_password; const char *etc_passwd, *etc_shadow; int r; @@ -866,20 +866,13 @@ static int process_root_args(void) { password = "x"; hashed_password = arg_root_password; } else if (arg_root_password) { - _cleanup_free_ char *salt = NULL; - /* hashed_password points inside cd after crypt_r returns so cd has function scope. */ + r = hash_password(arg_root_password, &_hashed_password); + if (r < 0) + return log_error_errno(r, "Failed to hash password: %m"); password = "x"; + hashed_password = _hashed_password; - r = make_salt(&salt); - if (r < 0) - return log_error_errno(r, "Failed to get salt: %m"); - - errno = 0; - hashed_password = crypt_r(arg_root_password, salt, &cd); - if (!hashed_password) - return log_error_errno(errno == 0 ? SYNTHETIC_ERRNO(EINVAL) : errno, - "Failed to encrypt password: %m"); } else if (arg_delete_root_password) password = hashed_password = ""; else diff --git a/src/home/homectl-fido2.c b/src/home/homectl-fido2.c index b7b2c1a3b5..b9092df18c 100644 --- a/src/home/homectl-fido2.c +++ b/src/home/homectl-fido2.c @@ -70,31 +70,23 @@ static int add_fido2_salt( size_t secret_size) { _cleanup_(json_variant_unrefp) JsonVariant *l = NULL, *w = NULL, *e = NULL; - _cleanup_(erase_and_freep) char *base64_encoded = NULL; - _cleanup_free_ char *unix_salt = NULL; - struct crypt_data cd = {}; - char *k; + _cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL; int r; - r = make_salt(&unix_salt); - if (r < 0) - return log_error_errno(r, "Failed to generate salt: %m"); - /* Before using UNIX hashing on the supplied key we base64 encode it, since crypt_r() and friends * expect a NUL terminated string, and we use a binary key */ r = base64mem(secret, secret_size, &base64_encoded); if (r < 0) return log_error_errno(r, "Failed to base64 encode secret key: %m"); - errno = 0; - k = crypt_r(base64_encoded, unix_salt, &cd); - if (!k) + r = hash_password(base64_encoded, &hashed); + if (r < 0) return log_error_errno(errno_or_else(EINVAL), "Failed to UNIX hash secret key: %m"); r = json_build(&e, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("credential", JSON_BUILD_BASE64(cid, cid_size)), JSON_BUILD_PAIR("salt", JSON_BUILD_BASE64(fido2_salt, fido2_salt_size)), - JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(k)))); + JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)))); if (r < 0) return log_error_errno(r, "Failed to build FIDO2 salt JSON key object: %m"); diff --git a/src/home/homectl-pkcs11.c b/src/home/homectl-pkcs11.c index f4253ed7bf..21c9b9a6a3 100644 --- a/src/home/homectl-pkcs11.c +++ b/src/home/homectl-pkcs11.c @@ -134,10 +134,7 @@ static int add_pkcs11_encrypted_key( const void *decrypted_key, size_t decrypted_key_size) { _cleanup_(json_variant_unrefp) JsonVariant *l = NULL, *w = NULL, *e = NULL; - _cleanup_(erase_and_freep) char *base64_encoded = NULL; - _cleanup_free_ char *salt = NULL; - struct crypt_data cd = {}; - char *k; + _cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL; int r; assert(v); @@ -147,25 +144,20 @@ static int add_pkcs11_encrypted_key( assert(decrypted_key); assert(decrypted_key_size > 0); - r = make_salt(&salt); - if (r < 0) - return log_error_errno(r, "Failed to generate salt: %m"); - /* Before using UNIX hashing on the supplied key we base64 encode it, since crypt_r() and friends * expect a NUL terminated string, and we use a binary key */ r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); if (r < 0) return log_error_errno(r, "Failed to base64 encode secret key: %m"); - errno = 0; - k = crypt_r(base64_encoded, salt, &cd); - if (!k) + r = hash_password(base64_encoded, &hashed); + if (r < 0) return log_error_errno(errno_or_else(EINVAL), "Failed to UNIX hash secret key: %m"); r = json_build(&e, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("uri", JSON_BUILD_STRING(uri)), JSON_BUILD_PAIR("data", JSON_BUILD_BASE64(encrypted_key, encrypted_key_size)), - JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(k)))); + JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)))); if (r < 0) return log_error_errno(r, "Failed to build encrypted JSON key object: %m"); diff --git a/src/home/homectl-recovery-key.c b/src/home/homectl-recovery-key.c index 9d7f345f1e..c63d3415f4 100644 --- a/src/home/homectl-recovery-key.c +++ b/src/home/homectl-recovery-key.c @@ -183,9 +183,7 @@ static int print_qr_code(const char *secret) { } int identity_add_recovery_key(JsonVariant **v) { - _cleanup_(erase_and_freep) char *unix_salt = NULL, *password = NULL; - struct crypt_data cd = {}; - char *k; + _cleanup_(erase_and_freep) char *password = NULL, *hashed = NULL; int r; assert(v); @@ -196,17 +194,12 @@ int identity_add_recovery_key(JsonVariant **v) { return r; /* Let's UNIX hash it */ - r = make_salt(&unix_salt); + r = hash_password(password, &hashed); if (r < 0) - return log_error_errno(r, "Failed to generate salt: %m"); - - errno = 0; - k = crypt_r(password, unix_salt, &cd); - if (!k) return log_error_errno(errno_or_else(EINVAL), "Failed to UNIX hash secret key: %m"); /* Let's now add the "privileged" version of the recovery key */ - r = add_privileged(v, k); + r = add_privileged(v, hashed); if (r < 0) return r; diff --git a/src/home/homework.c b/src/home/homework.c index 594c4a05bb..986ce2b3f0 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -17,6 +17,7 @@ #include "homework-mount.h" #include "homework-pkcs11.h" #include "homework.h" +#include "libcrypt-util.h" #include "main-func.h" #include "memory-util.h" #include "missing_magic.h" diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 0bbe44ce26..6928427730 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -806,20 +806,13 @@ int user_record_make_hashed_password(UserRecord *h, char **secret, bool extend) } STRV_FOREACH(i, secret) { - _cleanup_free_ char *salt = NULL; - struct crypt_data cd = {}; - char *k; + _cleanup_(erase_and_freep) char *hashed = NULL; - r = make_salt(&salt); + r = hash_password(*i, &hashed); if (r < 0) return r; - errno = 0; - k = crypt_r(*i, salt, &cd); - if (!k) - return errno_or_else(EINVAL); - - r = strv_extend(&np, k); + r = strv_consume(&np, TAKE_PTR(hashed)); if (r < 0) return r; } diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index bf6605508a..d19bcf1d8a 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -4,6 +4,7 @@ #include #include "alloc-util.h" +#include "errno-util.h" #include "libcrypt-util.h" #include "log.h" #include "macro.h" @@ -74,6 +75,30 @@ int make_salt(char **ret) { #endif } +int hash_password(const char *password, char **ret) { + _cleanup_free_ char *salt = NULL; + char *p; + struct crypt_data cd = {}; + int r; + + r = make_salt(&salt); + if (r < 0) + return log_debug_errno(r, "Failed to generate salt: %m"); + + errno = 0; + p = crypt_r(password, salt, &cd); + if (!p) + return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), + "crypt_r() failed: %m"); + + p = strdup(p); + if (!p) + return -ENOMEM; + + *ret = p; + return 0; +} + bool looks_like_hashed_password(const char *s) { /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists * various hashing methods. We only reject (return false) strings which are documented to have diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index 8a860ceb0d..b10be2f7d2 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -18,5 +18,5 @@ #include int make_salt(char **ret); - +int hash_password(const char *password, char **ret); bool looks_like_hashed_password(const char *s);