1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "dlfcn-util.h"
6 #include "errno-util.h"
9 #include "memory-util.h"
10 #include "password-quality-util.h"
15 static void *pwquality_dl
= NULL
;
17 DLSYM_FUNCTION(pwquality_check
);
18 DLSYM_FUNCTION(pwquality_default_settings
);
19 DLSYM_FUNCTION(pwquality_free_settings
);
20 DLSYM_FUNCTION(pwquality_generate
);
21 DLSYM_FUNCTION(pwquality_get_str_value
);
22 DLSYM_FUNCTION(pwquality_read_config
);
23 DLSYM_FUNCTION(pwquality_set_int_value
);
24 DLSYM_FUNCTION(pwquality_strerror
);
26 int dlopen_pwquality(void) {
27 return dlopen_many_sym_or_warn(
28 &pwquality_dl
, "libpwquality.so.1", LOG_DEBUG
,
29 DLSYM_ARG(pwquality_check
),
30 DLSYM_ARG(pwquality_default_settings
),
31 DLSYM_ARG(pwquality_free_settings
),
32 DLSYM_ARG(pwquality_generate
),
33 DLSYM_ARG(pwquality_get_str_value
),
34 DLSYM_ARG(pwquality_read_config
),
35 DLSYM_ARG(pwquality_set_int_value
),
36 DLSYM_ARG(pwquality_strerror
));
39 static void pwq_maybe_disable_dictionary(pwquality_settings_t
*pwq
) {
40 char buf
[PWQ_MAX_ERROR_MESSAGE_LEN
];
46 r
= sym_pwquality_get_str_value(pwq
, PWQ_SETTING_DICT_PATH
, &path
);
48 log_debug("Failed to read libpwquality dictionary path, ignoring: %s",
49 sym_pwquality_strerror(buf
, sizeof(buf
), r
, NULL
));
54 log_debug("Weird, no dictionary file configured, ignoring.");
58 if (access(path
, F_OK
) >= 0)
61 if (errno
!= ENOENT
) {
62 log_debug_errno(errno
, "Failed to check if dictionary file %s exists, ignoring: %m", path
);
66 r
= sym_pwquality_set_int_value(pwq
, PWQ_SETTING_DICT_CHECK
, 0);
68 log_debug("Failed to disable libpwquality dictionary check, ignoring: %s",
69 sym_pwquality_strerror(buf
, sizeof(buf
), r
, NULL
));
72 static int pwq_allocate_context(pwquality_settings_t
**ret
) {
73 _cleanup_(sym_pwquality_free_settingsp
) pwquality_settings_t
*pwq
= NULL
;
74 char buf
[PWQ_MAX_ERROR_MESSAGE_LEN
];
80 r
= dlopen_pwquality();
84 pwq
= sym_pwquality_default_settings();
88 r
= sym_pwquality_read_config(pwq
, NULL
, &auxerror
);
90 log_debug("Failed to read libpwquality configuration, ignoring: %s",
91 sym_pwquality_strerror(buf
, sizeof(buf
), r
, auxerror
));
93 pwq_maybe_disable_dictionary(pwq
);
99 int suggest_passwords(void) {
100 _cleanup_(sym_pwquality_free_settingsp
) pwquality_settings_t
*pwq
= NULL
;
101 _cleanup_strv_free_erase_
char **suggestions
= NULL
;
102 _cleanup_(erase_and_freep
) char *joined
= NULL
;
103 char buf
[PWQ_MAX_ERROR_MESSAGE_LEN
];
106 r
= pwq_allocate_context(&pwq
);
108 if (ERRNO_IS_NOT_SUPPORTED(r
))
110 return log_error_errno(r
, "Failed to allocate libpwquality context: %m");
113 suggestions
= new0(char*, N_SUGGESTIONS
+1);
117 for (size_t i
= 0; i
< N_SUGGESTIONS
; i
++) {
118 r
= sym_pwquality_generate(pwq
, 64, suggestions
+ i
);
120 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to generate password, ignoring: %s",
121 sym_pwquality_strerror(buf
, sizeof(buf
), r
, NULL
));
124 joined
= strv_join(suggestions
, " ");
128 printf("Password suggestions: %s\n", joined
);
132 int check_password_quality(const char *password
, const char *old
, const char *username
, char **ret_error
) {
133 _cleanup_(sym_pwquality_free_settingsp
) pwquality_settings_t
*pwq
= NULL
;
134 char buf
[PWQ_MAX_ERROR_MESSAGE_LEN
];
140 r
= pwq_allocate_context(&pwq
);
142 return log_debug_errno(r
, "Failed to allocate libpwquality context: %m");
144 r
= sym_pwquality_check(pwq
, password
, old
, username
, &auxerror
);
147 r
= strdup_to(ret_error
,
148 sym_pwquality_strerror(buf
, sizeof(buf
), r
, auxerror
));
153 return 0; /* all bad */
156 return 1; /* all good */