From f2c5edbe5a5f601be5fe7c73fa4007a243b1d52e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Apr 2019 18:17:04 +0200 Subject: [PATCH 1/2] user-util: add generic make_salt() API --- src/basic/user-util.c | 38 ++++++++++++++++++++++++++++++++++++++ src/basic/user-util.h | 2 ++ 2 files changed, 40 insertions(+) diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 2090675b0d..1dd8e11e9e 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -22,6 +22,7 @@ #include "missing.h" #include "parse-util.h" #include "path-util.h" +#include "random-util.h" #include "string-util.h" #include "strv.h" #include "user-util.h" @@ -870,3 +871,40 @@ int fgetsgent_sane(FILE *stream, struct sgrp **sg) { return !!s; } #endif + +int make_salt(char **ret) { + static const char table[] = + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "./"; + + uint8_t raw[16]; + char *salt, *j; + size_t i; + int r; + + /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but + * SHA512, i.e. is legacy-free and minimizes our deps. */ + + assert_cc(sizeof(table) == 64U + 1U); + + /* 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) + return r; + + salt = new(char, 3+sizeof(raw)+1+1); + if (!salt) + return -ENOMEM; + + /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ + j = stpcpy(salt, "$6$"); + for (i = 0; i < sizeof(raw); i++) + j[i] = table[raw[i] & 63]; + j[i++] = '$'; + j[i] = 0; + + *ret = salt; + return 0; +} diff --git a/src/basic/user-util.h b/src/basic/user-util.h index cc899ee76f..52f3df792d 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -113,3 +113,5 @@ int putgrent_sane(const struct group *gr, FILE *stream); int fgetsgent_sane(FILE *stream, struct sgrp **sg); int putsgent_sane(const struct sgrp *sg, FILE *stream); #endif + +int make_salt(char **ret); From 3862043310de6e68bdc7ba0c45f2149445c91aa1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Apr 2019 18:17:17 +0200 Subject: [PATCH 2/2] firstboot: port to make_salt() Also, let's use crypt_r() over crypt(). Not because we actually use threads, but because it's safer and more future proof in general. --- src/firstboot/firstboot.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index c21cf76b93..7d97777b0d 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -595,12 +595,6 @@ static int write_root_shadow(const char *path, const struct spwd *p) { static int process_root_password(void) { - static const char table[] = - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789" - "./"; - struct spwd item = { .sp_namp = (char*) "root", .sp_min = -1, @@ -610,12 +604,9 @@ static int process_root_password(void) { .sp_expire = -1, .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ }; - + _cleanup_free_ char *salt = NULL; _cleanup_close_ int lock = -1; - char salt[3+16+1+1]; - uint8_t raw[16]; - unsigned i; - char *j; + struct crypt_data cd = {}; const char *etc_shadow; int r; @@ -659,27 +650,15 @@ static int process_root_password(void) { if (!arg_root_password) return 0; - /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ - r = genuine_random_bytes(raw, 16, RANDOM_BLOCK); + r = make_salt(&salt); if (r < 0) return log_error_errno(r, "Failed to get salt: %m"); - /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ - assert_cc(sizeof(table) == 64 + 1); - j = stpcpy(salt, "$6$"); - for (i = 0; i < 16; i++) - j[i] = table[raw[i] & 63]; - j[i++] = '$'; - j[i] = 0; - errno = 0; - item.sp_pwdp = crypt(arg_root_password, salt); - if (!item.sp_pwdp) { - if (!errno) - errno = EINVAL; - - return log_error_errno(errno, "Failed to encrypt password: %m"); - } + item.sp_pwdp = crypt_r(arg_root_password, salt, &cd); + if (!item.sp_pwdp) + return log_error_errno(errno == 0 ? SYNTHETIC_ERRNO(EINVAL) : errno, + "Failed to encrypt password: %m"); item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY);