diff --git a/README b/README index 83493b0417..2d6d30dc78 100644 --- a/README +++ b/README @@ -212,7 +212,7 @@ REQUIREMENTS: newer though. TL;DR: turn audit off, still. glibc >= 2.31 - libxcrypt or glibc (<= 2.38 built with --enable-crypt) + libxcrypt >= 4.4.0 (optional) libmount >= 2.30 (from util-linux) (util-linux *must* be built without --enable-libmount-support-mtab) libseccomp >= 2.4.0 (optional) diff --git a/meson.build b/meson.build index cc26bbd63e..ff8cb279a8 100644 --- a/meson.build +++ b/meson.build @@ -685,15 +685,6 @@ conf.set('GPERF_LEN_TYPE', gperf_len_type, ##################################################################### -foreach header : [ - 'crypt.h', -] - - if not cc.has_header(header) - error(f'Header file @header@ not found') - endif -endforeach - foreach header : [ 'gshadow.h', 'nss.h', @@ -1046,22 +1037,18 @@ else 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 = [] + libcrypt_cflags = [] + have = get_option('libcrypt').allowed() +else + libcrypt = dependency('libcrypt', 'libxcrypt', + required : get_option('libcrypt'), + version : '>=4.4.0') + libcrypt_cflags = libcrypt.partial_dependency(includes: true, compile_args: true) + have = libcrypt.found() 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 ''', args : '-D_GNU_SOURCE', - dependencies : libcrypt) - conf.set10('HAVE_' + func.to_upper(), have) -endforeach +conf.set10('HAVE_LIBCRYPT', have) bpf_framework = get_option('bpf-framework') bpf_compiler = get_option('bpf-compiler') @@ -1594,10 +1581,11 @@ conf.set10('ENABLE_SYSUPDATED', have2) conf.set10('ENABLE_STORAGETM', get_option('storagetm')) have = get_option('homed').require( + conf.get('HAVE_LIBCRYPT') == 1 and conf.get('HAVE_OPENSSL') == 1 and conf.get('HAVE_LIBFDISK') == 1 and conf.get('HAVE_LIBCRYPTSETUP') == 1, - error_message : 'openssl, fdisk and libcryptsetup required').allowed() + error_message : 'libcrypt, openssl, fdisk, and libcryptsetup required').allowed() conf.set10('ENABLE_HOMED', have) have = have and conf.get('HAVE_PAM') == 1 @@ -3124,6 +3112,7 @@ foreach tuple : [ ['gnutls'], ['libarchive'], ['libbpf'], + ['libcrypt'], ['libcryptsetup'], ['libcryptsetup-plugins'], ['libcurl'], diff --git a/meson_options.txt b/meson_options.txt index 4ce3c7faca..5061869483 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -426,6 +426,8 @@ option('pwquality', type : 'feature', deprecated : { 'true' : 'enabled', 'false' description : 'libpwquality support') option('microhttpd', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libµhttpd support') +option('libcrypt', type : 'feature', + description : 'libcrypt/libxcrypt support') option('libcryptsetup', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, description : 'libcryptsetup support') option('libcryptsetup-plugins', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' }, diff --git a/src/firstboot/meson.build b/src/firstboot/meson.build index 28c1d2703a..e83eded6ad 100644 --- a/src/firstboot/meson.build +++ b/src/firstboot/meson.build @@ -6,6 +6,5 @@ executables += [ 'public' : true, 'conditions' : ['ENABLE_FIRSTBOOT'], 'sources' : files('firstboot.c'), - 'dependencies' : libcrypt, }, ] diff --git a/src/home/meson.build b/src/home/meson.build index dbb374ce4a..1efee1619e 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -64,7 +64,6 @@ executables += [ 'sources' : systemd_homed_sources, 'extract' : systemd_homed_extract_sources, 'dependencies' : [ - libcrypt, libm, libopenssl, threads, @@ -80,7 +79,6 @@ executables += [ ], 'dependencies' : [ libblkid_cflags, - libcrypt, libfdisk, libopenssl, libp11kit_cflags, @@ -93,7 +91,6 @@ executables += [ 'sources' : homectl_sources, 'objects' : ['systemd-homed'], 'dependencies' : [ - libcrypt, libdl, libopenssl, libp11kit_cflags, @@ -112,7 +109,6 @@ modules += [ 'conditions' : ['HAVE_PAM'], 'sources' : pam_systemd_home_sources, 'dependencies' : [ - libcrypt, libintl, libpam_misc, libpam, diff --git a/src/include/musl/crypt.h b/src/include/musl/crypt.h new file mode 100644 index 0000000000..64570f7046 --- /dev/null +++ b/src/include/musl/crypt.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include_next + +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 diff --git a/src/libc/musl/crypt.c b/src/libc/musl/crypt.c new file mode 100644 index 0000000000..d44113fdc6 --- /dev/null +++ b/src/libc/musl/crypt.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/src/libc/musl/meson.build b/src/libc/musl/meson.build index d40a2f1911..4fabac7bcc 100644 --- a/src/libc/musl/meson.build +++ b/src/libc/musl/meson.build @@ -5,6 +5,7 @@ if get_option('libc') != 'musl' endif libc_wrapper_sources += files( + 'crypt.c', 'getopt.c', 'printf.c', 'stdio.c', diff --git a/src/shared/libcrypt-util.c b/src/shared/libcrypt-util.c index 594963ac6b..85069314be 100644 --- a/src/shared/libcrypt-util.c +++ b/src/shared/libcrypt-util.c @@ -1,145 +1,160 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include -#include +#if HAVE_LIBCRYPT +# include +#endif #include "alloc-util.h" +#include "dlfcn-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) { +#if HAVE_LIBCRYPT +static void *libcrypt_dl = NULL; -#if HAVE_CRYPT_GENSALT_RA +static DLSYM_PROTOTYPE(crypt_gensalt_ra) = NULL; +static DLSYM_PROTOTYPE(crypt_preferred_method) = NULL; +static DLSYM_PROTOTYPE(crypt_ra) = NULL; + +int dlopen_libcrypt(void) { +#ifdef __GLIBC__ + static int cached = 0; + int r; + + if (libcrypt_dl) + return 0; /* Already loaded */ + + if (cached < 0) + return cached; /* Already tried, and failed. */ + + /* Several distributions like Debian/Ubuntu and OpenSUSE provide libxcrypt as libcrypt.so.1, + * while others like Fedora/CentOS and Arch provide it as libcrypt.so.2. */ + ELF_NOTE_DLOPEN("crypt", + "Support for hashing passwords", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libcrypt.so.2", "libcrypt.so.1"); + + _cleanup_(dlclosep) void *dl = NULL; + r = dlopen_safe("libcrypt.so.2", &dl, /* reterr_dlerror= */ NULL); + if (r < 0) { + const char *dle = NULL; + r = dlopen_safe("libcrypt.so.1", &dl, &dle); + if (r < 0) { + log_debug_errno(r, "libcrypt.so.2/libcrypt.so.1 is not available: %s", dle ?: STRERROR(r)); + return (cached = -EOPNOTSUPP); /* turn into recognizable error */ + } + log_debug("Loaded 'libcrypt.so.1' via dlopen()"); + } else + log_debug("Loaded 'libcrypt.so.2' via dlopen()"); + + r = dlsym_many_or_warn( + dl, LOG_DEBUG, + DLSYM_ARG(crypt_gensalt_ra), + DLSYM_ARG(crypt_preferred_method), + DLSYM_ARG(crypt_ra)); + if (r < 0) + return (cached = r); + + libcrypt_dl = TAKE_PTR(dl); +#else + libcrypt_dl = NULL; + sym_crypt_gensalt_ra = missing_crypt_gensalt_ra; + sym_crypt_preferred_method = missing_crypt_preferred_method; + sym_crypt_ra = missing_crypt_ra; +#endif + return 0; +} + +int make_salt(char **ret) { const char *e; char *salt; + int r; - /* 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); + + r = dlopen_libcrypt(); + if (r < 0) + return r; e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); if (!e) -#if HAVE_CRYPT_PREFERRED_METHOD - e = crypt_preferred_method(); -#else - e = "$6$"; -#endif + e = sym_crypt_preferred_method(); log_debug("Generating salt for hash prefix: %s", e); - salt = crypt_gensalt_ra(e, 0, NULL, 0); + salt = sym_crypt_gensalt_ra(e, 0, NULL, 0); if (!salt) return -errno; *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(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) { +int hash_password(const char *password, char **ret) { _cleanup_free_ char *salt = NULL; - _cleanup_(erase_and_freep) void *_cd_data = NULL; + _cleanup_(erase_and_freep) void *cd_data = NULL; const char *p; - int r, _cd_size = 0; + int r, cd_size = 0; - assert(!!cd_data == !!cd_size); + assert(password); + assert(ret); r = make_salt(&salt); if (r < 0) return log_debug_errno(r, "Failed to generate salt: %m"); errno = 0; - p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size); + p = sym_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); } +int test_password_one(const char *hashed_password, const char *password) { + _cleanup_(erase_and_freep) void *cd_data = NULL; + int r, cd_size = 0; + const char *k; + + assert(hashed_password); + assert(password); + + r = dlopen_libcrypt(); + if (r < 0) + return r; + + errno = 0; + k = sym_crypt_ra(password, hashed_password, &cd_data, &cd_size); + if (!k) { + if (errno == ENOMEM) + return -ENOMEM; + /* Unknown or unavailable hashing method or string too short */ + return 0; + } + + return streq(k, hashed_password); +} + +int test_password_many(char **hashed_password, const char *password) { + int r; + + assert(password); + + STRV_FOREACH(hpw, hashed_password) { + r = test_password_one(*hpw, password); + if (r < 0) + return r; + if (r > 0) + return true; + } + + return false; +} +#endif + bool looks_like_hashed_password(const char *s) { /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists * various hashing methods. We only reject (return false) strings which are documented to have @@ -155,34 +170,3 @@ bool looks_like_hashed_password(const char *s) { return !STR_IN_SET(s, "x", "*"); } - -int test_password_one(const char *hashed_password, const char *password) { - _cleanup_(erase_and_freep) void *cd_data = NULL; - int cd_size = 0; - const char *k; - - errno = 0; - k = crypt_ra(password, hashed_password, &cd_data, &cd_size); - if (!k) { - if (errno == ENOMEM) - return -ENOMEM; - /* Unknown or unavailable hashing method or string too short */ - return 0; - } - - return streq(k, hashed_password); -} - -int test_password_many(char **hashed_password, const char *password) { - int r; - - STRV_FOREACH(hpw, hashed_password) { - r = test_password_one(*hpw, password); - if (r < 0) - return r; - if (r > 0) - return true; - } - - return false; -} diff --git a/src/shared/libcrypt-util.h b/src/shared/libcrypt-util.h index 27c5f055a3..3f79916cbc 100644 --- a/src/shared/libcrypt-util.h +++ b/src/shared/libcrypt-util.h @@ -3,11 +3,21 @@ #include "shared-forward.h" +#if HAVE_LIBCRYPT +int dlopen_libcrypt(void); int make_salt(char **ret); -int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret); -static inline int hash_password(const char *password, char **ret) { - return hash_password_full(password, NULL, NULL, ret); -} -bool looks_like_hashed_password(const char *s); +int hash_password(const char *password, char **ret); int test_password_one(const char *hashed_password, const char *password); int test_password_many(char **hashed_password, const char *password); + +#else + +static inline int dlopen_libcrypt(void) { + return -EOPNOTSUPP; +} +static inline int hash_password(const char *password, char **ret) { + return -EOPNOTSUPP; +} +#endif + +bool looks_like_hashed_password(const char *s); diff --git a/src/shared/meson.build b/src/shared/meson.build index e0b86e0b81..36d38f4ed9 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -367,7 +367,7 @@ libshared_deps = [threads, libaudit_cflags, libblkid_cflags, libbpf_cflags, - libcrypt, + libcrypt_cflags, libcryptsetup_cflags, libdl, libdw_cflags, diff --git a/src/test/meson.build b/src/test/meson.build index a21f85c2ec..6a26eb3f87 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -345,7 +345,7 @@ executables += [ }, test_template + { 'sources' : files('test-libcrypt-util.c'), - 'dependencies' : libcrypt, + 'conditions' : ['HAVE_LIBCRYPT'], 'timeout' : 120, }, test_template + { diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index 47b8470ffb..10b8da1e9c 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -11,6 +11,7 @@ #include "idn-util.h" #include "libarchive-util.h" #include "libaudit-util.h" +#include "libcrypt-util.h" #include "libfido2-util.h" #include "libmount-util.h" #include "main-func.h" @@ -52,6 +53,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libarchive, HAVE_LIBARCHIVE); ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT); ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID); + ASSERT_DLOPEN(dlopen_libcrypt, HAVE_LIBCRYPT); ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2); ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD); ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT); diff --git a/src/test/test-libcrypt-util.c b/src/test/test-libcrypt-util.c index 92eda2e1a7..792b2b2ef9 100644 --- a/src/test/test-libcrypt-util.c +++ b/src/test/test-libcrypt-util.c @@ -1,41 +1,25 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "libcrypt-util.h" #include "strv.h" #include "tests.h" -static void test_crypt_preferred_method(void) { - log_info("/* %s */", __func__); - - log_info("crypt_preferred_method: %s", -#if HAVE_CRYPT_PREFERRED_METHOD - crypt_preferred_method() -#else - "(not available)" -#endif - ); -} - -static void test_make_salt(void) { - log_info("/* %s */", __func__); +TEST(make_salt) { + _cleanup_strv_free_ char **l = NULL; for (int i = 0; i < 10; i++) { _cleanup_free_ char *t; - assert_se(make_salt(&t) == 0); + ASSERT_OK(make_salt(&t)); log_info("%s", t); + + ASSERT_FALSE(strv_contains(l, t)); + ASSERT_OK(strv_consume(&l, TAKE_PTR(t))); } } -static int test_hash_password(void) { - log_info("/* %s */", __func__); - +TEST(hash_password) { /* As a warm-up exercise, check if we can hash passwords. */ - - bool have_sane_hash = false; - FOREACH_STRING(hash, "ew3bU1.hoKk4o", "$1$gc5rWpTB$wK1aul1PyBn9AX1z93stk1", @@ -43,80 +27,46 @@ static int test_hash_password(void) { "$5$lGhDrcrao9zb5oIK$05KlOVG3ocknx/ThreqXE/gk.XzFFBMTksc4t2CPDUD", "$6$c7wB/3GiRk0VHf7e$zXJ7hN0aLZapE.iO4mn/oHu6.prsXTUG/5k1AxpgR85ELolyAcaIGRgzfwJs3isTChMDBjnthZyaMCfCNxo9I.", "$y$j9T$$9cKOWsAm4m97WiYk61lPPibZpy3oaGPIbsL4koRe/XD") { - int b; - b = test_password_one(hash, "ppp"); - log_info("%s: %s", hash, yes_no(b)); -#if defined(XCRYPT_VERSION_MAJOR) - /* xcrypt is supposed to always implement all methods. */ - assert_se(b); +#ifndef __GLIBC__ + /* musl does not support yescrypt. */ + if (hash[1] == 'y') { + ASSERT_OK_ZERO(test_password_one(hash, "ppp")); + continue; + } #endif - - if (b && IN_SET(hash[1], '6', 'y')) - have_sane_hash = true; + ASSERT_OK_POSITIVE(test_password_one(hash, "ppp")); } - return have_sane_hash; -} + FOREACH_STRING(i, "abc123", "h⸿sło") { + _cleanup_free_ char *hashed; -static void test_hash_password_full(void) { - log_info("/* %s */", __func__); + ASSERT_OK(hash_password(i, &hashed)); + log_debug("\"%s\" → \"%s\"", i, hashed); - _cleanup_free_ void *cd_data = NULL; - int cd_size = 0; - - log_info("sizeof(struct crypt_data): %zu bytes", sizeof(struct crypt_data)); - - for (unsigned c = 0; c < 2; c++) - FOREACH_STRING(i, "abc123", "h⸿sło") { - _cleanup_free_ char *hashed; - - if (c == 0) - assert_se(hash_password_full(i, &cd_data, &cd_size, &hashed) == 0); - else - assert_se(hash_password_full(i, NULL, NULL, &hashed) == 0); - log_debug("\"%s\" → \"%s\"", i, hashed); - log_info("crypt_r[a] buffer size: %i bytes", cd_size); - - assert_se(test_password_one(hashed, i) == true); - assert_se(test_password_one(i, hashed) <= 0); /* We get an error for non-utf8 */ - assert_se(test_password_one(hashed, "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed), i) == true); - assert_se(test_password_many(STRV_MAKE(hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar") == false); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - i) == true); - assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); - assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ - hashed, - "$y$j9T$SAayASazWZIQeJd9AS02m/$"), - "") == false); + ASSERT_OK_POSITIVE(test_password_one(hashed, i)); + ASSERT_LE(test_password_one(i, hashed), 0); /* We get an error for non-utf8 */ + ASSERT_OK_ZERO(test_password_one(hashed, "foobar")); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE(hashed), i)); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed), "foobar")); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar")); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i)); + ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + i)); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "")); + ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */ + hashed, + "$y$j9T$SAayASazWZIQeJd9AS02m/$"), + "")); } } -int main(int argc, char *argv[]) { - test_setup_logging(LOG_DEBUG); - -#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 - - test_crypt_preferred_method(); - test_make_salt(); - - if (!test_hash_password()) - return log_tests_skipped("crypt doesn't support yescrypt or sha512crypt"); - - test_hash_password_full(); - - return 0; -} +DEFINE_TEST_MAIN(LOG_DEBUG); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index d822df61fb..47bd01f9d0 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -4,7 +4,6 @@ #include "alloc-util.h" #include "format-util.h" -#include "libcrypt-util.h" #include "log.h" #include "memory-util.h" #include "path-util.h" @@ -342,18 +341,6 @@ TEST(get_group_creds) { test_get_group_creds_one("65534", NOBODY_GROUP_NAME, GID_NOBODY); } -TEST(make_salt) { - _cleanup_free_ char *s, *t; - - ASSERT_OK(make_salt(&s)); - log_info("got %s", s); - - ASSERT_OK(make_salt(&t)); - log_info("got %s", t); - - ASSERT_NOT_STREQ(s, t); -} - TEST(in_gid) { ASSERT_OK(in_gid(getgid())); ASSERT_OK(in_gid(getegid()));