The Samba-Bugzilla – Attachment 13904 Details for
Bug 13212
Active Directory account randomly locked when using 'winbind refresh tickets'
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
patch that fixes the bad password attempts
0001-winbind-account-locked-when-using-winbind-refresh-ti.patch (text/plain), 9.61 KB, created by
David Mulder
on 2018-01-12 21:00:48 UTC
(
hide
)
Description:
patch that fixes the bad password attempts
Filename:
MIME Type:
Creator:
David Mulder
Created:
2018-01-12 21:00:48 UTC
Size:
9.61 KB
patch
obsolete
>From dc61485ce3c08c9efa94ac74bc5b08af439f20d3 Mon Sep 17 00:00:00 2001 >From: David Mulder <dmulder@suse.com> >Date: Wed, 10 Jan 2018 10:00:27 -0700 >Subject: [PATCH] winbind: account locked when using winbind refresh tickets > >Users were being locked out by machines they >hadn't recently authenticated to. The source of >the problem is in krb5_ticket_refresh_handler(), >when users are password kinit'd after a long >period of being offline using invalid passwords. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=13212 > >Signed-off-by: David Mulder <dmulder@suse.com> >--- > source3/libads/ads_ldap_protos.h | 2 + > source3/libads/ldap.c | 27 ++++++++ > source3/winbindd/winbindd.h | 1 + > source3/winbindd/winbindd_cred_cache.c | 119 ++++++++++++++++++++++++++++----- > source3/winbindd/winbindd_pam.c | 6 +- > source3/winbindd/winbindd_proto.h | 3 +- > 6 files changed, 138 insertions(+), 20 deletions(-) > >diff --git a/source3/libads/ads_ldap_protos.h b/source3/libads/ads_ldap_protos.h >index b063815678a..e1ad7f30666 100644 >--- a/source3/libads/ads_ldap_protos.h >+++ b/source3/libads/ads_ldap_protos.h >@@ -52,6 +52,8 @@ char **ads_pull_strings_range(ADS_STRUCT *ads, > bool *more_strings); > bool ads_pull_uint32(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, > uint32_t *v); >+bool ads_pull_uint64(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, >+ uint64_t *v); > bool ads_pull_guid(ADS_STRUCT *ads, LDAPMessage *msg, struct GUID *guid); > bool ads_pull_sid(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, > struct dom_sid *sid); >diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c >index c18837cc524..edcb602b273 100644 >--- a/source3/libads/ldap.c >+++ b/source3/libads/ldap.c >@@ -2743,6 +2743,33 @@ int ads_count_replies(ADS_STRUCT *ads, void *res) > } > > /** >+ * pull a single uint64_t from a ADS result >+ * @param ads connection to ads server >+ * @param msg Results of search >+ * @param field Attribute to retrieve >+ * @param v Pointer to int to store result >+ * @return boolean inidicating success >+*/ >+bool ads_pull_uint64(ADS_STRUCT *ads, LDAPMessage *msg, const char *field, >+ uint64_t *v) >+{ >+ char **values; >+ >+ values = ldap_get_values(ads->ldap.ld, msg, field); >+ if (!values) { >+ return False; >+ } >+ if (!values[0]) { >+ ldap_value_free(values); >+ return False; >+ } >+ >+ *v = strtoull(values[0], NULL, 10); >+ ldap_value_free(values); >+ return True; >+} >+ >+/** > * pull a single objectGUID from an ADS result > * @param ads connection to ADS server > * @param msg results of search >diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h >index 396f7f7946e..10057757b0f 100644 >--- a/source3/winbindd/winbindd.h >+++ b/source3/winbindd/winbindd.h >@@ -347,6 +347,7 @@ struct WINBINDD_CCACHE_ENTRY { > time_t renew_until; > time_t refresh_time; > struct tevent_timer *event; >+ NTTIME last_password_change; > }; > > #include "winbindd/winbindd_proto.h" >diff --git a/source3/winbindd/winbindd_cred_cache.c b/source3/winbindd/winbindd_cred_cache.c >index 5e019dfce0c..b2273858b7f 100644 >--- a/source3/winbindd/winbindd_cred_cache.c >+++ b/source3/winbindd/winbindd_cred_cache.c >@@ -26,6 +26,7 @@ > #include "../libcli/auth/libcli_auth.h" > #include "smb_krb5.h" > #include "libads/kerberos_proto.h" >+#include "winbindd_ads.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_WINBIND >@@ -100,6 +101,61 @@ void ccache_remove_all_after_fork(void) > return; > } > >+static uint64_t fetch_last_password_change(struct WINBINDD_CCACHE_ENTRY *entry) >+{ >+ TALLOC_CTX *ctx = talloc_new(entry); >+ ADS_STATUS status; >+ ADS_STRUCT *ads = NULL; >+ LDAPMessage *res = NULL; >+ char *ldap_exp; >+ uint64_t ret = 0; >+ const char *attr_list[] = { >+ "pwdLastSet", >+ NULL >+ }; >+ char *sam = NULL, *at_ptr; >+ >+ at_ptr = strchr(entry->principal_name, '@'); >+ if (at_ptr != NULL) { >+ int strlen = at_ptr - entry->principal_name; >+ sam = talloc_strndup(ctx, entry->principal_name, strlen); >+ } else { >+ DBG_DEBUG("Could not determine samAccountName from %s\n", >+ entry->principal_name); >+ goto fail; >+ } >+ >+ ldap_exp = talloc_asprintf(ctx, "(samAccountName=%s)", sam); >+ if (ldap_exp == NULL) { >+ goto fail; >+ } >+ >+ status = ads_idmap_cached_connection(&ads, entry->realm); >+ if (!ADS_ERR_OK(status)) { >+ DBG_DEBUG("Failed to fetch ads cached connection\n"); >+ goto fail; >+ } >+ >+ status = ads_do_search_all(ads, ads->config.bind_path, >+ LDAP_SCOPE_SUBTREE, ldap_exp, >+ attr_list, &res); >+ if (ADS_ERR_OK(status)) { >+ int count = ads_count_replies(ads, res); >+ if (count != 1) { >+ DBG_DEBUG("Number of fetched responses for search with" >+ " filter \"%s\" was %d\n", ldap_exp, count); >+ goto fail; >+ } >+ if (!ads_pull_uint64(ads, res, "pwdLastSet", &ret)) { >+ goto fail; >+ } >+ } >+ >+fail: >+ TALLOC_FREE(ctx); >+ return ret; >+} >+ > /**************************************************************** > Do the work of refreshing the ticket. > ****************************************************************/ >@@ -134,19 +190,34 @@ static void krb5_ticket_refresh_handler(struct tevent_context *event_ctx, > rekinit: > if (cred_ptr && cred_ptr->pass) { > >- set_effective_uid(entry->uid); >- >- ret = kerberos_kinit_password_ext(entry->principal_name, >- cred_ptr->pass, >- 0, /* hm, can we do time correction here ? */ >- &entry->refresh_time, >- &entry->renew_until, >- entry->ccname, >- False, /* no PAC required anymore */ >- True, >- WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, >- NULL); >- gain_root_privilege(); >+ /* Using cached passwords to kinit can lockout a user >+ * account if their password has changed. Check the >+ * user pwdLastSet attribute and ignore the kinit if it >+ * has changed. >+ */ >+ if (fetch_last_password_change(entry) >+ <= entry->last_password_change) { >+ set_effective_uid(entry->uid); >+ >+ ret = kerberos_kinit_password_ext( >+ entry->principal_name, >+ cred_ptr->pass, >+ 0, /* can we do time correction here? */ >+ &entry->refresh_time, >+ &entry->renew_until, >+ entry->ccname, >+ False, /* no PAC required anymore */ >+ True, >+ WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, >+ NULL); >+ >+ gain_root_privilege(); >+ } else { >+ ret = KRB5KDC_ERR_PREAUTH_FAILED; >+ DBG_NOTICE("Skipping re-kinit for %s" >+ " due to cached invalid password\n", >+ entry->principal_name); >+ } > > if (ret) { > DEBUG(3,("krb5_ticket_refresh_handler: " >@@ -331,9 +402,14 @@ static void krb5_ticket_gain_handler(struct tevent_context *event_ctx, > goto retry_later; > } > >- set_effective_uid(entry->uid); >+ /* Using cached passwords to kinit can lockout a user account if their >+ * password has changed. Check the user pwdLastSet attribute and ignore >+ * the kinit if it has changed. >+ */ >+ if (fetch_last_password_change(entry) <= entry->last_password_change) { >+ set_effective_uid(entry->uid); > >- ret = kerberos_kinit_password_ext(entry->principal_name, >+ ret = kerberos_kinit_password_ext(entry->principal_name, > cred_ptr->pass, > 0, /* hm, can we do time correction here ? */ > &entry->refresh_time, >@@ -343,7 +419,14 @@ static void krb5_ticket_gain_handler(struct tevent_context *event_ctx, > True, > WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, > NULL); >- gain_root_privilege(); >+ >+ gain_root_privilege(); >+ } else { >+ ret = KRB5KDC_ERR_PREAUTH_FAILED; >+ DBG_NOTICE("Skipping kinit for %s" >+ " due to cached invalid password\n", >+ entry->principal_name); >+ } > > if (ret) { > DEBUG(3,("krb5_ticket_gain_handler: " >@@ -494,7 +577,8 @@ NTSTATUS add_ccache_to_list(const char *princ_name, > time_t create_time, > time_t ticket_end, > time_t renew_until, >- bool postponed_request) >+ bool postponed_request, >+ NTTIME last_password_change) > { > struct WINBINDD_CCACHE_ENTRY *entry = NULL; > struct timeval t; >@@ -625,6 +709,7 @@ NTSTATUS add_ccache_to_list(const char *princ_name, > entry->renew_until = renew_until; > entry->uid = uid; > entry->ref_count = 1; >+ entry->last_password_change = last_password_change; > > if (!lp_winbind_refresh_tickets() || renew_until <= 0) { > goto add_entry; >diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c >index abd208a515f..fb836962387 100644 >--- a/source3/winbindd/winbindd_pam.c >+++ b/source3/winbindd/winbindd_pam.c >@@ -767,7 +767,8 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, > time(NULL), > ticket_lifetime, > renewal_until, >- false); >+ false, >+ info3_copy->base.last_password_change); > > if (!NT_STATUS_IS_OK(result)) { > DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n", >@@ -1103,7 +1104,8 @@ static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain, > time(NULL), > time(NULL) + lp_winbind_cache_time(), > time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, >- true); >+ true, >+ my_info3->base.last_password_change); > > if (!NT_STATUS_IS_OK(result)) { > DEBUG(10,("winbindd_dual_pam_auth_cached: failed " >diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h >index cf01337aaad..b3bd1b6deee 100644 >--- a/source3/winbindd/winbindd_proto.h >+++ b/source3/winbindd/winbindd_proto.h >@@ -232,7 +232,8 @@ NTSTATUS add_ccache_to_list(const char *princ_name, > time_t create_time, > time_t ticket_end, > time_t renew_until, >- bool postponed_request); >+ bool postponed_request, >+ NTTIME last_password_change); > NTSTATUS remove_ccache(const char *username); > struct WINBINDD_MEMORY_CREDS *find_memory_creds_by_name(const char *username); > NTSTATUS winbindd_add_memory_creds(const char *username, >-- >2.13.6 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 13212
:
13903
|
13904
|
14715