diff options
author | Lennart Poettering <lennart@poettering.net> | 2020-08-19 15:40:41 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-19 15:40:41 +0200 |
commit | 1b13600948b9fc5d35b3b643d02e5323f75dd682 (patch) | |
tree | 3d05a605a155ff37a08ea518d0bd4f9bf3272a32 /src/home | |
parent | 843ce053b42f02c234b2215f6424193256d1d61d (diff) | |
parent | 4d89db12fc51c10960ec97645a3df5854787f387 (diff) | |
download | systemd-1b13600948b9fc5d35b3b643d02e5323f75dd682.tar.gz |
Merge pull request #16771 from poettering/dyn-pwq
make libpwquality a dlopen() dependency + use it in systemd-firstboot, too
Diffstat (limited to 'src/home')
-rw-r--r-- | src/home/homectl.c | 3 | ||||
-rw-r--r-- | src/home/homed-home.c | 5 | ||||
-rw-r--r-- | src/home/meson.build | 8 | ||||
-rw-r--r-- | src/home/pwquality-util.c | 186 | ||||
-rw-r--r-- | src/home/pwquality-util.h | 9 | ||||
-rw-r--r-- | src/home/user-record-pwquality.c | 90 | ||||
-rw-r--r-- | src/home/user-record-pwquality.h | 7 |
7 files changed, 106 insertions, 202 deletions
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 <unistd.h> - -#if HAVE_PWQUALITY -/* pwquality.h uses size_t but doesn't include sys/types.h on its own */ -#include <sys/types.h> -#include <pwquality.h> -#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); |