[SCM] Samba Shared Repository - branch v3-5-stable updated

Karolin Seeger kseeger at samba.org
Mon Jan 25 06:37:38 MST 2010


The branch, v3-5-stable has been updated
       via  3389f40... WHATSNEW: Update changes.
       via  f81ef95... s3:auth: fix account unlock regression introduced with fix for bug #4347
       via  8725300... s3:auth: don't update the bad pw count if pw is among last 2 history entries
       via  bfc4bcc... s3:auth:check_sam_security: introduce a bool var to control pad_pw_count incrementation
       via  e6397be... s3:passdb: store the plain nt passwords hashes in history, not salted md5
       via  2fcfdd1... s3:smbd:password_in_history: treat entry with 0 salt as 0 + plain nt hash
       via  624285b... s3:auth:check_sam_security: improve calling and logging of pdb_update_sam_account
       via  d23ad60... s3:auth:check_sam_security: fix a leading tab/ws mixup
       via  5deb3e2... s3:auth:check_sam_security: create (and use) a common exit point
       via  35f158e... s3:auth:check_sam_security: null out sampass after it has been stolen.
       via  079a5fe... s3:auth:sam_password_ok: take username, acct_ctrl and nt/lm hashes, not sampass
       via  47b0b19... s3:auth: use data_blob_null instead of data_blob(NULL, 0) in sam_password_ok()
       via  cd774ba... s3:auth:sam_password_ok: fix allocation of a data blob.
       via  14b75a1... s3:auth:sam_password_ok: enhance readability (imho) by adding some pointers
       via  e0bf3de... s3:check_sam_security: untangle assignment from statement
       via  478e00c... s3: Factor password_in_history() out of check_passwd_history() (cherry picked from commit a92102cf3044ad3be49d6f746ed3f95c49d30412)
       via  7f5220c... Simplify E_md5hash a bit (cherry picked from commit 7e430f3093c5bc06d8ca1186f982fe51af8c5637)
       via  674550c... s3: Simplify pdb_set_plaintext_passwd: pwhistory==NULL can not happen anymore (cherry picked from commit 2042f4937db80939ca3d70816d864b4d762d46fb)
       via  d3a1cc9... s3: Simplify pdb_set_plaintext_passwd: pwHistLen==0 was checked above (cherry picked from commit bfa814be469e5a7c22e45ff8261de749e51414b2)
       via  7e26397... s3: Add a paranoia check to pdb_set_plaintext_passwd() (cherry picked from commit 58b2f41c14e590724e2cb45f23ff7e75d5d2e7ab)
       via  0101bdf... s3: Simplify pdb_set_plaintext_passwd() by removing a redundant condition
       via  d579138... s3: Simplify pdb_set_plaintext_passwd: memcpy deals fine with 0 bytes (cherry picked from commit 8a4463c61292872e9a294a6b026ec6d65d2219b8)
       via  02d23ee... s3: Simplify pdb_set_plaintext_passwd by using talloc_zero_array (cherry picked from commit 501dd6fe17e72d8e487a622c0e66cb5938e66731)
       via  e267e7c... s3: Make use of talloc_array in pdb_set_plaintext_passwd() (cherry picked from commit a5a477648f301b9c435609b0c6f4d76d4229b9ae)
       via  0567a76... s3: Simplify pdb_set_plaintext_passwd() a bit
       via  b3ad0c2... s3: Simplify pdb_set_plaintext_passwd() slightly
       via  d1bff7b... s3: Fix a typo (cherry picked from commit 53e9ffb3a66acfa9af2bf4c616b2b83daf723f49)
       via  4e7b5be... s3: Avoid a memset(, 0, ) call (cherry picked from commit 7758648556aba5242f913d6cc0f46a2d9f1cfaa9)
      from  9956693... WHATSNEW: Update changes since 3.5.0rc1.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-5-stable


- Log -----------------------------------------------------------------
commit 3389f40817fbde52c8b1da480f5cda0428a1b7ed
Author: Karolin Seeger <kseeger at samba.org>
Date:   Mon Jan 25 12:51:41 2010 +0100

    WHATSNEW: Update changes.
    
    Karolin
    (cherry picked from commit 05850542df7c9c6e15bbc609df59c7177d3ab996)

commit f81ef95f5110fea275519bd93b17642789d95dcf
Author: Michael Adam <obnox at samba.org>
Date:   Thu Jan 14 14:24:35 2010 +0100

    s3:auth: fix account unlock regression introduced with fix for bug #4347
    
    By an oversight, the patchset for #4347 made the unlocking of a locked
    account after the lockout duration ineffective.
    Thanks to Björn for finding this!
    
    Michael
    (cherry picked from commit 5eb9b66de0fd0adc59339a944f02f5fe25868568)

commit 872530076011593c1116c16b02e1fa9f0a85f5a8
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 17:29:04 2010 +0100

    s3:auth: don't update the bad pw count if pw is among last 2 history entries
    
    This conforms to the behaviour of Windows 2003:
    http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/bpactlck.mspx
    
    This is supposed to fixes Bug #4347 .
    
    Michael
    (cherry picked from commit fcadc524779a50ee379fb4feb02448944dc174dc)

commit bfc4bccf00bf3a17bd3cf12337953425f0fcc471
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 16:35:44 2010 +0100

    s3:auth:check_sam_security: introduce a bool var to control pad_pw_count incrementation
    
    This is a preparatory patch for the last part in fixing bug #4347 .
    
    Michael
    (cherry picked from commit 0d6ad513e27e83b6a460954f3120395f13f65088)

commit e6397bef88675acc61c1020ac0d5dc848a99beeb
Author: Michael Adam <obnox at samba.org>
Date:   Tue Jan 5 18:28:48 2010 +0100

    s3:passdb: store the plain nt passwords hashes in history, not salted md5
    
    This is in order to be able to do challenge response with the history,
    so that this can be checked when an invalid password was entered:
    If the given password is wrong but in the history, then the bad password
    count should not be updated...
    
    The "lucky" bit here is that the md5 has and the nt hash (md4) both are
    16 bytes long.
    
    This is part of the fix for bug #4347 .
    
    Michael
    (cherry picked from commit d909861c64cf874b1625039b0e1eace507a29b28)

commit 2fcfdd1135286e269e0e246ca2b34156ba37fd7d
Author: Michael Adam <obnox at samba.org>
Date:   Tue Jan 5 16:58:30 2010 +0100

    s3:smbd:password_in_history: treat entry with 0 salt as 0 + plain nt hash
    
    This is to introduce a new format of the password history, maintaining backwards
    compatibility: The old format was 16 byte hash + 16 byte md5(salt + nt hash).
    The new format is 16 zero bytes and 16 bytes nt hash.
    
    This will allow us to respect the last X entries of the nt password history
    when deciding whether to increment the bad password count.
    
    This is part of the fix for bug #4347 .
    
    Michael
    (cherry picked from commit f260d6a48dce32208424aa9bfbf2b1e293e48045)

commit 624285b05afc6c6d46a814e980e47bef9f3f6195
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 13:53:10 2010 +0100

    s3:auth:check_sam_security: improve calling and logging of pdb_update_sam_account
    
    Log what went wrongl, and also call pdb_update_sam_account inside
    become_root/unbecome_root: do the logging outside.
    
    Michael
    (cherry picked from commit 640dfa851a296a403e218096444b203da13ebf10)

commit d23ad60678536ac0a039d1fc0a2dad09de1daba1
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 13:40:58 2010 +0100

    s3:auth:check_sam_security: fix a leading tab/ws mixup
    
    Michael
    (cherry picked from commit 093607e082657ebbf2b49dd5d615c5e6f14c8dcb)

commit 5deb3e29acd5a4f917a972a4d1565f6012e91e06
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 12:36:56 2010 +0100

    s3:auth:check_sam_security: create (and use) a common exit point
    
    for use after sam_password_ok() has been called.
    
    Michael
    (cherry picked from commit 10a847fe9d03d1fe62aa96fee251e10bea1da463)

commit 35f158e283fd4efd92b3c6625ce54b413eb20b31
Author: Michael Adam <obnox at samba.org>
Date:   Wed Jan 6 12:32:51 2010 +0100

    s3:auth:check_sam_security: null out sampass after it has been stolen.
    
    So that a later talloc_free would not harm. I could have used
    talloc_move instead of talloc steal in make_server_info_sam(),
    but this would have required a change of the signature.
    
    Michael
    (cherry picked from commit 1bb4a2ca3a1e11b395b3b819e468ecac67e16d64)

commit 079a5fef10ce8cc9ae11a64456107eb6baec2064
Author: Michael Adam <obnox at samba.org>
Date:   Mon Jan 4 18:15:24 2010 +0100

    s3:auth:sam_password_ok: take username, acct_ctrl and nt/lm hashes, not sampass
    
    This is in preparation to extending check_sam_security to also check
    against the password history before updating the bad password count.
    This way, sam_password_ok can more easily be reused for that purpose.
    
    Michael
    (cherry picked from commit 2925209acc8bcda487fa8f05365ea8fedb232218)

commit 47b0b192e00496f8dff843d435c89a648f60087a
Author: Michael Adam <obnox at samba.org>
Date:   Mon Jan 4 15:37:24 2010 +0100

    s3:auth: use data_blob_null instead of data_blob(NULL, 0) in sam_password_ok()
    
    This way it is more explicit that there is no allocated data here
    that may leak.
    
    Michael
    (cherry picked from commit c9e05e11b152401d63ae9b8b40c717d0bd3d0646)

commit cd774bafc11b2dbb981710697e716d0ae896496d
Author: Michael Adam <obnox at samba.org>
Date:   Wed Dec 30 15:37:23 2009 +0100

    s3:auth:sam_password_ok: fix allocation of a data blob.
    
    data_blob(mem_ctx, 16) does not use mem_ctx as a talloc ctx but
    copies 16 bytes from mem_ctx into the newly allocated data blob.
    This can not have been intentional. A blank uint8_t array of
    length 16 is allocated by passing NULL instead of mem_ctx.
    And using data_blob_talloc(mem_ctx, NULL, 16) adds the allocated
    blank 16 byte array to mem_ctx - so this is what must have been
    intended.
    
    Michael
    (cherry picked from commit c3bd0b5951f09f102abaa19fb2e1f55711b975d2)

commit 14b75a10f23de06c843fd0f489bcc9eb0d504f30
Author: Michael Adam <obnox at samba.org>
Date:   Wed Dec 30 15:35:50 2009 +0100

    s3:auth:sam_password_ok: enhance readability (imho) by adding some pointers
    
    and removing bool variables and several checks.
    
    Michael
    (cherry picked from commit 761a8b8fa5b5d05d5802fecf07229de40d33c558)

commit e0bf3deafb5a53b529f0504d2be6605c2c255e5b
Author: Michael Adam <obnox at samba.org>
Date:   Wed Dec 30 12:46:22 2009 +0100

    s3:check_sam_security: untangle assignment from statement
    
    Michael
    (cherry picked from commit 232602ee2914851b0af851aa5dada3bf1c99dcff)

commit 478e00c760de5625018a86c03a668d0cabbbf3c9
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 20:54:33 2009 +0100

    s3: Factor password_in_history() out of check_passwd_history()
    (cherry picked from commit a92102cf3044ad3be49d6f746ed3f95c49d30412)

commit 7f5220c728bf7e5f711923ed7fd72559dd61b225
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 19:29:36 2009 +0100

    Simplify E_md5hash a bit
    (cherry picked from commit 7e430f3093c5bc06d8ca1186f982fe51af8c5637)

commit 674550c8f5592af87c8ae84f4094a5b2d8844d74
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 19:18:09 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd: pwhistory==NULL can not happen anymore
    (cherry picked from commit 2042f4937db80939ca3d70816d864b4d762d46fb)

commit d3a1cc995fdacbbc6daa6f3809cd09a25b266505
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 19:16:58 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd: pwHistLen==0 was checked above
    (cherry picked from commit bfa814be469e5a7c22e45ff8261de749e51414b2)

commit 7e26397c2e9ade3ed655fedab03e2cc62aa134db
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 19:12:50 2009 +0100

    s3: Add a paranoia check to pdb_set_plaintext_passwd()
    (cherry picked from commit 58b2f41c14e590724e2cb45f23ff7e75d5d2e7ab)

commit 0101bdf41b83df6b11d91cba86ac49aac7babf50
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:50:38 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd() by removing a redundant condition
    
    if (current_history_len != pwHistLen) {
         if (current_history_len < pwHistLen) {
         }
    }
    
    The second "if" is a bit pointless here
    (cherry picked from commit 76a9af7cac4a6d6ba00d81a946db094ecfd43817)

commit d5791386f0b5162b078408df2eceaba7837f1977
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:44:38 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd: memcpy deals fine with 0 bytes
    (cherry picked from commit 8a4463c61292872e9a294a6b026ec6d65d2219b8)

commit 02d23eeeca6122471d3684dab94f6ff5d8e51b90
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:43:03 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd by using talloc_zero_array
    (cherry picked from commit 501dd6fe17e72d8e487a622c0e66cb5938e66731)

commit e267e7c8403f98dcb0abf6f48a2385c8e2980cba
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:39:19 2009 +0100

    s3: Make use of talloc_array in pdb_set_plaintext_passwd()
    (cherry picked from commit a5a477648f301b9c435609b0c6f4d76d4229b9ae)

commit 0567a7615de54a6cff6e808dd1e7fbf8a3616476
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:24:04 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd() a bit
    
    Remove an indentation by the early return in
    
    +       if (pwHistLen == 0) {
    +               /* Set the history length to zero. */
    +               pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
    +               return true;
    +       }
    (cherry picked from commit 7097be60809252c6faf0388d0019384f01a7ff42)

commit b3ad0c290bd7e4e2f1ecf6376bce1597a2c7cb62
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 18:13:28 2009 +0100

    s3: Simplify pdb_set_plaintext_passwd() slightly
    
    No functional change, this just removes an indentation level by the early
    "return True;" in
    
    +       if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) {
    +               /*
    +                * No password history for non-user accounts
    +                */
    +               return true;
    +       }
    
    Volker
    (cherry picked from commit 0630fdc5ec8440c8338c7302dc5b52849e3f50be)

commit d1bff7b8f601df38161be9aba3a9d70f609d946e
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 17:51:39 2009 +0100

    s3: Fix a typo
    (cherry picked from commit 53e9ffb3a66acfa9af2bf4c616b2b83daf723f49)

commit 4e7b5becb1c7715bf17b59aa59235a9861a7f544
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Dec 14 17:43:56 2009 +0100

    s3: Avoid a memset(, 0, ) call
    (cherry picked from commit 7758648556aba5242f913d6cc0f46a2d9f1cfaa9)

-----------------------------------------------------------------------

Summary of changes:
 WHATSNEW.txt                 |    4 +
 libcli/auth/smbencrypt.c     |    8 +--
 source3/auth/auth_sam.c      |  197 +++++++++++++++++++++++++++++++-----------
 source3/include/proto.h      |    3 +
 source3/passdb/pdb_get_set.c |  133 ++++++++++++++++-------------
 source3/smbd/chgpasswd.c     |   87 +++++++++++++------
 6 files changed, 291 insertions(+), 141 deletions(-)


Changeset truncated at 500 lines:

diff --git a/WHATSNEW.txt b/WHATSNEW.txt
index e71ffce..ac82c51 100644
--- a/WHATSNEW.txt
+++ b/WHATSNEW.txt
@@ -115,6 +115,10 @@ Changes since 3.5.0rc1
 ----------------------
 
 
+o   Michael Adam <obnox at samba.org>
+    * BUG 4347: Check password history before increasing "badPasswordCount".
+
+
 o   Jeremy Allison <jra at samba.org>
     * BUG 5202: Fix changing of ACLs on writable file with "dos filemode=yes".
     * BUG 6876: Fix deletion of an object whose parent folder does not have delete
diff --git a/libcli/auth/smbencrypt.c b/libcli/auth/smbencrypt.c
index a3182cd..f7c60e7 100644
--- a/libcli/auth/smbencrypt.c
+++ b/libcli/auth/smbencrypt.c
@@ -100,13 +100,9 @@ bool E_md4hash(const char *passwd, uint8_t p16[16])
 void E_md5hash(const uint8_t salt[16], const uint8_t nthash[16], uint8_t hash_out[16])
 {
 	struct MD5Context tctx;
-	uint8_t array[32];
-
-	memset(hash_out, '\0', 16);
-	memcpy(array, salt, 16);
-	memcpy(&array[16], nthash, 16);
 	MD5Init(&tctx);
-	MD5Update(&tctx, array, 32);
+	MD5Update(&tctx, salt, 16);
+	MD5Update(&tctx, nthash, 16);
 	MD5Final(hash_out, &tctx);
 }
 
