diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index de0cfced6d9..66f345ee5f7 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -69,6 +69,8 @@ int make_salt(char **ret) { assert_cc(sizeof(table) == 64U + 1U); + log_debug("Generating fallback salt for hash prefix: $6$"); + /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ r = genuine_random_bytes(raw, sizeof(raw), RANDOM_BLOCK); if (r < 0) @@ -90,6 +92,47 @@ int make_salt(char **ret) { #endif } +#if HAVE_CRYPT_RA +# define CRYPT_RA_NAME "crypt_ra" +#else +# define CRYPT_RA_NAME "crypt_r" + +/* Provide a poor man's fallback that uses a fixed size buffer. */ + +static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) { + assert(data); + assert(size); + + /* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this + * implementation of libcrypt; over 128kB in some other implementations). This is large enough that + * it may be unwise to allocate it on the stack. */ + + if (!*data) { + *data = new0(struct crypt_data, 1); + if (!*data) { + errno = -ENOMEM; + return NULL; + } + + *size = (int) (sizeof(struct crypt_data)); + } + + char *t = crypt_r(phrase, setting, *data); + if (!t) + return NULL; + + /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on + * error, so let's just return that. */ + if (t[0] == '*') + return NULL; + + return t; +} + +#define crypt_ra systemd_crypt_ra + +#endif + int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) { _cleanup_free_ char *salt = NULL; _cleanup_(erase_and_freep) void *_cd_data = NULL; @@ -106,7 +149,7 @@ int hash_password_full(const char *password, void **cd_data, int *cd_size, char p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size); if (!p) return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), - "crypt_ra() failed: %m"); + CRYPT_RA_NAME "() failed: %m"); p = strdup(p); if (!p)