diff options
author | Andrew Bartlett <abartlet@samba.org> | 2013-11-06 10:39:42 +1300 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2014-04-02 17:12:46 +0200 |
commit | 3f07737fd4a92fc948cfc432bc46098d6dd5269a (patch) | |
tree | 9fb99bf3cad568fe51ad3d6cbeeba83718462223 /source4/auth | |
parent | a0de9290099a93413048a03740cfb04ca1355c78 (diff) | |
download | samba-3f07737fd4a92fc948cfc432bc46098d6dd5269a.tar.gz samba-3f07737fd4a92fc948cfc432bc46098d6dd5269a.tar.xz samba-3f07737fd4a92fc948cfc432bc46098d6dd5269a.zip |
s4:auth: Add password lockout support to the AD DC
Including a fix by Arvid Requate <requate@univention.de>
Change-Id: I25d10da50dd6119801cd37349cce970599531c6b
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Diffstat (limited to 'source4/auth')
-rw-r--r-- | source4/auth/ntlm/auth_sam.c | 7 | ||||
-rw-r--r-- | source4/auth/sam.c | 117 |
2 files changed, 124 insertions, 0 deletions
diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c index d07f9301fb4..8f7f5448e84 100644 --- a/source4/auth/ntlm/auth_sam.c +++ b/source4/auth/ntlm/auth_sam.c @@ -213,6 +213,13 @@ static NTSTATUS authsam_authenticate(struct auth4_context *auth_context, nt_status = authsam_password_ok(auth_context, mem_ctx, acct_flags, lm_pwd, nt_pwd, user_info, user_sess_key, lm_sess_key); + if (NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD)) { + NTSTATUS update_bad_pwd_count_status = authsam_update_bad_pwd_count(auth_context->sam_ctx, msg, domain_dn); + if (!NT_STATUS_IS_OK(update_bad_pwd_count_status)) { + /* bo! (what can we do here? */ + } + } + NT_STATUS_NOT_OK_RETURN(nt_status); nt_status = authsam_account_ok(mem_ctx, auth_context->sam_ctx, diff --git a/source4/auth/sam.c b/source4/auth/sam.c index 1c3b81ad0c6..789ff19d15c 100644 --- a/source4/auth/sam.c +++ b/source4/auth/sam.c @@ -83,6 +83,7 @@ const char *user_attrs[] = { "logonCount", "primaryGroupID", "memberOf", + "badPasswordTime", NULL, }; @@ -634,3 +635,119 @@ NTSTATUS authsam_get_user_info_dc_principal(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } + +NTSTATUS authsam_update_bad_pwd_count(struct ldb_context *sam_ctx, + struct ldb_message *msg, + struct ldb_dn *domain_dn) +{ + const char *attrs[] = { "lockoutThreshold", + "lockOutObservationWindow", + "lockoutDuration", + "pwdProperties", + NULL }; + int ret, badPwdCount; + int64_t lockoutThreshold, lockOutObservationWindow, badPasswordTime; + struct dom_sid *sid; + struct ldb_result *domain_res; + struct ldb_message *msg_mod; + struct timeval tv_now = timeval_current(); + NTTIME now = timeval_to_nttime(&tv_now); + NTSTATUS status; + uint32_t pwdProperties, rid = 0; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_new(msg); + if (mem_ctx == NULL) { + return NT_STATUS_NO_MEMORY; + } + + sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid"); + + ret = dsdb_search_dn(sam_ctx, mem_ctx, &domain_res, domain_dn, attrs, 0); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(mem_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + pwdProperties = ldb_msg_find_attr_as_uint(domain_res->msgs[0], + "pwdProperties", -1); + if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) { + status = dom_sid_split_rid(NULL, sid, NULL, &rid); + if (!NT_STATUS_IS_OK(status)) { + /* + * This can't happen anyway, but always try + * and update the badPwdCount on failure + */ + rid = 0; + } + } + + /* + * Work out if we are doing password lockout on the domain. + * Also, the built in administrator account is exempt: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx + */ + lockoutThreshold = ldb_msg_find_attr_as_int(domain_res->msgs[0], + "lockoutThreshold", 0); + if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) { + DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n", + ldb_dn_get_linearized(msg->dn))); + TALLOC_FREE(mem_ctx); + return NT_STATUS_OK; + } + + lockOutObservationWindow = ldb_msg_find_attr_as_int64(domain_res->msgs[0], + "lockOutObservationWindow", 0); + + badPasswordTime = ldb_msg_find_attr_as_int64(msg, "badPasswordTime", 0); + + msg_mod = ldb_msg_new(mem_ctx); + if (msg_mod == NULL) { + TALLOC_FREE(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + msg_mod->dn = msg->dn; + + if (badPasswordTime - lockOutObservationWindow >= now) { + badPwdCount = ldb_msg_find_attr_as_int(msg, "badPwdCount", 0); + } else { + badPwdCount = 0; + } + + badPwdCount++; + + ret = samdb_msg_add_int(sam_ctx, msg_mod, msg_mod, "badPwdCount", badPwdCount); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod, "badPasswordTime", now); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + if (badPwdCount >= lockoutThreshold) { + ret = samdb_msg_add_int64(sam_ctx, msg_mod, msg_mod, "lockoutTime", now); + if (ret != LDB_SUCCESS) { + TALLOC_FREE(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + DEBUG(5, ("Locked out user %s after %d wrong passwords\n", + ldb_dn_get_linearized(msg->dn), badPwdCount)); + } + + ret = dsdb_replace(sam_ctx, msg_mod, 0); + if (ret != LDB_SUCCESS) { + DEBUG(0, ("Failed to upate badPwdCount, badPasswordTime or set lockoutTime on %s: %s\n", + ldb_dn_get_linearized(msg_mod->dn), ldb_errstring(sam_ctx))); + TALLOC_FREE(mem_ctx); + return NT_STATUS_INTERNAL_ERROR; + } + + DEBUG(5, ("Updated badPwdCount on %s after %d wrong passwords\n", + ldb_dn_get_linearized(msg->dn), badPwdCount)); + + TALLOC_FREE(mem_ctx); + return NT_STATUS_OK; +} |