Skip to content

Commit 1d8aae4

Browse files
Blarseldv-alt
andcommitted
shared: add libpasswdqc support
Co-authored-by: Dmitry V. Levin <[email protected]> Resolves: #15055
1 parent d34b182 commit 1d8aae4

File tree

8 files changed

+196
-3
lines changed

8 files changed

+196
-3
lines changed

meson.build

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1189,8 +1189,13 @@ else
11891189
endif
11901190
conf.set10('HAVE_LIBFDISK', have)
11911191

1192+
want_passwdqc = get_option('passwdqc')
11921193
want_pwquality = get_option('pwquality')
1193-
if want_pwquality != 'false' and not skip_deps
1194+
if want_passwdqc == 'true' and want_pwquality == 'true'
1195+
error('passwdqc and pwquality cannot be requested simultaneously')
1196+
endif
1197+
1198+
if want_pwquality != 'false' and want_passwdqc != 'true' and not skip_deps
11941199
libpwquality = dependency('pwquality',
11951200
version : '>= 1.4.1',
11961201
required : want_pwquality == 'true')
@@ -1201,6 +1206,16 @@ else
12011206
endif
12021207
conf.set10('HAVE_PWQUALITY', have)
12031208

1209+
if not have and want_passwdqc != 'false' and not skip_deps
1210+
libpasswdqc = dependency('passwdqc',
1211+
required : want_passwdqc == 'true')
1212+
have = libpasswdqc.found()
1213+
else
1214+
have = false
1215+
libpasswdqc = []
1216+
endif
1217+
conf.set10('HAVE_PASSWDQC', have)
1218+
12041219
want_seccomp = get_option('seccomp')
12051220
if want_seccomp != 'false' and not skip_deps
12061221
libseccomp = dependency('libseccomp',
@@ -4940,6 +4955,7 @@ foreach tuple : [
49404955
['microhttpd'],
49414956
['openssl'],
49424957
['p11kit'],
4958+
['passwdqc'],
49434959
['pcre2'],
49444960
['pwquality'],
49454961
['qrencode'],

meson_options.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,8 @@ option('xenctrl', type : 'combo', choices : ['auto', 'true', 'false'],
381381
description : 'support for Xen kexec')
382382
option('pam', type : 'combo', choices : ['auto', 'true', 'false'],
383383
description : 'PAM support')
384+
option('passwdqc', type : 'combo', choices : ['auto', 'true', 'false'],
385+
description : 'libpasswdqc support')
384386
option('pwquality', type : 'combo', choices : ['auto', 'true', 'false'],
385387
description : 'libpwquality support')
386388
option('microhttpd', type : 'combo', choices : ['auto', 'true', 'false'],

src/home/user-record-password-quality.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "user-record-password-quality.h"
1010
#include "user-record-util.h"
1111

12-
#if HAVE_PWQUALITY
12+
#if HAVE_PASSWDQC || HAVE_PWQUALITY
1313

1414
int user_record_check_password_quality(
1515
UserRecord *hr,

src/shared/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ shared_sources = files(
128128
'pager.c',
129129
'parse-argument.c',
130130
'parse-helpers.c',
131+
'password-quality-util-passwdqc.c',
131132
'password-quality-util-pwquality.c',
132133
'pcre2-util.c',
133134
'pkcs11-util.c',
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
3+
#include "dlfcn-util.h"
4+
#include "errno-util.h"
5+
#include "log.h"
6+
#include "macro.h"
7+
#include "memory-util.h"
8+
#include "password-quality-util.h"
9+
#include "strv.h"
10+
11+
#if HAVE_PASSWDQC
12+
13+
static void *passwdqc_dl = NULL;
14+
15+
void (*sym_passwdqc_params_reset)(passwdqc_params_t *params);
16+
int (*sym_passwdqc_params_load)(passwdqc_params_t *params, char **reason, const char *pathname);
17+
int (*sym_passwdqc_params_parse)(passwdqc_params_t *params, char **reason, int argc, const char *const *argv);
18+
void (*sym_passwdqc_params_free)(passwdqc_params_t *params);
19+
const char *(*sym_passwdqc_check)(const passwdqc_params_qc_t *params, const char *newpass, const char *oldpass, const struct passwd *pw);
20+
char *(*sym_passwdqc_random)(const passwdqc_params_qc_t *params);
21+
22+
int dlopen_passwdqc(void) {
23+
return dlopen_many_sym_or_warn(
24+
&passwdqc_dl, "libpasswdqc.so.1", LOG_DEBUG,
25+
DLSYM_ARG(passwdqc_params_reset),
26+
DLSYM_ARG(passwdqc_params_load),
27+
DLSYM_ARG(passwdqc_params_parse),
28+
DLSYM_ARG(passwdqc_params_free),
29+
DLSYM_ARG(passwdqc_check),
30+
DLSYM_ARG(passwdqc_random));
31+
}
32+
33+
static int pwqc_allocate_context(passwdqc_params_t **ret) {
34+
35+
_cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
36+
_cleanup_free_ char *load_reason = NULL;
37+
int r;
38+
39+
assert(ret);
40+
41+
r = dlopen_passwdqc();
42+
if (r < 0)
43+
return r;
44+
45+
params = new0(passwdqc_params_t, 1);
46+
if (!params)
47+
return log_oom();
48+
49+
sym_passwdqc_params_reset(params);
50+
51+
r = sym_passwdqc_params_load(params, &load_reason, "/etc/passwdqc.conf");
52+
if (r < 0) {
53+
if (!load_reason)
54+
return log_oom();
55+
log_debug("Failed to load passwdqc configuration file, ignoring: %s", load_reason);
56+
}
57+
58+
*ret = TAKE_PTR(params);
59+
return 0;
60+
}
61+
62+
int suggest_passwords(void) {
63+
64+
_cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
65+
_cleanup_strv_free_erase_ char **suggestions = NULL;
66+
_cleanup_(erase_and_freep) char *joined = NULL;
67+
int r;
68+
69+
r = pwqc_allocate_context(&params);
70+
if (r < 0) {
71+
if (ERRNO_IS_NOT_SUPPORTED(r))
72+
return 0;
73+
return log_error_errno(r, "Failed to allocate libpasswdqc context: %m");
74+
}
75+
76+
suggestions = new0(char*, N_SUGGESTIONS+1);
77+
if (!suggestions)
78+
return log_oom();
79+
80+
for (size_t i = 0; i < N_SUGGESTIONS; i++) {
81+
suggestions[i] = sym_passwdqc_random(&params->qc);
82+
if (!suggestions[i])
83+
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring");
84+
}
85+
86+
joined = strv_join(suggestions, " ");
87+
if (!joined)
88+
return log_oom();
89+
90+
printf("Password suggestions: %s\n", joined);
91+
return 1;
92+
}
93+
94+
int check_password_quality(
95+
const char *password,
96+
const char *old,
97+
const char *username,
98+
char **ret_error) {
99+
100+
_cleanup_(sym_passwdqc_params_freep) passwdqc_params_t *params = NULL;
101+
const char *check_reason;
102+
int r;
103+
104+
assert(password);
105+
106+
r = pwqc_allocate_context(&params);
107+
if (r < 0)
108+
return log_debug_errno(r, "Failed to allocate libpasswdqc context: %m");
109+
110+
if (username) {
111+
const struct passwd pw = {
112+
.pw_name = (char *) username,
113+
/*
114+
* passwdqc_check() could use this information to check
115+
* whether the password is based on the personal login information,
116+
* but we cannot provide it.
117+
*/
118+
.pw_passwd = (char *) "",
119+
.pw_gecos = (char *) "",
120+
.pw_dir = (char *) "",
121+
.pw_shell = (char *) ""
122+
};
123+
124+
check_reason = sym_passwdqc_check(&params->qc, password, old, &pw);
125+
} else
126+
check_reason = sym_passwdqc_check(&params->qc, password, old, /* pw */ NULL);
127+
128+
if (check_reason) {
129+
if (ret_error) {
130+
char *e = strdup(check_reason);
131+
if (!e)
132+
return log_oom();
133+
*ret_error = e;
134+
}
135+
136+
return 0; /* all bad */
137+
}
138+
139+
return 1; /* all good */
140+
}
141+
142+
#endif
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
#pragma once
3+
4+
#include "macro.h"
5+
6+
#if HAVE_PASSWDQC
7+
#include <passwdqc.h>
8+
9+
extern void (*sym_passwdqc_params_reset)(passwdqc_params_t *params);
10+
extern int (*sym_passwdqc_params_load)(passwdqc_params_t *params, char **reason, const char *pathname);
11+
extern int (*sym_passwdqc_params_parse)(passwdqc_params_t *params, char **reason, int argc, const char *const *argv);
12+
extern void (*sym_passwdqc_params_free)(passwdqc_params_t *params);
13+
extern const char *(*sym_passwdqc_check)(const passwdqc_params_qc_t *params, const char *newpass, const char *oldpass, const struct passwd *pw);
14+
extern char *(*sym_passwdqc_random)(const passwdqc_params_qc_t *params);
15+
16+
int dlopen_passwdqc(void);
17+
18+
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(passwdqc_params_t*, sym_passwdqc_params_free, NULL);
19+
20+
int suggest_passwords(void);
21+
int check_password_quality(const char *password, const char *old, const char *username, char **ret_error);
22+
23+
#endif

src/shared/password-quality-util.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33

44
#define N_SUGGESTIONS 6
55

6-
#if HAVE_PWQUALITY
6+
#if HAVE_PASSWDQC
7+
8+
#include "password-quality-util-passwdqc.h"
9+
10+
#elif HAVE_PWQUALITY
711

812
#include "password-quality-util-pwquality.h"
913

src/test/test-dlopen-so.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "libfido2-util.h"
1111
#include "macro.h"
1212
#include "main-func.h"
13+
#include "password-quality-util-passwdqc.h"
1314
#include "password-quality-util-pwquality.h"
1415
#include "pcre2-util.h"
1516
#include "pkcs11-util.h"
@@ -32,6 +33,10 @@ static int run(int argc, char **argv) {
3233
assert_se(dlopen_cryptsetup() >= 0);
3334
#endif
3435

36+
#if HAVE_PASSWDQC
37+
assert_se(dlopen_passwdqc() >= 0);
38+
#endif
39+
3540
#if HAVE_PWQUALITY
3641
assert_se(dlopen_pwquality() >= 0);
3742
#endif

0 commit comments

Comments
 (0)