newer though. TL;DR: turn audit off, still.
glibc >= 2.31
- libxcrypt or glibc (<= 2.38 built with --enable-crypt)
+ libxcrypt >= 4.4.0
libmount >= 2.30 (from util-linux)
(util-linux *must* be built without --enable-libmount-support-mtab)
libseccomp >= 2.4.0 (optional)
libatomic = []
endif
-libcrypt = dependency('libcrypt', 'libxcrypt', required : false)
-if not libcrypt.found()
- # fallback to use find_library() if libcrypt is provided by glibc, e.g. for LibreELEC.
- libcrypt = cc.find_library('crypt')
+if get_option('libc') == 'musl'
+ libcrypt = []
+else
+ libcrypt = dependency('libcrypt', 'libxcrypt',
+ required : true,
+ version : '>=4.4.0')
endif
-foreach func : [
- 'crypt_ra', # since libxcrypt-4.0.0
- 'crypt_gensalt_ra', # since libxcrypt-4.0.0
- 'crypt_preferred_method', # since libxcrypt-4.4.0
-]
-
- have = cc.has_function(func, prefix : '''#include <crypt.h>''', args : '-D_GNU_SOURCE',
- dependencies : libcrypt)
- conf.set10('HAVE_' + func.to_upper(), have)
-endforeach
-
bpf_framework = get_option('bpf-framework')
bpf_compiler = get_option('bpf-compiler')
libbpf = dependency('libbpf',
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include_next <crypt.h>
+
+const char* missing_crypt_preferred_method(void);
+#define crypt_preferred_method missing_crypt_preferred_method
+
+char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes);
+#define crypt_gensalt_ra missing_crypt_gensalt_ra
+
+char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size);
+#define crypt_ra missing_crypt_ra
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <assert.h>
+#include <crypt.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/random.h>
+
+const char* missing_crypt_preferred_method(void) {
+ return "$6$";
+}
+
+char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes) {
+ static const char table[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "./";
+
+ static_assert(sizeof(table) == 64U + 1U);
+
+ /* This doesn't do anything but SHA512, and silently ignore all arguments, to make it legacy-free and
+ * minimize the implementation. */
+
+ /* Insist on the best randomness by getrandom(), this is about keeping passwords secret after all. */
+ uint8_t raw[16];
+ for (size_t i = 0; i < sizeof(raw);) {
+ size_t n = sizeof(raw) - i;
+ ssize_t l = getrandom(raw + i, n, 0);
+ if (l < 0)
+ return NULL;
+ if (l == 0) {
+ /* Weird, should never happen. */
+ errno = EIO;
+ return NULL;
+ }
+
+ if ((size_t) l == n)
+ break; /* Done reading, success. */
+
+ i += l;
+ /* Interrupted by a signal; keep going. */
+ }
+
+ /* "$6$" + salt + "$" + NUL */
+ char *salt = malloc(3 + sizeof(raw) + 1 + 1);
+ if (!salt) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
+ char *p = stpcpy(salt, "$6$");
+ for (size_t i = 0; i < sizeof(raw); i++)
+ *p++ = table[raw[i] & 63];
+ *p++ = '$';
+ *p = '\0';
+
+ return salt;
+}
+
+char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size) {
+ struct crypt_data *buf = NULL;
+ bool allocated = false;
+
+ if (!phrase || !setting || !data || !size) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (*data) {
+ if (*size != sizeof(struct crypt_data)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ buf = *data;
+ } else {
+ if (*size != 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ buf = calloc(1, sizeof(struct crypt_data));
+ if (!buf) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ allocated = true;
+ }
+
+ /* 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. */
+
+ char *t = crypt_r(phrase, setting, buf);
+ if (!t || t[0] == '*') {
+ if (allocated)
+ free(buf);
+ return NULL;
+ }
+
+ if (allocated) {
+ *data = buf;
+ *size = sizeof(struct crypt_data);
+ }
+ return t;
+}
endif
libc_wrapper_sources += files(
+ 'crypt.c',
'getopt.c',
'printf.c',
'stdio.c',
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <crypt.h>
-#include <stdlib.h>
#include "alloc-util.h"
#include "errno-util.h"
#include "libcrypt-util.h"
#include "log.h"
-#include "random-util.h" /* IWYU pragma: keep */
#include "string-util.h"
#include "strv.h"
int make_salt(char **ret) {
- assert(ret);
-
-#if HAVE_CRYPT_GENSALT_RA
const char *e;
char *salt;
- /* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt).
- * crypt_gensalt_ra() is usually provided by libxcrypt. */
+ assert(ret);
e = secure_getenv("SYSTEMD_CRYPT_PREFIX");
if (!e)
-#if HAVE_CRYPT_PREFERRED_METHOD
e = crypt_preferred_method();
-#else
- e = "$6$";
-#endif
log_debug("Generating salt for hash prefix: %s", e);
*ret = salt;
return 0;
-#else
- /* If crypt_gensalt_ra() is not available, we use SHA512 and generate the salt on our own. */
-
- 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);
-
- 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 = crypto_random_bytes(raw, sizeof(raw));
- 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
-}
-
-#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(phrase);
- assert(setting);
- 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(const char *password, char **ret) {
_cleanup_free_ char *salt = NULL;
_cleanup_(erase_and_freep) void *cd_data = NULL;
errno = 0;
p = crypt_ra(password, salt, &cd_data, &cd_size);
if (!p)
- return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
- CRYPT_RA_NAME "() failed: %m");
+ return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), "crypt_ra() failed: %m");
return strdup_to(ret, p);
}
#include "tests.h"
TEST(crypt_preferred_method) {
- log_info("crypt_preferred_method: %s",
-#if HAVE_CRYPT_PREFERRED_METHOD
- crypt_preferred_method()
-#else
- "(not available)"
-#endif
- );
+ log_info("crypt_preferred_method: %s", crypt_preferred_method());
}
TEST(make_salt) {
}
TEST(hash_password) {
-#if defined(__powerpc__) && !defined(XCRYPT_VERSION_MAJOR)
- return log_tests_skipped("crypt_r() causes a buffer overflow on ppc64el, see https://github.com/systemd/systemd/pull/16981#issuecomment-691203787");
-#endif
-
/* As a warm-up exercise, check if we can hash passwords. */
FOREACH_STRING(hash,
"ew3bU1.hoKk4o",
ASSERT_OK_ZERO(test_password_one(hash, "ppp"));
continue;
}
-#elif !defined(XCRYPT_VERSION_MAJOR)
- ASSERT_OK(test_password_one(hash, "ppp"));
- continue;
#endif
ASSERT_OK_POSITIVE(test_password_one(hash, "ppp"));
}