summaryrefslogtreecommitdiffstats
path: root/src/home/user-record-password-quality.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/home/user-record-password-quality.c')
-rw-r--r--src/home/user-record-password-quality.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/home/user-record-password-quality.c b/src/home/user-record-password-quality.c
new file mode 100644
index 0000000..38f4acb
--- /dev/null
+++ b/src/home/user-record-password-quality.c
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "bus-common-errors.h"
+#include "errno-util.h"
+#include "home-util.h"
+#include "libcrypt-util.h"
+#include "password-quality-util.h"
+#include "strv.h"
+#include "user-record-password-quality.h"
+#include "user-record-util.h"
+
+#if HAVE_PASSWDQC || HAVE_PWQUALITY
+
+int user_record_check_password_quality(
+ UserRecord *hr,
+ UserRecord *secret,
+ sd_bus_error *error) {
+
+ _cleanup_free_ char *auxerror = NULL;
+ int r;
+
+ assert(hr);
+ assert(secret);
+
+ /* This is a bit more complex than one might think at first. check_password_quality() 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;
+
+ 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 = check_password_quality(*pp, *old, hr->user_name, &auxerror);
+ if (r <= 0)
+ goto error;
+
+ called = true;
+ }
+
+ if (called)
+ continue;
+
+ /* If there are no old passwords, let's call check_password_quality() without any. */
+ r = check_password_quality(*pp, /* old */ NULL, hr->user_name, &auxerror);
+ if (r <= 0)
+ goto error;
+ }
+ return 1;
+
+error:
+ if (r == 0)
+ return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY,
+ "Password too weak: %s", auxerror);
+ if (ERRNO_IS_NOT_SUPPORTED(r))
+ return 0;
+ return log_debug_errno(r, "Failed to check password quality: %m");
+}
+
+#else
+
+int user_record_check_password_quality(
+ UserRecord *hr,
+ UserRecord *secret,
+ sd_bus_error *error) {
+
+ return 0;
+}
+
+#endif