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')
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',
['microhttpd'],
['openssl'],
['p11kit'],
+ ['passwdqc'],
['pcre2'],
['pwquality'],
['qrencode'],
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'],
--- /dev/null
+/* 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(¶ms);
+ 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(¶ms->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(¶ms);
+ 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(¶ms->qc, password, old, &pw);
+ } else
+ check_reason = sym_passwdqc_check(¶ms->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
--- /dev/null
+/* 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