CVE-2021-20251 s4:dsdb: Make badPwdCount update atomic
[bbaumbach/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / password_hash.c
index b9f7fb77e6f151f6ab3e6ab305907339a79be286..b308226a9f9a42247d8641de21d2e070d5160017 100644 (file)
@@ -45,6 +45,7 @@
 #include "lib/crypto/md4.h"
 #include "param/param.h"
 #include "lib/krb5_wrap/krb5_samba.h"
+#include "auth/auth_sam.h"
 #include "auth/common_auth.h"
 #include "lib/messaging/messaging.h"
 #include "lib/param/loadparm.h"
@@ -2729,7 +2730,8 @@ static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io
        struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
        struct ldb_message *mod_msg = NULL;
        struct ldb_message *pso_msg = NULL;
-       NTSTATUS status;
+       struct ldb_message *current = NULL;
+       NTSTATUS status = NT_STATUS_OK;
        int ret; /* The errors we will actually return */
        int dbg_ret; /* The errors we can only complain about in logs */
 
@@ -2775,13 +2777,28 @@ static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io
                goto done;
        }
 
+       /*
+        * Re-read the account details, using the GUID in case the DN
+        * is being changed.
+        */
+       status = authsam_reread_user_logon_data(
+               ldb, io->ac,
+               io->ac->search_res->message,
+               &current);
+       if (!NT_STATUS_IS_OK(status)) {
+               /* The re-read can return account locked out, as well
+                * as an internal error
+                */
+               goto end_transaction;
+       }
+
        /* PSO search result is optional (NULL if no PSO applies) */
        if (io->ac->pso_res != NULL) {
                pso_msg = io->ac->pso_res->message;
        }
 
        status = dsdb_update_bad_pwd_count(io->ac, ldb,
-                                          io->ac->search_res->message,
+                                          current,
                                           io->ac->dom_res->message,
                                           pso_msg,
                                           &mod_msg);
@@ -2831,7 +2848,11 @@ end_transaction:
 
 done:
        ret = LDB_ERR_CONSTRAINT_VIOLATION;
-       *werror = WERR_INVALID_PASSWORD;
+       if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
+               *werror = WERR_ACCOUNT_LOCKED_OUT;
+       } else {
+               *werror = WERR_INVALID_PASSWORD;
+       }
        ldb_asprintf_errstring(ldb,
                               "%08X: %s - check_password_restrictions: "
                               "The old password specified doesn't match!",