diff --git a/source3/auth/auth_sam.c b/source3/auth/auth_sam.c
index f0500b3..bd99b3a 100644
--- a/source3/auth/auth_sam.c
+++ b/source3/auth/auth_sam.c
@@ -33,21 +33,23 @@
 
 static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
 				TALLOC_CTX *mem_ctx,
-				struct samu *sampass, 
+				const char *username,
+				uint32_t acct_ctrl,
+				const uint8_t *lm_pw,
+				const uint8_t *nt_pw,
 				const auth_usersupplied_info *user_info, 
 				DATA_BLOB *user_sess_key, 
 				DATA_BLOB *lm_sess_key)
 {
-	uint32 acct_ctrl;
-	const uint8 *lm_pw, *nt_pw;
-	struct samr_Password lm_hash, nt_hash, client_lm_hash, client_nt_hash;
-	const char *username = pdb_get_username(sampass);
-	bool got_lm = false, got_nt = false;
+	struct samr_Password _lm_hash, _nt_hash, _client_lm_hash, _client_nt_hash;
+	struct samr_Password *lm_hash = NULL;
+	struct samr_Password *nt_hash = NULL;
+	struct samr_Password *client_lm_hash = NULL;
+	struct samr_Password *client_nt_hash = NULL;
 
-	*user_sess_key = data_blob(NULL, 0);
-	*lm_sess_key = data_blob(NULL, 0);
+	*user_sess_key = data_blob_null;
+	*lm_sess_key = data_blob_null;
 
-	acct_ctrl = pdb_get_acct_ctrl(sampass);
 	if (acct_ctrl & ACB_PWNOTREQ) {
 		if (lp_null_passwords()) {
 			DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", username));
@@ -58,34 +60,35 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
 		}		
 	}
 
-	lm_pw = pdb_get_lanman_passwd(sampass);
-	nt_pw = pdb_get_nt_passwd(sampass);
 	if (lm_pw) {
-		memcpy(lm_hash.hash, lm_pw, sizeof(lm_hash.hash));
+		memcpy(_lm_hash.hash, lm_pw, sizeof(_lm_hash.hash));
+		lm_hash = &_lm_hash;
 	}
 	if (nt_pw) {
-		memcpy(nt_hash.hash, nt_pw, sizeof(nt_hash.hash));
+		memcpy(_nt_hash.hash, nt_pw, sizeof(_nt_hash.hash));
+		nt_hash = &_nt_hash;
 	}
-	if (user_info->lm_interactive_pwd.data && sizeof(client_lm_hash.hash) == user_info->lm_interactive_pwd.length) {
-		memcpy(client_lm_hash.hash, user_info->lm_interactive_pwd.data, sizeof(lm_hash.hash));
-		got_lm = true;
+	if (user_info->lm_interactive_pwd.data && sizeof(_client_lm_hash.hash) == user_info->lm_interactive_pwd.length) {
+		memcpy(_client_lm_hash.hash, user_info->lm_interactive_pwd.data, sizeof(_lm_hash.hash));
+		client_lm_hash = &_client_lm_hash;
 	}
-	if (user_info->nt_interactive_pwd.data && sizeof(client_nt_hash.hash) == user_info->nt_interactive_pwd.length) {
-		memcpy(client_nt_hash.hash, user_info->nt_interactive_pwd.data, sizeof(nt_hash.hash));
-		got_nt = true;
+	if (user_info->nt_interactive_pwd.data && sizeof(_client_nt_hash.hash) == user_info->nt_interactive_pwd.length) {
+		memcpy(_client_nt_hash.hash, user_info->nt_interactive_pwd.data, sizeof(_nt_hash.hash));
+		client_nt_hash = &_client_nt_hash;
 	}
-	if (got_lm || got_nt) {
-		*user_sess_key = data_blob(mem_ctx, 16);
+
+	if (client_lm_hash || client_nt_hash) {
+		*user_sess_key = data_blob_talloc(mem_ctx, NULL, 16);
 		if (!user_sess_key->data) {
 			return NT_STATUS_NO_MEMORY;
 		}
 		SMBsesskeygen_ntv1(nt_pw, user_sess_key->data);
 		return hash_password_check(mem_ctx, lp_lanman_auth(),
-					   got_lm ? &client_lm_hash : NULL, 
-					   got_nt ? &client_nt_hash : NULL,
+					   client_lm_hash,
+					   client_nt_hash,
 					   username, 
-					   lm_pw ? &lm_hash: NULL, 
-					   nt_pw ? &nt_hash : NULL);
+					   lm_hash,
+					   nt_hash);
 	} else {
 		return ntlm_password_check(mem_ctx, lp_lanman_auth(),
 					   lp_ntlm_auth(),
@@ -95,8 +98,8 @@ static NTSTATUS sam_password_ok(const struct auth_context *auth_context,
 					   username, 
 					   user_info->smb_name,
 					   user_info->client_domain,
-					   lm_pw ? &lm_hash: NULL, 
-					   nt_pw ? &nt_hash : NULL,
+					   lm_hash,
+					   nt_hash,
 					   user_sess_key, lm_sess_key);
 	}
 }
@@ -278,6 +281,75 @@ static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx,
 	return NT_STATUS_OK;
 }
 
+/**
+ * Check whether the given password is one of the last two
+ * password history entries. If so, the bad pwcount should
+ * not be incremented even thought the actual password check
+ * failed.
+ */
+static bool need_to_increment_bad_pw_count(
+	const struct auth_context *auth_context,
+	struct samu* sampass,
+	const auth_usersupplied_info *user_info)
+{
+	uint8_t i;
+	const uint8_t *pwhistory;
+	uint32_t pwhistory_len;
+	uint32_t policy_pwhistory_len;
+	uint32_t acct_ctrl;
+	const char *username;
+	TALLOC_CTX *mem_ctx = talloc_stackframe();
+	bool result = true;
+
+	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY,
+			       &policy_pwhistory_len);
+	if (policy_pwhistory_len == 0) {
+		goto done;
+	}
+
+	pwhistory = pdb_get_pw_history(sampass, &pwhistory_len);
+	if (!pwhistory || pwhistory_len == 0) {
+		goto done;
+	}
+
+	acct_ctrl = pdb_get_acct_ctrl(sampass);
+	username = pdb_get_username(sampass);
+
+	for (i=1; i < MIN(MIN(3, policy_pwhistory_len), pwhistory_len); i++) {
+		static const uint8_t zero16[SALTED_MD5_HASH_LEN];
+		const uint8_t *salt;
+		const uint8_t *nt_pw;
+		NTSTATUS status;
+		DATA_BLOB user_sess_key = data_blob_null;
+		DATA_BLOB lm_sess_key = data_blob_null;
+
+		salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
+		nt_pw = salt + PW_HISTORY_SALT_LEN;
+
+		if (memcmp(zero16, nt_pw, NT_HASH_LEN) == 0) {
+			/* skip zero password hash */
+			continue;
+		}
+
+		if (memcmp(zero16, salt, PW_HISTORY_SALT_LEN) != 0) {
+			/* skip nonzero salt (old format entry) */
+			continue;
+		}
+
+		status = sam_password_ok(auth_context, mem_ctx,
+					 username, acct_ctrl, NULL, nt_pw,
+					 user_info, &user_sess_key, &lm_sess_key);
+		if (NT_STATUS_IS_OK(status)) {
+			result = false;
+			break;
+		}
+	}
+
+done:
+	TALLOC_FREE(mem_ctx);
+	return result;
+}
+
 /****************************************************************************
 check if a username/password is OK assuming the password is a 24 byte
 SMB hash supplied in the user_info structure
@@ -297,6 +369,9 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 	DATA_BLOB user_sess_key = data_blob_null;
 	DATA_BLOB lm_sess_key = data_blob_null;
 	bool updated_autolock = False, updated_badpw = False;
+	const char *username;
+	const uint8_t *nt_pw;
+	const uint8_t *lm_pw;
 
 	if (!user_info || !auth_context) {
 		return NT_STATUS_UNSUCCESSFUL;
@@ -305,7 +380,8 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 	/* the returned struct gets kept on the server_info, by means
 	   of a steal further down */
 
-	if ( !(sampass = samu_new( mem_ctx )) ) {
+	sampass = samu_new(mem_ctx);
+	if (sampass == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
@@ -322,16 +398,21 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 		return NT_STATUS_NO_SUCH_USER;
 	}
 
+	username = pdb_get_username(sampass);
+	nt_pw = pdb_get_nt_passwd(sampass);
+	lm_pw = pdb_get_lanman_passwd(sampass);
+
 	/* see if autolock flag needs to be updated */
 	if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL)
 		pdb_update_autolock_flag(sampass, &updated_autolock);
 	/* 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", pdb_get_username(sampass)));
+		DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", username));
 		return NT_STATUS_ACCOUNT_LOCKED_OUT;
 	}
 
-	nt_status = sam_password_ok(auth_context, mem_ctx, sampass, 
+	nt_status = sam_password_ok(auth_context, mem_ctx,
+				    username, pdb_get_acct_ctrl(sampass), lm_pw, nt_pw,
 				    user_info, &user_sess_key, &lm_sess_key);
 
 	/* Notify passdb backend of login success/failure. If not 
@@ -340,10 +421,19 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 	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 &&
+		    pdb_get_acct_ctrl(sampass) & ACB_NORMAL &&
 		    NT_STATUS_IS_OK(update_login_attempts_status)) 
-		{  
+		{
+			increment_bad_pw_count =
+				need_to_increment_bad_pw_count(auth_context,
+							       sampass,
+							       user_info);
+		}
+
+		if (increment_bad_pw_count) {
 			pdb_increment_bad_password_count(sampass);
 			updated_badpw = True;
 		} else {
@@ -351,18 +441,21 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 						      &updated_badpw);
 		}
 		if (updated_autolock || updated_badpw){
+			NTSTATUS status;
+
 			become_root();
-			if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
-				DEBUG(1, ("Failed to modify entry.\n"));
+			status = pdb_update_sam_account(sampass);
 			unbecome_root();
+
+			if (!NT_STATUS_IS_OK(status)) {
+				DEBUG(1, ("Failed to modify entry: %s\n",
+					  nt_errstr(status)));
+			}
 		}
-		data_blob_free(&user_sess_key);
-		data_blob_free(&lm_sess_key);
-		TALLOC_FREE(sampass);
-		return nt_status;
+		goto done;
 	}
 
-	if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) && 
+	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);
@@ -370,30 +463,32 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 	}
 
 	if (updated_autolock || updated_badpw){
+		NTSTATUS status;
+
 		become_root();
-		if(!NT_STATUS_IS_OK(pdb_update_sam_account(sampass)))
-			DEBUG(1, ("Failed to modify entry.\n"));
+		status = pdb_update_sam_account(sampass);
 		unbecome_root();
- 	}
+
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(1, ("Failed to modify entry: %s\n",
+				  nt_errstr(status)));
+		}
+	}
 
 	nt_status = sam_account_ok(mem_ctx, sampass, user_info);
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
-		TALLOC_FREE(sampass);
-		data_blob_free(&user_sess_key);
-		data_blob_free(&lm_sess_key);
-		return nt_status;
+		goto done;
 	}
 
 	become_root();
 	nt_status = make_server_info_sam(server_info, sampass);
 	unbecome_root();
+	sampass = NULL;
 
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status)));
-		data_blob_free(&user_sess_key);
-		data_blob_free(&lm_sess_key);
-		return nt_status;
+		goto done;
 	}
 
 	(*server_info)->user_session_key =
@@ -408,6 +503,10 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context,
 
 	(*server_info)->nss_token |= user_info->was_mapped;
 
+done:
+	TALLOC_FREE(sampass);
+	data_blob_free(&user_sess_key);
+	data_blob_free(&lm_sess_key);
 	return nt_status;
 }
 
diff --git a/source3/include/proto.h b/source3/include/proto.h
index b3512d9..b363358 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6099,6 +6099,9 @@ NTSTATUS pass_oem_change(char *user,
 			 uchar password_encrypted_with_nt_hash[516],
 			 const uchar old_nt_hash_encrypted[16],
 			 uint32 *reject_reason);
+bool password_in_history(uint8_t nt_pw[NT_HASH_LEN],
+			 uint32_t pw_history_len,
+			 const uint8_t *pw_history);
 NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason);
 
 /* The following definitions come from smbd/close.c  */
diff --git a/source3/passdb/pdb_get_set.c b/source3/passdb/pdb_get_set.c
index 30775e4..74ed018 100644
--- a/source3/passdb/pdb_get_set.c
+++ b/source3/passdb/pdb_get_set.c
@@ -980,6 +980,9 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 {
 	uchar new_lanman_p16[LM_HASH_LEN];
 	uchar new_nt_p16[NT_HASH_LEN];
+	uchar *pwhistory;
+	uint32 pwHistLen;
+	uint32 current_history_len;
 
 	if (!plaintext)
 		return False;
@@ -1009,68 +1012,80 @@ bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext)
 	if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED))
 		return False;
 
