summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/ENVIRONMENT.md7
-rw-r--r--src/basic/user-util.c37
-rw-r--r--src/basic/user-util.h2
-rw-r--r--src/firstboot/firstboot.c14
-rw-r--r--src/shared/libcrypt-util.c75
-rw-r--r--src/shared/libcrypt-util.h20
-rw-r--r--src/shared/meson.build3
-rw-r--r--src/test/test-user-util.c1
8 files changed, 107 insertions, 52 deletions
diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 9b1df6b59c..fec40b1e9c 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -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
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 571578c4e4..68c6dd0da7 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -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;
-}
diff --git a/src/basic/user-util.h b/src/basic/user-util.h
index e11dd9b379..714e83082c 100644
--- a/src/basic/user-util.h
+++ b/src/basic/user-util.h
@@ -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);
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 528e6452cf..8001f90d57 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -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"
diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c
new file mode 100644
index 0000000000..b1a8168030
--- /dev/null
+++ b/src/shared/libcrypt-util.c
@@ -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
+}
diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h
new file mode 100644
index 0000000000..3da1ab5ad9
--- /dev/null
+++ b/src/shared/libcrypt-util.h
@@ -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);
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 08aa480b6c..f4f5ebf3c4 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -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,
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index fde8336bf9..6bfe7dc7e1 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -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"