]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared: add libpasswdqc support 20425/head
authorEgor Ignatov <egori@altlinux.org>
Fri, 6 Aug 2021 08:41:01 +0000 (11:41 +0300)
committerDmitry V. Levin <ldv@strace.io>
Thu, 6 Jul 2023 10:59:41 +0000 (10:59 +0000)
Co-authored-by: Dmitry V. Levin <ldv@altlinux.org>
Resolves: #15055

meson.build
meson_options.txt
src/home/user-record-password-quality.c
src/shared/meson.build
src/shared/password-quality-util-passwdqc.c [new file with mode: 0644]
src/shared/password-quality-util-passwdqc.h [new file with mode: 0644]
src/shared/password-quality-util.h
src/test/test-dlopen-so.c

index fa2f7e354497da59c59d2b7358c5b71a6b8d2e78..3b29807e93df9170b22a4d1fe7912f518be24c5d 100644 (file)
@@ -1189,8 +1189,13 @@ else
 endif
 conf.set10('HAVE_LIBFDISK', have)
 
+want_passwdqc = get_option('passwdqc')
 want_pwquality = get_option('pwquality')
-if want_pwquality != 'false' and not skip_deps
+if want_passwdqc == 'true' and want_pwquality == 'true'
+        error('passwdqc and pwquality cannot be requested simultaneously')
+endif
+
+if want_pwquality != 'false' and want_passwdqc != 'true' and not skip_deps
         libpwquality = dependency('pwquality',
                                   version : '>= 1.4.1',
                                   required : want_pwquality == 'true')
@@ -1201,6 +1206,16 @@ else
 endif
 conf.set10('HAVE_PWQUALITY', have)
 
