shared: split out crypt() specific helpers into its own .c/.h in src/shared/

This way we can use libxcrypt specific functionality such as
crypt_gensalt() and thus take benefit of the newer algorithms libxcrypt
implements. (Also adds support for a new env var $SYSTEMD_CRYPT_PREFIX
which may be used to select the hash algorithm to use for libxcrypt.)

Also, let's move the weird crypt.h inclusion into libcrypt.h so that
there's a single place for it.
This commit is contained in:
Lennart Poettering 2019-11-13 23:13:42 +01:00
parent 2ee4b118fa
commit 42f3b2f975
8 changed files with 107 additions and 52 deletions

View File

@ -73,6 +73,13 @@ All tools:
appropriate path under /run. This variable is also set by the manager when
RuntimeDirectory= is used, see systemd.exec(5).
* `$SYSTEMD_CRYPT_PREFIX` — if set configures the hash method prefix to use for
UNIX crypt() when generating passwords. By default the system's "preferred
method" is used, but this can be overridden with this environment
variable. Takes a prefix such as `$6$` or `$y$`. (Note that this is only
honoured on systems built with libxcrypt and is ignored on systems using
glibc's original, internal crypt() implementation.)
systemctl:
* `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus

View File

@ -945,40 +945,3 @@ 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;
}

View File

@ -137,6 +137,4 @@ int fgetsgent_sane(FILE *stream, struct sgrp **sg);
int putsgent_sane(const struct sgrp *sg, FILE *stream);
#endif
int make_salt(char **ret);
bool is_nologin_shell(const char *shell);

View File

@ -4,19 +4,6 @@
#include <getopt.h>
#include <unistd.h>
#if HAVE_CRYPT_H
/* libxcrypt is a replacement for glibc's libcrypt, and libcrypt might be
* removed from glibc at some point. As part of the removal, defines for
* crypt(3) are dropped from unistd.h, and we must include crypt.h instead.
*
* Newer versions of glibc (v2.0+) already ship crypt.h with a definition
* of crypt(3) as well, so we simply include it if it is present. MariaDB,
* MySQL, PostgreSQL, Perl and some other wide-spread packages do it the
* same way since ages without any problems.
*/
# include <crypt.h>
#endif
#include "sd-id128.h"
#include "alloc-util.h"
@ -28,6 +15,7 @@
#include "fs-util.h"
#include "hostname-util.h"
#include "kbd-util.h"
#include "libcrypt-util.h"
#include "locale-util.h"
#include "main-func.h"
#include "memory-util.h"

View File

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "libcrypt-util.h"
#include "log.h"
#include "macro.h"
#include "missing_stdlib.h"
#include "random-util.h"
#include "string-util.h"
#include "strv.h"
int make_salt(char **ret) {
#ifdef XCRYPT_VERSION_MAJOR
const char *e;
char *salt;
/* If we have libxcrypt we default to the "preferred method" (i.e. usually yescrypt), and generate it
* with crypt_gensalt_ra(). */
e = secure_getenv("SYSTEMD_CRYPT_PREFIX");
if (!e)
e = crypt_preferred_method();
log_debug("Generating salt for hash prefix: %s", e);
salt = crypt_gensalt_ra(e, 0, NULL, 0);
if (!salt)
return -errno;
*ret = salt;
return 0;
#else
/* If libxcrypt is not used, we use SHA512 and generate the salt on our own since crypt_gensalt_ra()
* is not available. */
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;
#endif
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#if HAVE_CRYPT_H
/* libxcrypt is a replacement for glibc's libcrypt, and libcrypt might be
* removed from glibc at some point. As part of the removal, defines for
* crypt(3) are dropped from unistd.h, and we must include crypt.h instead.
*
* Newer versions of glibc (v2.0+) already ship crypt.h with a definition
* of crypt(3) as well, so we simply include it if it is present. MariaDB,
* MySQL, PostgreSQL, Perl and some other wide-spread packages do it the
* same way since ages without any problems.
*/
#include <crypt.h>
#endif
#include <stdbool.h>
#include <stdlib.h>
int make_salt(char **ret);

View File

@ -106,6 +106,8 @@ shared_sources = files('''
json-internal.h
json.c
json.h
libcrypt-util.c
libcrypt-util.h
libmount-util.h
linux/auto_dev-ioctl.h
linux/bpf.h
@ -279,6 +281,7 @@ libshared_deps = [threads,
libacl,
libblkid,
libcap,
libcrypt,
libcryptsetup,
libgcrypt,
libidn,

View File

@ -2,6 +2,7 @@
#include "alloc-util.h"
#include "format-util.h"
#include "libcrypt-util.h"
#include "log.h"
#include "macro.h"
#include "memory-util.h"