[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