+if not have and want_passwdqc != 'false' and not skip_deps
+        libpasswdqc = dependency('passwdqc',
+                                 required : want_passwdqc == 'true')
+        have = libpasswdqc.found()
+else
+        have = false
+        libpasswdqc = []
+endif
+conf.set10('HAVE_PASSWDQC', have)
+
 want_seccomp = get_option('seccomp')
 if want_seccomp != 'false' and not skip_deps
         libseccomp = dependency('libseccomp',
@@ -4940,6 +4955,7 @@ foreach tuple : [
         ['microhttpd'],
         ['openssl'],
         ['p11kit'],
+        ['passwdqc'],
         ['pcre2'],
         ['pwquality'],
         ['qrencode'],
index 46a74b763587e307a7afcb9f697488afcdb9f370..19093238500a07954f268d41460e0680dfb5803f 100644 (file)
@@ -381,6 +381,8 @@ option('xenctrl', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'support for Xen kexec')
 option('pam', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'PAM support')
+option('passwdqc', type : 'combo', choices : ['auto', 'true', 'false'],
+       description : 'libpasswdqc support')
 option('pwquality', type : 'combo', choices : ['auto', 'true', 'false'],
        description : 'libpwquality support')
 option('microhttpd', type : 'combo', choices : ['auto', 'true', 'false'],
index 5c2909688d20786e202fa8d4250d9943b99290ac..38f4acb0e79adb7d66b3fa939d156856b4d53e28 100644 (file)
@@ -9,7 +9,7 @@
 #include "user-record-password-quality.h"
 #include "user-record-util.h"
 
-#if HAVE_PWQUALITY
+#if HAVE_PASSWDQC || HAVE_PWQUALITY
 
 int user_record_check_password_quality(
                 UserRecord *hr,
index fe88731c32f01c622d9cfecc4c2e898899db9aac..8fe02410d63f2a5995d5ae5b6c524b0fc8a46b0c 100644 (file)
@@ -128,6 +128,7 @@ shared_sources = files(
         'pager.c',
         'parse-argument.c',
         'parse-helpers.c',
+        'password-quality-util-passwdqc.c',
         'password-quality-util-pwquality.c',
         'pcre2-util.c',
         'pkcs11-util.c',
diff --git a/src/shared/password-quality-util-passwdqc.c b/src/shared/password-quality-util-passwdqc.c
new file mode 100644 (file)
index 0000000..adfc14d
--- /dev/null
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "dlfcn-util.h"
+#include "errno-util.h"
+#include "log.h"
+#include "macro.h"
+#include "memory-util.h"
+#include "password-quality-util.h"
+#include "strv.h"
+
+#if HAVE_PASSWDQC
+
+static void *passwdqc_dl = NULL;
+
+void (*sym_passwdqc_params_reset)(passwdqc_params_t *params);
+int (*sym_passwdqc_params_load)(passwdqc_params_t *params, char **reason, const char *pathname);
+int (*sym_passwdqc_params_parse)(passwdqc_params_t *params, char **reason, int argc, const char *const *argv);
+void (*sym_passwdqc_params_free)(passwdqc_params_t *params);
+const char *(*sym_passwdqc_check)(const passwdqc_params_qc_t *params, const char *newpass, const char *oldpass, const struct passwd *pw);
+char *(*sym_passwdqc_random)(const passwdqc_params_qc_t *params);
+
+int dlopen_passwdqc(void) {
+        return dlopen_many_sym_or_warn(
+                        &passwdqc_dl, "libpasswdqc.so.1", LOG_DEBUG,
+                        DLSYM_ARG(passwdqc_params_reset),
+                        DLSYM_ARG(passwdqc_params_load),
+                        DLSYM_ARG(passwdqc_params_parse),
+                        DLSYM_ARG(passwdqc_params_free),
+                        DLSYM_ARG(passwdqc_check),
+                        DLSYM_ARG(passwdqc_random));
+}
+
+static int pwqc_allocate_context(passwdqc_params_t **ret) {
+
+        _cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
+        _cleanup_free_ char *load_reason = NULL;
+        int r;
+
+        assert(ret);
+
+        r = dlopen_passwdqc();
+        if (r < 0)
+                return r;
+
+        params = new0(passwdqc_params_t, 1);
+        if (!params)
+                return log_oom();
+
+        sym_passwdqc_params_reset(params);
+
+        r = sym_passwdqc_params_load(params, &load_reason, "/etc/passwdqc.conf");
+        if (r < 0) {
+                if (!load_reason)
+                        return log_oom();
+                log_debug("Failed to load passwdqc configuration file, ignoring: %s", load_reason);
+        }
+
+        *ret = TAKE_PTR(params);
+        return 0;
+}
+
+int suggest_passwords(void) {
+
+        _cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
+        _cleanup_strv_free_erase_ char **suggestions = NULL;
+        _cleanup_(erase_and_freep) char *joined = NULL;
+        int r;
+
+        r = pwqc_allocate_context(&params);
+        if (r < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(r))
+                        return 0;
+                return log_error_errno(r, "Failed to allocate libpasswdqc context: %m");
+        }
+
+        suggestions = new0(char*, N_SUGGESTIONS+1);
+        if (!suggestions)
+                return log_oom();
+
+        for (size_t i = 0; i < N_SUGGESTIONS; i++) {
+                suggestions[i] = sym_passwdqc_random(&params->qc);
+                if (!suggestions[i])
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring");
+        }
+
+        joined = strv_join(suggestions, " ");
+        if (!joined)
+                return log_oom();
+
+        printf("Password suggestions: %s\n", joined);
+        return 1;
+}
+
+int check_password_quality(
+                const char *password,
+                const char *old,
+                const char *username,
+                char **ret_error) {
+
+        _cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
+        const char *check_reason;
+        int r;
+
+        assert(password);
+
+        r = pwqc_allocate_context(&params);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to allocate libpasswdqc context: %m");
+
+        if (username) {
+                const struct passwd pw = {
+                        .pw_name = (char *) username,
+                        /*
+                         * passwdqc_check() could use this information to check
+                         * whether the password is based on the personal login information,
+                         * but we cannot provide it.
+                         */
+                        .pw_passwd = (char *) "",
+                        .pw_gecos = (char *) "",
+                        .pw_dir = (char *) "",
+                        .pw_shell = (char *) ""
+                };
+
+                check_reason = sym_passwdqc_check(&params->qc, password, old, &pw);
+        } else
+                check_reason = sym_passwdqc_check(&params->qc, password, old, /* pw */ NULL);
+
+        if (check_reason) {
+                if (ret_error) {
+                        char *e = strdup(check_reason);
+                        if (!e)
+                                return log_oom();
+                        *ret_error = e;
+                }
+
+                return 0; /* all bad */
+        }
+
+        return 1; /* all good */
+}
+
+#endif
diff --git a/src/shared/password-quality-util-passwdqc.h b/src/shared/password-quality-util-passwdqc.h
new file mode 100644 (file)
index 0000000..0d528d2
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include "macro.h"
+
+#if HAVE_PASSWDQC
+#include <passwdqc.h>
+
+extern void (*sym_passwdqc_params_reset)(passwdqc_params_t *params);
+extern int (*sym_passwdqc_params_load)(passwdqc_params_t *params, char **reason, const char *pathname);
+extern int (*sym_passwdqc_params_parse)(passwdqc_params_t *params, char **reason, int argc, const char *const *argv);
+extern void (*sym_passwdqc_params_free)(passwdqc_params_t *params);
+extern const char *(*sym_passwdqc_check)(const passwdqc_params_qc_t *params, const char *newpass, const char *oldpass, const struct passwd *pw);
+extern char *(*sym_passwdqc_random)(const passwdqc_params_qc_t *params);
+
+int dlopen_passwdqc(void);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(passwdqc_params_t*, sym_passwdqc_params_free, NULL);
+
+int suggest_passwords(void);
+int check_password_quality(const char *password, const char *old, const char *username, char **ret_error);
+
+#endif
index a55727d1fb517a3c0de8c9bfa8b05d46f8bdd909..f838ba73efe56d462b9905a9feb253524db114a8 100644 (file)
@@ -3,7 +3,11 @@
 
 #define N_SUGGESTIONS 6
 
-#if HAVE_PWQUALITY
+#if HAVE_PASSWDQC
+
+#include "password-quality-util-passwdqc.h"
+
+#elif HAVE_PWQUALITY
 
 #include "password-quality-util-pwquality.h"
 
index 2d3b7744f68916ed22e588bf0d3d95da241aec0f..e98b8dae1e0fe7765088d2ceca03be01fb3b9b42 100644 (file)
@@ -10,6 +10,7 @@
 #include "libfido2-util.h"
 #include "macro.h"
 #include "main-func.h"
+#include "password-quality-util-passwdqc.h"
 #include "password-quality-util-pwquality.h"
 #include "pcre2-util.h"
 #include "pkcs11-util.h"
@@ -32,6 +33,10 @@ static int run(int argc, char **argv) {
         assert_se(dlopen_cryptsetup() >= 0);
 #endif
 
+#if HAVE_PASSWDQC
+        assert_se(dlopen_passwdqc() >= 0);
+#endif
+
 #if HAVE_PWQUALITY
         assert_se(dlopen_pwquality() >= 0);
 #endif