From f16f9a5563928b1b8c0ec7b8bc8711b8ba382fa2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 11 Jan 2021 12:11:35 -0800 Subject: [PATCH] WIP. Prototype patch for bug : https://bugzilla.samba.org/show_bug.cgi?id=14611 Signed-off-by: Jeremy Allison --- source3/auth/check_samsec.c | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/source3/auth/check_samsec.c b/source3/auth/check_samsec.c index cfd32c5f5ba..1f93ca787ec 100644 --- a/source3/auth/check_samsec.c +++ b/source3/auth/check_samsec.c @@ -379,6 +379,7 @@ NTSTATUS check_sam_security(const DATA_BLOB *challenge, const uint8_t *nt_pw; const uint8_t *lm_pw; uint32_t acct_ctrl; + struct named_mutex *mtx = NULL; /* the returned struct gets kept on the server_info, by means of a steal further down */ @@ -418,6 +419,56 @@ NTSTATUS check_sam_security(const DATA_BLOB *challenge, challenge, lm_pw, nt_pw, user_info, &user_sess_key, &lm_sess_key); + /* + * We must re-load the sam acount information under a mutex + * lock to ensure we don't miss any concurrent account lockout + * changes. + */ + + /* Clear out old sampass info. */ + TALLOC_FREE(sampass); + acct_ctrl = 0; + username = NULL; + nt_pw = NULL; + lm_pw = NULL; + + sampass = samu_new(mem_ctx); + if (sampass == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* Grab the named mutex under root with 30 second timeout. */ + become_root(); + mtx = grab_named_mutex(NULL, "check_sam_security_mutex", 30); + /* Re-load the account information. */ + ret = pdb_getsampwnam(sampass, user_info->mapped.account_name); + unbecome_root(); + + /* Everything from here on is done under the mutex. */ + if (mtx == NULL) { + DBG_ERR("Acquisition of mutex check_sam_security_mutex failed " + "for user %s\n", + user_info->mapped.account_name); + nt_status = NT_STATUS_INTERNAL_ERROR; + goto done; + } + + /* Re-load the account control info. */ + acct_ctrl = pdb_get_acct_ctrl(sampass); + username = pdb_get_username(sampass); + + /* + * Check if the account is now locked out - now under the mutex. + * This can happen if the server is under + * a password guess attack and the ACB_AUTOLOCK is set by + * another process. + */ + if (acct_ctrl & ACB_AUTOLOCK) { + DBG_NOTICE("Account for user %s was locked out.\n", username); + nt_status = NT_STATUS_ACCOUNT_LOCKED_OUT; + goto done; + } + /* Notify passdb backend of login success/failure. If not NT_STATUS_OK the backend doesn't like the login */ @@ -510,6 +561,7 @@ done: TALLOC_FREE(sampass); data_blob_free(&user_sess_key); data_blob_free(&lm_sess_key); + TALLOC_FREE(mtx); return nt_status; } -- 2.27.0