[Pkg-samba-maint] [samba] 02/09: CVE-2013-4496:s3-samr: Block attempts to crack passwords via repeated password changes

Ivo De Decker ivodd at moszumanska.debian.org
Fri Mar 14 16:24:55 UTC 2014


This is an automated email from the git hooks/post-receive script.

ivodd pushed a commit to annotated tag upstream/4.1.6+dfsg
in repository samba.

commit f5743f0355d1dbbcfef7c228e04b25520872b5e3
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Fri Nov 1 14:55:44 2013 +1300

    CVE-2013-4496:s3-samr: Block attempts to crack passwords via repeated password changes
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=10245
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
---
 source3/rpc_server/samr/srv_samr_chgpasswd.c | 55 +++++++++++++++++
 source3/rpc_server/samr/srv_samr_nt.c        | 90 +++++++++++++++++++++++-----
 2 files changed, 129 insertions(+), 16 deletions(-)

diff --git a/source3/rpc_server/samr/srv_samr_chgpasswd.c b/source3/rpc_server/samr/srv_samr_chgpasswd.c
index db1f459..1c9c33a 100644
--- a/source3/rpc_server/samr/srv_samr_chgpasswd.c
+++ b/source3/rpc_server/samr/srv_samr_chgpasswd.c
@@ -1106,6 +1106,8 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
 	struct samu *sampass = NULL;
 	NTSTATUS nt_status;
 	bool ret = false;
+	bool updated_badpw = false;
+	NTSTATUS update_login_attempts_status;
 
 	if (!(sampass = samu_new(NULL))) {
 		return NT_STATUS_NO_MEMORY;
@@ -1121,6 +1123,13 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
 		return NT_STATUS_NO_SUCH_USER;
 	}
 
+	/* Quit if the account was locked out. */
+	if (pdb_get_acct_ctrl(sampass) & ACB_AUTOLOCK) {
+		DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", user));
+		TALLOC_FREE(sampass);
+		return NT_STATUS_ACCOUNT_LOCKED_OUT;
+	}
+
 	nt_status = check_oem_password(user,
 				       password_encrypted_with_lm_hash,
 				       old_lm_hash_encrypted,
@@ -1129,6 +1138,52 @@ NTSTATUS pass_oem_change(char *user, const char *rhost,
 				       sampass,
 				       &new_passwd);
 
+	/*
+	 * Notify passdb backend of login success/failure. If not
+	 * NT_STATUS_OK the backend doesn't like the login
+	 */
+	update_login_attempts_status = pdb_update_login_attempts(sampass,
+						NT_STATUS_IS_OK(nt_status));
+
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		bool increment_bad_pw_count = false;
+
+		if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) &&
+		    (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
+		    NT_STATUS_IS_OK(update_login_attempts_status))
+		{
+			increment_bad_pw_count = true;
+		}
+
+		if (increment_bad_pw_count) {
+			pdb_increment_bad_password_count(sampass);
+			updated_badpw = true;
+		} else {
+			pdb_update_bad_password_count(sampass,
+						      &updated_badpw);
+		}
+	} else {
+
+		if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) &&
+		    (pdb_get_bad_password_count(sampass) > 0)){
+			pdb_set_bad_password_count(sampass, 0, PDB_CHANGED);
+			pdb_set_bad_password_time(sampass, 0, PDB_CHANGED);
+			updated_badpw = true;
+		}
+	}
+
+	if (updated_badpw) {
+		NTSTATUS update_status;
+		become_root();
+		update_status = pdb_update_sam_account(sampass);
+		unbecome_root();
+
+		if (!NT_STATUS_IS_OK(update_status)) {
+			DEBUG(1, ("Failed to modify entry: %s\n",
+				  nt_errstr(update_status)));
+		}
+	}
+
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		TALLOC_FREE(sampass);
 		return nt_status;
diff --git a/source3/rpc_server/samr/srv_samr_nt.c b/source3/rpc_server/samr/srv_samr_nt.c
index b366eda..98e8bea 100644
--- a/source3/rpc_server/samr/srv_samr_nt.c
+++ b/source3/rpc_server/samr/srv_samr_nt.c
@@ -1722,9 +1722,11 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 	NTSTATUS status;
 	bool ret = false;
 	struct samr_user_info *uinfo;
-	struct samu *pwd;
+	struct samu *pwd = NULL;
 	struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
 	struct samr_Password lm_pwd, nt_pwd;
+	bool updated_badpw = false;
+	NTSTATUS update_login_attempts_status;
 
 	uinfo = policy_handle_find(p, r->in.user_handle,
 				   SAMR_USER_ACCESS_SET_PASSWORD, NULL,
@@ -1736,6 +1738,15 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 	DEBUG(5,("_samr_ChangePasswordUser: sid:%s\n",
 		  sid_string_dbg(&uinfo->sid)));
 
+	/* basic sanity checking on parameters.  Do this before any database ops */
+	if (!r->in.lm_present || !r->in.nt_present ||
+	    !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
+	    !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
+		/* we should really handle a change with lm not
+		   present */
+		return NT_STATUS_INVALID_PARAMETER_MIX;
+	}
+
 	if (!(pwd = samu_new(NULL))) {
 		return NT_STATUS_NO_MEMORY;
 	}
@@ -1749,6 +1760,14 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 		return NT_STATUS_WRONG_PASSWORD;
 	}
 
