From 679badd7ba5ddcff97ad8603fcf272454ab06663 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Aug 2020 09:56:56 +0200 Subject: [PATCH 1/3] home: make libpwquality dep a runtime dlopen() one Also, let's move the glue for this to src/shared/ so that we later can reuse this in sysemd-firstboot. Given that libpwquality is a more a leaf dependency, let's make it runtime optional, so that downstream distros can downgrade their package deps from Required to Recommended. --- meson.build | 6 +- src/home/homectl.c | 3 +- src/home/homed-home.c | 5 +- src/home/meson.build | 8 +- src/home/pwquality-util.c | 186 ------------------------------- src/home/pwquality-util.h | 9 -- src/home/user-record-pwquality.c | 90 +++++++++++++++ src/home/user-record-pwquality.h | 7 ++ src/shared/meson.build | 2 + src/shared/pwquality-util.c | 158 ++++++++++++++++++++++++++ src/shared/pwquality-util.h | 34 ++++++ 11 files changed, 302 insertions(+), 206 deletions(-) delete mode 100644 src/home/pwquality-util.c delete mode 100644 src/home/pwquality-util.h create mode 100644 src/home/user-record-pwquality.c create mode 100644 src/home/user-record-pwquality.h create mode 100644 src/shared/pwquality-util.c create mode 100644 src/shared/pwquality-util.h diff --git a/meson.build b/meson.build index 227fe097a8..47b2b5f4b1 100644 --- a/meson.build +++ b/meson.build @@ -2173,8 +2173,7 @@ if conf.get('ENABLE_HOMED') == 1 link_with : [libshared], dependencies : [threads, libcrypt, - libopenssl, - libpwquality], + libopenssl], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) @@ -2188,8 +2187,7 @@ if conf.get('ENABLE_HOMED') == 1 libcrypt, libopenssl, libp11kit, - libfido2, - libpwquality], + libfido2], install_rpath : rootlibexecdir, install : true, install_dir : rootbindir) diff --git a/src/home/homectl.c b/src/home/homectl.c index 33e262706d..9d082ef0c0 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -30,6 +30,7 @@ #include "rlimit-util.h" #include "spawn-polkit-agent.h" #include "terminal-util.h" +#include "user-record-pwquality.h" #include "user-record-show.h" #include "user-record-util.h" #include "user-record.h" @@ -1097,7 +1098,7 @@ static int create_home(int argc, char *argv[], void *userdata) { /* If password quality enforcement is disabled, let's at least warn client side */ - r = quality_check_password(hr, hr, &error); + r = user_record_quality_check_password(hr, hr, &error); if (r < 0) log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", bus_error_message(&error, r)); } diff --git a/src/home/homed-home.c b/src/home/homed-home.c index f0c157cb7d..45c2152531 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -33,6 +33,7 @@ #include "strv.h" #include "user-record-sign.h" #include "user-record-util.h" +#include "user-record-pwquality.h" #include "user-record.h" #include "user-util.h" @@ -1289,7 +1290,7 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) { if (h->record->enforce_password_policy == false) log_debug("Password quality check turned off for account, skipping."); else { - r = quality_check_password(h->record, secret, error); + r = user_record_quality_check_password(h->record, secret, error); if (r < 0) return r; } @@ -1640,7 +1641,7 @@ int home_passwd(Home *h, if (c->enforce_password_policy == false) log_debug("Password quality check turned off for account, skipping."); else { - r = quality_check_password(c, merged_secret, error); + r = user_record_quality_check_password(c, merged_secret, error); if (r < 0) return r; } diff --git a/src/home/meson.build b/src/home/meson.build index 797f3a3c6d..fbf09501c4 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -50,8 +50,8 @@ systemd_homed_sources = files(''' homed-varlink.c homed-varlink.h homed.c - pwquality-util.c - pwquality-util.h + user-record-pwquality.c + user-record-pwquality.h user-record-sign.c user-record-sign.h user-record-util.c @@ -74,8 +74,8 @@ homectl_sources = files(''' homectl-pkcs11.c homectl-pkcs11.h homectl.c - pwquality-util.c - pwquality-util.h + user-record-pwquality.c + user-record-pwquality.h user-record-util.c user-record-util.h '''.split()) diff --git a/src/home/pwquality-util.c b/src/home/pwquality-util.c deleted file mode 100644 index fbf6f6c8cc..0000000000 --- a/src/home/pwquality-util.c +++ /dev/null @@ -1,186 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include - -#if HAVE_PWQUALITY -/* pwquality.h uses size_t but doesn't include sys/types.h on its own */ -#include -#include -#endif - -#include "bus-common-errors.h" -#include "home-util.h" -#include "memory-util.h" -#include "pwquality-util.h" -#include "strv.h" - -#if HAVE_PWQUALITY -DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, pwquality_free_settings); - -static void pwquality_maybe_disable_dictionary( - pwquality_settings_t *pwq) { - - char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; - const char *path; - int r; - - r = pwquality_get_str_value(pwq, PWQ_SETTING_DICT_PATH, &path); - if (r < 0) { - log_warning("Failed to read libpwquality dictionary path, ignoring: %s", pwquality_strerror(buf, sizeof(buf), r, NULL)); - return; - } - - // REMOVE THIS AS SOON AS https://github.com/libpwquality/libpwquality/pull/21 IS MERGED AND RELEASED - if (isempty(path)) - path = "/usr/share/cracklib/pw_dict.pwd.gz"; - - if (isempty(path)) { - log_warning("Weird, no dictionary file configured, ignoring."); - return; - } - - if (access(path, F_OK) >= 0) - return; - - if (errno != ENOENT) { - log_warning_errno(errno, "Failed to check if dictionary file %s exists, ignoring: %m", path); - return; - } - - r = pwquality_set_int_value(pwq, PWQ_SETTING_DICT_CHECK, 0); - if (r < 0) { - log_warning("Failed to disable libpwquality dictionary check, ignoring: %s", pwquality_strerror(buf, sizeof(buf), r, NULL)); - return; - } -} - -int quality_check_password( - UserRecord *hr, - UserRecord *secret, - sd_bus_error *error) { - - _cleanup_(pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; - char buf[PWQ_MAX_ERROR_MESSAGE_LEN], **pp; - void *auxerror; - int r; - - assert(hr); - assert(secret); - - pwq = pwquality_default_settings(); - if (!pwq) - return log_oom(); - - r = pwquality_read_config(pwq, NULL, &auxerror); - if (r < 0) - log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to read libpwquality configuration, ignoring: %s", - pwquality_strerror(buf, sizeof(buf), r, auxerror)); - - pwquality_maybe_disable_dictionary(pwq); - - /* This is a bit more complex than one might think at first. pwquality_check() would like to know the - * old password to make security checks. We support arbitrary numbers of passwords however, hence we - * call the function once for each combination of old and new password. */ - - /* Iterate through all new passwords */ - STRV_FOREACH(pp, secret->password) { - bool called = false; - char **old; - - r = test_password_many(hr->hashed_password, *pp); - if (r < 0) - return r; - if (r == 0) /* This is an old password as it isn't listed in the hashedPassword field, skip it */ - continue; - - /* Check this password against all old passwords */ - STRV_FOREACH(old, secret->password) { - - if (streq(*pp, *old)) - continue; - - r = test_password_many(hr->hashed_password, *old); - if (r < 0) - return r; - if (r > 0) /* This is a new password, not suitable as old password */ - continue; - - r = pwquality_check(pwq, *pp, *old, hr->user_name, &auxerror); - if (r < 0) - return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s", - pwquality_strerror(buf, sizeof(buf), r, auxerror)); - - called = true; - } - - if (called) - continue; - - /* If there are no old passwords, let's call pwquality_check() without any. */ - r = pwquality_check(pwq, *pp, NULL, hr->user_name, &auxerror); - if (r < 0) - return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s", - pwquality_strerror(buf, sizeof(buf), r, auxerror)); - } - - return 0; -} - -#define N_SUGGESTIONS 6 - -int suggest_passwords(void) { - _cleanup_(pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; - _cleanup_strv_free_erase_ char **suggestions = NULL; - _cleanup_(erase_and_freep) char *joined = NULL; - char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; - void *auxerror; - size_t i; - int r; - - pwq = pwquality_default_settings(); - if (!pwq) - return log_oom(); - - r = pwquality_read_config(pwq, NULL, &auxerror); - if (r < 0) - log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to read libpwquality configuration, ignoring: %s", - pwquality_strerror(buf, sizeof(buf), r, auxerror)); - - pwquality_maybe_disable_dictionary(pwq); - - suggestions = new0(char*, N_SUGGESTIONS+1); - if (!suggestions) - return log_oom(); - - for (i = 0; i < N_SUGGESTIONS; i++) { - r = pwquality_generate(pwq, 64, suggestions + i); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s", - pwquality_strerror(buf, sizeof(buf), r, NULL)); - } - - joined = strv_join(suggestions, " "); - if (!joined) - return log_oom(); - - log_info("Password suggestions: %s", joined); - return 0; -} - -#else - -int quality_check_password( - UserRecord *hr, - UserRecord *secret, - sd_bus_error *error) { - - assert(hr); - assert(secret); - - return 0; -} - -int suggest_passwords(void) { - return 0; -} -#endif diff --git a/src/home/pwquality-util.h b/src/home/pwquality-util.h deleted file mode 100644 index d61c04c342..0000000000 --- a/src/home/pwquality-util.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -#pragma once - -#include "sd-bus.h" -#include "user-record.h" - -int quality_check_password(UserRecord *hr, UserRecord *secret, sd_bus_error *error); - -int suggest_passwords(void); diff --git a/src/home/user-record-pwquality.c b/src/home/user-record-pwquality.c new file mode 100644 index 0000000000..a5d632c772 --- /dev/null +++ b/src/home/user-record-pwquality.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "bus-common-errors.h" +#include "errno-util.h" +#include "home-util.h" +#include "pwquality-util.h" +#include "strv.h" +#include "user-record-pwquality.h" +#include "user-record-util.h" + +#if HAVE_PWQUALITY + +int user_record_quality_check_password( + UserRecord *hr, + UserRecord *secret, + sd_bus_error *error) { + + _cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; + char buf[PWQ_MAX_ERROR_MESSAGE_LEN], **pp; + void *auxerror; + int r; + + assert(hr); + assert(secret); + + r = pwq_allocate_context(&pwq); + if (ERRNO_IS_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return log_debug_errno(r, "Failed to allocate libpwquality context: %m"); + + /* This is a bit more complex than one might think at first. pwquality_check() would like to know the + * old password to make security checks. We support arbitrary numbers of passwords however, hence we + * call the function once for each combination of old and new password. */ + + /* Iterate through all new passwords */ + STRV_FOREACH(pp, secret->password) { + bool called = false; + char **old; + + r = test_password_many(hr->hashed_password, *pp); + if (r < 0) + return r; + if (r == 0) /* This is an old password as it isn't listed in the hashedPassword field, skip it */ + continue; + + /* Check this password against all old passwords */ + STRV_FOREACH(old, secret->password) { + + if (streq(*pp, *old)) + continue; + + r = test_password_many(hr->hashed_password, *old); + if (r < 0) + return r; + if (r > 0) /* This is a new password, not suitable as old password */ + continue; + + r = sym_pwquality_check(pwq, *pp, *old, hr->user_name, &auxerror); + if (r < 0) + return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, auxerror)); + + called = true; + } + + if (called) + continue; + + /* If there are no old passwords, let's call pwquality_check() without any. */ + r = sym_pwquality_check(pwq, *pp, NULL, hr->user_name, &auxerror); + if (r < 0) + return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, auxerror)); + } + + return 1; +} + +#else + +int user_record_quality_check_password( + UserRecord *hr, + UserRecord *secret, + sd_bus_error *error) { + + return 0; +} + +#endif diff --git a/src/home/user-record-pwquality.h b/src/home/user-record-pwquality.h new file mode 100644 index 0000000000..a37d369181 --- /dev/null +++ b/src/home/user-record-pwquality.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" +#include "user-record.h" + +int user_record_quality_check_password(UserRecord *hr, UserRecord *secret, sd_bus_error *error); diff --git a/src/shared/meson.build b/src/shared/meson.build index 0da733c3fe..d192a4d8d7 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -191,6 +191,8 @@ shared_sources = files(''' pretty-print.h ptyfwd.c ptyfwd.h + pwquality-util.c + pwquality-util.h reboot-util.c reboot-util.h resize-fs.c diff --git a/src/shared/pwquality-util.c b/src/shared/pwquality-util.c new file mode 100644 index 0000000000..799c39f32b --- /dev/null +++ b/src/shared/pwquality-util.c @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include + +#include "dlfcn-util.h" +#include "errno-util.h" +#include "log.h" +#include "macro.h" +#include "memory-util.h" +#include "pwquality-util.h" +#include "strv.h" + +#if HAVE_PWQUALITY + +static void *pwquality_dl = NULL; + +int (*sym_pwquality_check)(pwquality_settings_t *pwq, const char *password, const char *oldpassword, const char *user, void **auxerror); +pwquality_settings_t *(*sym_pwquality_default_settings)(void); +void (*sym_pwquality_free_settings)(pwquality_settings_t *pwq); +int (*sym_pwquality_generate)(pwquality_settings_t *pwq, int entropy_bits, char **password); +int (*sym_pwquality_get_str_value)(pwquality_settings_t *pwq, int setting, const char **value); +int (*sym_pwquality_read_config)(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror); +int (*sym_pwquality_set_int_value)(pwquality_settings_t *pwq, int setting, int value); +const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, void *auxerror); + +int dlopen_pwquality(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (pwquality_dl) + return 0; /* Already loaded */ + + dl = dlopen("libpwquality.so.1", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libpwquality support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + &sym_pwquality_check, "pwquality_check", + &sym_pwquality_default_settings, "pwquality_default_settings", + &sym_pwquality_free_settings, "pwquality_free_settings", + &sym_pwquality_generate, "pwquality_generate", + &sym_pwquality_get_str_value, "pwquality_get_str_value", + &sym_pwquality_read_config, "pwquality_read_config", + &sym_pwquality_set_int_value, "pwquality_set_int_value", + &sym_pwquality_strerror, "pwquality_strerror", + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + pwquality_dl = TAKE_PTR(dl); + return 1; +} + +void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq) { + char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + const char *path; + int r; + + assert(pwq); + + r = sym_pwquality_get_str_value(pwq, PWQ_SETTING_DICT_PATH, &path); + if (r < 0) { + log_debug("Failed to read libpwquality dictionary path, ignoring: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, NULL)); + return; + } + + // REMOVE THIS AS SOON AS https://github.com/libpwquality/libpwquality/pull/21 IS MERGED AND RELEASED + if (isempty(path)) + path = "/usr/share/cracklib/pw_dict.pwd.gz"; + + if (isempty(path)) { + log_debug("Weird, no dictionary file configured, ignoring."); + return; + } + + if (access(path, F_OK) >= 0) + return; + + if (errno != ENOENT) { + log_debug_errno(errno, "Failed to check if dictionary file %s exists, ignoring: %m", path); + return; + } + + r = sym_pwquality_set_int_value(pwq, PWQ_SETTING_DICT_CHECK, 0); + if (r < 0) + log_debug("Failed to disable libpwquality dictionary check, ignoring: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, NULL)); +} + +int pwq_allocate_context(pwquality_settings_t **ret) { + _cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; + char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + void *auxerror; + int r; + + assert(ret); + + r = dlopen_pwquality(); + if (r < 0) + return r; + + pwq = sym_pwquality_default_settings(); + if (!pwq) + return -ENOMEM; + + r = sym_pwquality_read_config(pwq, NULL, &auxerror); + if (r < 0) + log_debug("Failed to read libpwquality configuration, ignoring: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, auxerror)); + + pwq_maybe_disable_dictionary(pwq); + + *ret = TAKE_PTR(pwq); + return 0; +} + +#define N_SUGGESTIONS 6 + +int suggest_passwords(void) { + _cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; + _cleanup_strv_free_erase_ char **suggestions = NULL; + _cleanup_(erase_and_freep) char *joined = NULL; + char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + size_t i; + int r; + + r = pwq_allocate_context(&pwq); + if (ERRNO_IS_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return log_error_errno(r, "Failed to allocate libpwquality context: %m"); + + suggestions = new0(char*, N_SUGGESTIONS+1); + if (!suggestions) + return log_oom(); + + for (i = 0; i < N_SUGGESTIONS; i++) { + r = sym_pwquality_generate(pwq, 64, suggestions + i); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s", + sym_pwquality_strerror(buf, sizeof(buf), r, NULL)); + } + + joined = strv_join(suggestions, " "); + if (!joined) + return log_oom(); + + log_info("Password suggestions: %s", joined); + return 1; +} + +#endif diff --git a/src/shared/pwquality-util.h b/src/shared/pwquality-util.h new file mode 100644 index 0000000000..2ef34dabee --- /dev/null +++ b/src/shared/pwquality-util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "macro.h" + +#if HAVE_PWQUALITY +/* pwquality.h uses size_t but doesn't include sys/types.h on its own */ +#include +#include + +extern int (*sym_pwquality_check)(pwquality_settings_t *pwq, const char *password, const char *oldpassword, const char *user, void **auxerror); +extern pwquality_settings_t *(*sym_pwquality_default_settings)(void); +extern void (*sym_pwquality_free_settings)(pwquality_settings_t *pwq); +extern int (*sym_pwquality_generate)(pwquality_settings_t *pwq, int entropy_bits, char **password); +extern int (*sym_pwquality_get_str_value)(pwquality_settings_t *pwq, int setting, const char **value); +extern int (*sym_pwquality_read_config)(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror); +extern int (*sym_pwquality_set_int_value)(pwquality_settings_t *pwq, int setting, int value); +extern const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, void *auxerror); + +int dlopen_pwquality(void); + +DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, sym_pwquality_free_settings); + +void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq); +int pwq_allocate_context(pwquality_settings_t **ret); +int suggest_passwords(void); + +#else + +static inline int suggest_passwords(void) { + return 0; +} + +#endif From 7baf10a7be8bd1bad36d333f7013ed5c2b7b7d13 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Aug 2020 10:37:44 +0200 Subject: [PATCH 2/3] firstboot: hook up with libpwquality --- src/firstboot/firstboot.c | 10 ++++++++++ src/shared/pwquality-util.c | 33 +++++++++++++++++++++++++++++++++ src/shared/pwquality-util.h | 7 +++++++ 3 files changed, 50 insertions(+) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index e4c7a2d374..cf1ec28dd5 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -28,6 +28,7 @@ #include "path-util.h" #include "pretty-print.h" #include "proc-cmdline.h" +#include "pwquality-util.h" #include "random-util.h" #include "string-util.h" #include "strv.h" @@ -568,8 +569,11 @@ static int prompt_root_password(void) { msg1 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip):"); msg2 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter new root password again:"); + suggest_passwords(); + for (;;) { _cleanup_strv_free_erase_ char **a = NULL, **b = NULL; + _cleanup_free_ char *error = NULL; r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a); if (r < 0) @@ -583,6 +587,12 @@ static int prompt_root_password(void) { break; } + r = quality_check_password(*a, "root", &error); + if (r < 0) + return log_error_errno(r, "Failed to check quality of password: %m"); + if (r == 0) + log_warning("Password is weak, accepting anyway: %s", error); + r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b); if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); diff --git a/src/shared/pwquality-util.c b/src/shared/pwquality-util.c index 799c39f32b..67332833a5 100644 --- a/src/shared/pwquality-util.c +++ b/src/shared/pwquality-util.c @@ -155,4 +155,37 @@ int suggest_passwords(void) { return 1; } +int quality_check_password(const char *password, const char *username, char **ret_error) { + _cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL; + char buf[PWQ_MAX_ERROR_MESSAGE_LEN]; + void *auxerror; + int r; + + assert(password); + + r = pwq_allocate_context(&pwq); + if (ERRNO_IS_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return log_debug_errno(r, "Failed to allocate libpwquality context: %m"); + + r = sym_pwquality_check(pwq, password, NULL, username, &auxerror); + if (r < 0) { + + if (ret_error) { + _cleanup_free_ char *e = NULL; + + e = strdup(sym_pwquality_strerror(buf, sizeof(buf), r, auxerror)); + if (!e) + return -ENOMEM; + + *ret_error = TAKE_PTR(e); + } + + return 0; /* all bad */ + } + + return 1; /* all good */ +} + #endif diff --git a/src/shared/pwquality-util.h b/src/shared/pwquality-util.h index 2ef34dabee..a49de07990 100644 --- a/src/shared/pwquality-util.h +++ b/src/shared/pwquality-util.h @@ -24,6 +24,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, sym_pwquality_free_settings); void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq); int pwq_allocate_context(pwquality_settings_t **ret); int suggest_passwords(void); +int quality_check_password(const char *password, const char *username, char **ret_error); #else @@ -31,4 +32,10 @@ static inline int suggest_passwords(void) { return 0; } +static inline int quality_check_password(const char *password, const char *username, char **ret_error) { + if (ret_error) + *ret_error = NULL; + return 1; /* all good */ +} + #endif From 4d89db12fc51c10960ec97645a3df5854787f387 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 18 Aug 2020 10:41:18 +0200 Subject: [PATCH 3/3] update TODO --- TODO | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/TODO b/TODO index 7b928f5c10..9bb0831468 100644 --- a/TODO +++ b/TODO @@ -87,8 +87,7 @@ Features: * make us use dynamically fewer deps for containers in general purpose distros: o turn into dlopen() deps: - - libpwquality (always) - only relevant for homed, and maybe soon - firstboot + - libidn2 (always) - elfutils (always) - p11-kit-trust (always) - kmod-libs (only when called from PID 1) @@ -365,7 +364,6 @@ Features: - fingerprint authentication, pattern authentication, … - make sure "classic" user records can also be managed by homed - make size of $XDG_RUNTIME_DIR configurable in user record - - reuse pwquality magic in firstboot - query password from kernel keyring first - update even if record is "absent" - add a "access mode" + "fstype" field to the "status" section of json identity records reflecting the actually used access mode and fstype, even on non-luks backends