The branch, master has been updated
       via  a75378e3542 s4:kdc: translate sdb_entry->old[er]_keys into 
hdb_add_history_key()
       via  d4007b0ef9f s4:dsdb/tests: also verify too old, older password 
interaction with badPwdCount
       via  28cf6c70676 s4:dsdb/tests: Test Kerberos login with old password 
fails (but badPwdCount=0)
       via  370ba4ad527 s4:kdc: handle passwords from the history in 
hdb_samba4_auth_status()
      from  4a8cfe1650a vfs: Remove "sbuf" from readdir_fn()

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit a75378e354286d095d82f644d645768345cd00fb
Author: Stefan Metzmacher <me...@samba.org>
Date:   Mon Feb 7 19:32:08 2022 +0100

    s4:kdc: translate sdb_entry->old[er]_keys into hdb_add_history_key()
    
    It means that using the old or older password no longer
    changes badPwdCount for Kerberos authentication.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14054
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    
    Autobuild-User(master): Andrew Bartlett <abart...@samba.org>
    Autobuild-Date(master): Sat Jun 24 07:18:03 UTC 2023 on atb-devel-224

commit d4007b0ef9f745a4881588ef1b8185d6b53025ee
Author: Stefan Metzmacher <me...@samba.org>
Date:   Fri Jun 23 13:42:31 2023 +0200

    s4:dsdb/tests: also verify too old, older password interaction with 
badPwdCount
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14054
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 28cf6c706760894b7c0c65d4f5307d333d194154
Author: Stefan Metzmacher <me...@samba.org>
Date:   Fri Feb 25 05:16:36 2022 +0100

    s4:dsdb/tests: Test Kerberos login with old password fails (but 
badPwdCount=0)
    
    This demonstrates the pre-authentication failures with passwords from
    the password history don't incremend badPwdCount, similar to the
    NTLMSSP and simple bind cases. But it's still an interactive logon,
    which doesn't use 'old password allowed period'.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14054
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

commit 370ba4ad527b67555f69c2bc4b92effe0cc7169d
Author: Stefan Metzmacher <me...@samba.org>
Date:   Thu Feb 17 07:12:10 2022 +0100

    s4:kdc: handle passwords from the history in hdb_samba4_auth_status()
    
    This is important in order to prevent ACCOUNT_LOCKED_OUT
    with cached credentials.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14054
    
    Signed-off-by: Stefan Metzmacher <me...@samba.org>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>

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

Summary of changes:
 selftest/knownfail_mit_kdc                |  5 ++
 source4/dsdb/tests/python/login_basics.py | 97 ++++++++++++++++++++++++++++---
 source4/kdc/hdb-samba4.c                  | 11 ++++
 source4/kdc/sdb_to_hdb.c                  | 45 ++++++++++++++
 4 files changed, 149 insertions(+), 9 deletions(-)


Changeset truncated at 500 lines:

diff --git a/selftest/knownfail_mit_kdc b/selftest/knownfail_mit_kdc
index 9c5b76cac5a..8196f4f4d6b 100644
--- a/selftest/knownfail_mit_kdc
+++ b/selftest/knownfail_mit_kdc
@@ -2221,3 +2221,8 @@ 
samba.tests.krb5.as_canonicalization_tests.samba.tests.krb5.as_canonicalization_
 
^samba.tests.krb5.authn_policy_tests.samba.tests.krb5.authn_policy_tests.AuthnPolicyTests.test_authn_policy_bad_pwd_allowed_from_user_deny.ad_dc
 
^samba.tests.krb5.authn_policy_tests.samba.tests.krb5.authn_policy_tests.AuthnPolicyTests.test_authn_policy_denied_no_fast.ad_dc
 
^samba.tests.krb5.authn_policy_tests.samba.tests.krb5.authn_policy_tests.AuthnPolicyTests.test_authn_policy_tgt_lifetime_min.ad_dc
+#
+# MIT does not support password history in order to avoid badPwdCount changes
+# with the last password, see https://bugzilla.samba.org/show_bug.cgi?id=14054
+#
+^samba4.ldap.login_basics.python.*.__main__.BasicUserAuthTests.test_login_basics_krb5
diff --git a/source4/dsdb/tests/python/login_basics.py 
b/source4/dsdb/tests/python/login_basics.py
index b186e723f39..babe04879b1 100755
--- a/source4/dsdb/tests/python/login_basics.py
+++ b/source4/dsdb/tests/python/login_basics.py
@@ -122,7 +122,7 @@ class BasicUserAuthTests(BasePasswordTestCase):
         lastLogon = int(res[0]["lastLogon"][0])
 
         # check that the user can change its password