-	/* Store the password history. */
-	if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) {
-		uchar *pwhistory;
-		uint32 pwHistLen;
-		pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
-		if (pwHistLen != 0){
-			uint32 current_history_len;
-			/* We need to make sure we don't have a race condition here - the
-			   account policy history length can change between when the pw_history
-			   was first loaded into the struct samu struct and now.... JRA. */
-			pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);
-
-			if (current_history_len != pwHistLen) {
-				/* After closing and reopening struct samu the history
-					values will sync up. We can't do this here. */
-
-				/* current_history_len > pwHistLen is not a problem - we
-					have more history than we need. */
-
-				if (current_history_len < pwHistLen) {
-					/* Ensure we have space for the needed history. */
-					uchar *new_history = (uchar *)TALLOC(sampass,
-								pwHistLen*PW_HISTORY_ENTRY_LEN);
-					if (!new_history) {
-						return False;
-					}
-
-					/* And copy it into the new buffer. */
-					if (current_history_len) {
-						memcpy(new_history, pwhistory,
-							current_history_len*PW_HISTORY_ENTRY_LEN);
-					}
-					/* Clearing out any extra space. */
-					memset(&new_history[current_history_len*PW_HISTORY_ENTRY_LEN],
-						'\0', (pwHistLen-current_history_len)*PW_HISTORY_ENTRY_LEN);
-					/* Finally replace it. */
-					pwhistory = new_history;
-				}
-			}
-			if (pwhistory && pwHistLen){
-				/* Make room for the new password in the history list. */
-				if (pwHistLen > 1) {
-					memmove(&pwhistory[PW_HISTORY_ENTRY_LEN],
-						pwhistory, (pwHistLen -1)*PW_HISTORY_ENTRY_LEN );
-				}
-				/* Create the new salt as the first part of the history entry. */
-				generate_random_buffer(pwhistory, PW_HISTORY_SALT_LEN);
-
-				/* Generate the md5 hash of the salt+new password as the second
-					part of the history entry. */
-
-				E_md5hash(pwhistory, new_nt_p16, &pwhistory[PW_HISTORY_SALT_LEN]);
-				pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED);
-			} else {
-				DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n"));
-			}
-		} else {
-			/* Set the history length to zero. */
-			pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
+	if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) {
+		/*
+		 * No password history for non-user accounts
+		 */
+		return true;
+	}
+
+	pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
+
+	if (pwHistLen == 0) {
+		/* Set the history length to zero. */
+		pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED);
+		return true;
+	}
+
+	/*
+	 * We need to make sure we don't have a race condition here -
+	 * the account policy history length can change between when
+	 * the pw_history was first loaded into the struct samu struct
+	 * and now.... JRA.
+	 */
+	pwhistory = (uchar *)pdb_get_pw_history(sampass, &current_history_len);
+
+	if ((current_history_len != 0) && (pwhistory == NULL)) {
+		DEBUG(1, ("pdb_set_plaintext_passwd: pwhistory == NULL!\n"));
+		return false;
+	}
+
+	if (current_history_len < pwHistLen) {
+		/*
+		 * Ensure we have space for the needed history. This
+		 * also takes care of an account which did not have
+		 * any history at all so far, i.e. pwhistory==NULL
+		 */
+		uchar *new_history = talloc_zero_array(
+			sampass, uchar,
+			pwHistLen*PW_HISTORY_ENTRY_LEN);
+
+		if (!new_history) {
+			return False;
 		}
+
+		memcpy(new_history, pwhistory,
+		       current_history_len*PW_HISTORY_ENTRY_LEN);
+
+		pwhistory = new_history;
 	}
 
+	/*


-- 
Samba Shared Repository


More information about the samba-cvs mailing list