From 3b849f87f7237a3677338075309abb1355a4d9ef Mon Sep 17 00:00:00 2001 From: Tim Beale Date: Thu, 19 Apr 2018 10:46:48 +1200 Subject: [PATCH] dsdb: Update password_hash to use PSO settings for password changes Honour the settings in the PSO when changing the password, i.e. msDS-PasswordComplexityEnabled, msDS-PasswordHistoryLength, etc. The password_hash code populates dsdb_control_password_change_status's domain_data with the password settings to use - these are currently based on the settings for the domain. Now, if the password_hash code has worked out that a PSO applies to the user, we override the domain settings with the PSO's values. This change means the password_settings tests now pass. Signed-off-by: Tim Beale Reviewed-by: Andrew Bartlett Reviewed-by: Garming Sam --- selftest/knownfail.d/password_hash_gpgme | 2 - selftest/knownfail.d/password_settings | 6 --- .../dsdb/samdb/ldb_modules/password_hash.c | 52 ++++++++++++++++++- 3 files changed, 51 insertions(+), 9 deletions(-) delete mode 100644 selftest/knownfail.d/password_hash_gpgme diff --git a/selftest/knownfail.d/password_hash_gpgme b/selftest/knownfail.d/password_hash_gpgme deleted file mode 100644 index a382714e5a8..00000000000 --- a/selftest/knownfail.d/password_hash_gpgme +++ /dev/null @@ -1,2 +0,0 @@ -samba.tests.password_hash_gpgme.samba.tests.password_hash_gpgme.PassWordHashGpgmeTests.test_supplementalCredentials_cleartext_pso\(ad_dc:local\) - diff --git a/selftest/knownfail.d/password_settings b/selftest/knownfail.d/password_settings index a0cf46fda71..b23f3f9ef42 100644 --- a/selftest/knownfail.d/password_settings +++ b/selftest/knownfail.d/password_settings @@ -1,8 +1,2 @@ -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_basics\(ad_dc_ntvfs\) -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_equal_precedence\(ad_dc_ntvfs\) -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_nested_groups\(ad_dc_ntvfs\) -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_special_groups\(ad_dc_ntvfs\) -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_min_age\(ad_dc_ntvfs\) samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_max_age\(ad_dc_ntvfs\) -samba4.ldap.password_settings.python.password_settings.PasswordSettingsTestCase.test_pso_add_user\(ad_dc_ntvfs\) diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index ac97415ffff..56ecdaf81c0 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -3855,6 +3855,9 @@ static int get_pso_data_callback(struct ldb_request *req, { struct ldb_context *ldb = NULL; struct ph_context *ac = NULL; + bool domain_complexity = true; + bool pso_complexity = true; + struct dsdb_user_pwd_settings *settings = NULL; int ret = LDB_SUCCESS; ac = talloc_get_type(req->context, struct ph_context); @@ -3880,6 +3883,47 @@ static int get_pso_data_callback(struct ldb_request *req, goto done; } + /* + * use the PSO's values instead of the domain defaults (the PSO + * attributes should always exist, but use the domain default + * values as a fallback). + */ + settings = &ac->status->domain_data; + settings->store_cleartext = + ldb_msg_find_attr_as_bool(ares->message, + "msDS-PasswordReversibleEncryptionEnabled", + settings->store_cleartext); + + settings->pwdHistoryLength = + ldb_msg_find_attr_as_uint(ares->message, + "msDS-PasswordHistoryLength", + settings->pwdHistoryLength); + settings->maxPwdAge = + ldb_msg_find_attr_as_int64(ares->message, + "msDS-MaximumPasswordAge", + settings->maxPwdAge); + settings->minPwdAge = + ldb_msg_find_attr_as_int64(ares->message, + "msDS-MinimumPasswordAge", + settings->minPwdAge); + settings->minPwdLength = + ldb_msg_find_attr_as_uint(ares->message, + "msDS-MinimumPasswordLength", + settings->minPwdLength); + domain_complexity = + (settings->pwdProperties & DOMAIN_PASSWORD_COMPLEX); + pso_complexity = + ldb_msg_find_attr_as_bool(ares->message, + "msDS-PasswordComplexityEnabled", + domain_complexity); + + /* set or clear the complexity bit if required */ + if (pso_complexity && !domain_complexity) { + settings->pwdProperties |= DOMAIN_PASSWORD_COMPLEX; + } else if (domain_complexity && !pso_complexity) { + settings->pwdProperties &= ~DOMAIN_PASSWORD_COMPLEX; + } + if (ac->pso_res != NULL) { DBG_ERR("Too many PSO results for %s", ldb_dn_get_linearized(ac->search_res->message->dn)); @@ -3949,7 +3993,13 @@ static struct ldb_request * build_pso_data_request(struct ph_context *ac) /* attrs[] is returned from this function in pso_req->op.search.attrs, so it must be static, as otherwise the compiler can put it on the stack */ - static const char * const attrs[] = { "msDS-LockoutThreshold", + static const char * const attrs[] = { "msDS-PasswordComplexityEnabled", + "msDS-PasswordReversibleEncryptionEnabled", + "msDS-PasswordHistoryLength", + "msDS-MaximumPasswordAge", + "msDS-MinimumPasswordAge", + "msDS-MinimumPasswordLength", + "msDS-LockoutThreshold", "msDS-LockoutObservationWindow", NULL }; struct ldb_context *ldb = NULL; -- 2.34.1