-        new_password = "thatsAcomplPASS2"
+        too_old_password = "thatsAcomplTooOldPass1!"
         user_ldb.modify_ldif("""
 dn: %s
 changetype: modify
@@ -130,28 +130,74 @@ delete: userPassword
 userPassword: %s
 add: userPassword
 userPassword: %s
-""" % (userdn, userpass, new_password))
+""" % (userdn, userpass, too_old_password))
+
+        # change the password again
+        older_password = "thatsAcomplOlderPass1!"
+        user_ldb.modify_ldif("""
+dn: %s
+changetype: modify
+delete: userPassword
+userPassword: %s
+add: userPassword
+userPassword: %s
+""" % (userdn, too_old_password, older_password))
+
+        # change the password again
+        old_password = "thatsAcomplOldPass1!"
+        user_ldb.modify_ldif("""
+dn: %s
+changetype: modify
+delete: userPassword
+userPassword: %s
+add: userPassword
+userPassword: %s
+""" % (userdn, older_password, old_password))
+
+        # change the password once more
+        new_password = "thatsAcomplNewPass1!"
+        user_ldb.modify_ldif("""
+dn: %s
+changetype: modify
+delete: userPassword
+userPassword: %s
+add: userPassword
+userPassword: %s
+""" % (userdn, old_password, new_password))
 
         # discard the old creds (i.e. get rid of our valid Kerberos ticket)
         del test_creds
         test_creds = self.insta_creds(creds)
-        test_creds.set_password(userpass)
+        test_creds.set_password(older_password)
+
+        self.assertLoginFailure(ldap_url, test_creds, self.lp)
+        res = self._check_account(userdn,
+                                  badPwdCount=0,
+                                  badPasswordTime=badPasswordTime,
+                                  logonCount=logonCount,
+                                  lastLogon=lastLogon,
+                                  lastLogonTimestamp=lastLogonTimestamp,
+                                  userAccountControl=UF_NORMAL_ACCOUNT,
+                                  msDSUserAccountControlComputed=0,
+                                  msg='Test with older password fails (but 
badPwdCount=0)')
+
+        del test_creds
+        test_creds = self.insta_creds(creds)
+        test_creds.set_password(old_password)
 
         # for Kerberos, logging in with the old password fails
         if creds.get_kerberos_state() == MUST_USE_KERBEROS:
             self.assertLoginFailure(ldap_url, test_creds, self.lp)
-            info_msg = 'Test Kerberos login with old password fails'
-            expectBadPwdTime = ("greater", badPasswordTime)
+            info_msg = 'Test Kerberos login with old password fails (but 
badPwdCount=0)'
             res = self._check_account(userdn,
-                                      badPwdCount=1,
-                                      badPasswordTime=expectBadPwdTime,
+                                      badPwdCount=0,
+                                      badPasswordTime=badPasswordTime,
                                       logonCount=logonCount,
                                       lastLogon=lastLogon,
                                       lastLogonTimestamp=lastLogonTimestamp,
                                       userAccountControl=UF_NORMAL_ACCOUNT,
                                       msDSUserAccountControlComputed=0,
                                       msg=info_msg)
-            badPasswordTime = int(res[0]["badPasswordTime"][0])
         else:
             # for NTLM, logging in with the old password succeeds
             user_ldb = self.assertLoginSuccess(ldap_url, test_creds, self.lp)
@@ -168,8 +214,10 @@ userPassword: %s
                                       userAccountControl=UF_NORMAL_ACCOUNT,
                                       msDSUserAccountControlComputed=0,
                                       msg=info_msg)
+            logonCount = int(res[0]["logonCount"][0])
+            lastLogon = int(res[0]["lastLogon"][0])
 
-        # check logging in with the new password succeeds
+        # check logging in with the correct password succeeds
         test_creds.set_password(new_password)
         user_ldb = self.assertLoginSuccess(ldap_url, test_creds, self.lp)
         res = self._check_account(userdn,
@@ -181,6 +229,37 @@ userPassword: %s
                                   userAccountControl=UF_NORMAL_ACCOUNT,
                                   msDSUserAccountControlComputed=0,
                                   msg='Test login with new password succeeds')
+        logonCount = int(res[0]["logonCount"][0])
+        lastLogon = int(res[0]["lastLogon"][0])
+
+        del test_creds
+        test_creds = self.insta_creds(creds)
+        test_creds.set_password(too_old_password)
+
+        self.assertLoginFailure(ldap_url, test_creds, self.lp)
+        res = self._check_account(userdn,
+                                  badPwdCount=1,
+                                  badPasswordTime=("greater", badPasswordTime),
+                                  logonCount=logonCount,
+                                  lastLogon=lastLogon,
+                                  lastLogonTimestamp=lastLogonTimestamp,
+                                  userAccountControl=UF_NORMAL_ACCOUNT,
+                                  msDSUserAccountControlComputed=0,
+                                  msg='Test login with too old password fails')
+        badPasswordTime = int(res[0]["badPasswordTime"][0])
+
+        # check logging in with the correct password succeeds
+        test_creds.set_password(new_password)
+        user_ldb = self.assertLoginSuccess(ldap_url, test_creds, self.lp)
+        res = self._check_account(userdn,
+                                  badPwdCount=0,
+                                  badPasswordTime=badPasswordTime,
+                                  logonCount=(logoncount_relation, logonCount),
+                                  lastLogon=('greater', lastLogon),
+                                  lastLogonTimestamp=lastLogonTimestamp,
+                                  userAccountControl=UF_NORMAL_ACCOUNT,
+                                  msDSUserAccountControlComputed=0,
+                                  msg='Test login with new password succeeds 
again')
 
     def test_login_basics_krb5(self):
         self._test_login_basics(self.lockout1krb5_creds)
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c
index 90e52f60cef..c176a84eb5b 100644
--- a/source4/kdc/hdb-samba4.c
+++ b/source4/kdc/hdb-samba4.c
@@ -846,6 +846,17 @@ static krb5_error_code hdb_samba4_audit(krb5_context 
context,
                                status = NT_STATUS_WRONG_PASSWORD;
                        }
                        rwdc_fallback = kdc_db_ctx->rodc;
+               } else if (hdb_auth_status == 
KDC_AUTH_EVENT_HISTORIC_LONG_TERM_KEY) {
+                       /*
+                        * The pre-authentication succeeds with a password
+                        * from the password history, so we don't
+                        * update the badPwdCount, but still return
+                        * PREAUTH_FAILED and need to forward to
+                        * a RWDC in order to produce an autoritative
+                        * response for the client.
+                        */
+                       status = NT_STATUS_WRONG_PASSWORD;
+                       rwdc_fallback = kdc_db_ctx->rodc;
                } else if (hdb_auth_status == KDC_AUTH_EVENT_CLIENT_LOCKED_OUT) 
{
                        edata_status = status = NT_STATUS_ACCOUNT_LOCKED_OUT;
                        rwdc_fallback = kdc_db_ctx->rodc;
diff --git a/source4/kdc/sdb_to_hdb.c b/source4/kdc/sdb_to_hdb.c
index 994a52d7d44..93d2f3f5980 100644
--- a/source4/kdc/sdb_to_hdb.c
+++ b/source4/kdc/sdb_to_hdb.c
@@ -147,6 +147,31 @@ static int sdb_keys_to_Keys(const struct sdb_keys *s, Keys 
*h)
        return 0;
 }
 
+static int sdb_keys_to_HistKeys(krb5_context context,
+                               const struct sdb_keys *s,
+                               krb5_kvno kvno,
+                               hdb_entry *h)
+{
+       unsigned int i;
+
+       for (i = 0; i < s->len; i++) {
+               Key k = { 0, };
+               int ret;
+
+               ret = sdb_key_to_Key(&s->val[i], &k);
+               if (ret != 0) {
+                       return ENOMEM;
+               }
+               ret = hdb_add_history_key(context, h, kvno, &k);
+               free_Key(&k);
+               if (ret != 0) {
+                       return ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
 static int sdb_event_to_Event(krb5_context context,
                              const struct sdb_event *s, Event *h)
 {
@@ -192,6 +217,26 @@ int sdb_entry_to_hdb_entry(krb5_context context,
                goto error;
        }
 
+       if (h->kvno > 1) {
+               rc = sdb_keys_to_HistKeys(context,
+                                         &s->old_keys,
+                                         h->kvno - 1,
+                                         h);
+               if (rc != 0) {
+                       goto error;
+               }
+       }
+
+       if (h->kvno > 2) {
+               rc = sdb_keys_to_HistKeys(context,
+                                         &s->older_keys,
+                                         h->kvno - 2,
+                                         h);
+               if (rc != 0) {
+                       goto error;
+               }
+       }
+
        rc = sdb_event_to_Event(context,
                                 &s->created_by,
                                 &h->created_by);


-- 
Samba Shared Repository

Reply via email to