+	/* Quit if the account was locked out. */
+	if (pdb_get_acct_ctrl(pwd) & ACB_AUTOLOCK) {
+		DEBUG(3, ("Account for user %s was locked out.\n",
+			  pdb_get_username(pwd)));
+		status = NT_STATUS_ACCOUNT_LOCKED_OUT;
+		goto out;
+	}
+
 	{
 		const uint8_t *lm_pass, *nt_pass;
 
@@ -1757,29 +1776,19 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 
 		if (!lm_pass || !nt_pass) {
 			status = NT_STATUS_WRONG_PASSWORD;
-			goto out;
+			goto update_login;
 		}
 
 		memcpy(&lm_pwd.hash, lm_pass, sizeof(lm_pwd.hash));
 		memcpy(&nt_pwd.hash, nt_pass, sizeof(nt_pwd.hash));
 	}
 
-	/* basic sanity checking on parameters.  Do this before any database ops */
-	if (!r->in.lm_present || !r->in.nt_present ||
-	    !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
-	    !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
-		/* we should really handle a change with lm not
-		   present */
-		status = NT_STATUS_INVALID_PARAMETER_MIX;
-		goto out;
-	}
-
 	/* decrypt and check the new lm hash */
 	D_P16(lm_pwd.hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
 	D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
 	if (memcmp(checkHash.hash, lm_pwd.hash, 16) != 0) {
 		status = NT_STATUS_WRONG_PASSWORD;
-		goto out;
+		goto update_login;
 	}
 
 	/* decrypt and check the new nt hash */
@@ -1787,7 +1796,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 	D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
 	if (memcmp(checkHash.hash, nt_pwd.hash, 16) != 0) {
 		status = NT_STATUS_WRONG_PASSWORD;
-		goto out;
+		goto update_login;
 	}
 
 	/* The NT Cross is not required by Win2k3 R2, but if present
@@ -1796,7 +1805,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 		D_P16(lm_pwd.hash, r->in.nt_cross->hash, checkHash.hash);
 		if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
 			status = NT_STATUS_WRONG_PASSWORD;
-			goto out;
+			goto update_login;
 		}
 	}
 
@@ -1806,7 +1815,7 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 		D_P16(nt_pwd.hash, r->in.lm_cross->hash, checkHash.hash);
 		if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
 			status = NT_STATUS_WRONG_PASSWORD;
-			goto out;
+			goto update_login;
 		}
 	}
 
@@ -1817,6 +1826,55 @@ NTSTATUS _samr_ChangePasswordUser(struct pipes_struct *p,
 	}
 
 	status = pdb_update_sam_account(pwd);
+
+update_login:
+
+	/*
+	 * Notify passdb backend of login success/failure. If not
+	 * NT_STATUS_OK the backend doesn't like the login
+	 */
+	update_login_attempts_status = pdb_update_login_attempts(pwd,
+						NT_STATUS_IS_OK(status));
+
+	if (!NT_STATUS_IS_OK(status)) {
+		bool increment_bad_pw_count = false;
+
+		if (NT_STATUS_EQUAL(status,NT_STATUS_WRONG_PASSWORD) &&
+		    (pdb_get_acct_ctrl(pwd) & ACB_NORMAL) &&
+		    NT_STATUS_IS_OK(update_login_attempts_status))
+		{
+			increment_bad_pw_count = true;
+		}
+
+		if (increment_bad_pw_count) {
+			pdb_increment_bad_password_count(pwd);
+			updated_badpw = true;
+		} else {
+			pdb_update_bad_password_count(pwd,
+						      &updated_badpw);
+		}
+	} else {
+
+		if ((pdb_get_acct_ctrl(pwd) & ACB_NORMAL) &&
+		    (pdb_get_bad_password_count(pwd) > 0)){
+			pdb_set_bad_password_count(pwd, 0, PDB_CHANGED);
+			pdb_set_bad_password_time(pwd, 0, PDB_CHANGED);
+			updated_badpw = true;
+		}
+	}
+
+	if (updated_badpw) {
+		NTSTATUS update_status;
+		become_root();
+		update_status = pdb_update_sam_account(pwd);
+		unbecome_root();
+
+		if (!NT_STATUS_IS_OK(update_status)) {
+			DEBUG(1, ("Failed to modify entry: %s\n",
+				  nt_errstr(update_status)));
+		}
+	}
+
  out:
 	TALLOC_FREE(pwd);
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-samba/samba.git




More information about the Pkg-samba-maint mailing list