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