The Samba-Bugzilla – Attachment 13903 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.25 KB, created by
David Mulder
on 2018-01-11 23:46:58 UTC
(
hide
)
Description:
patch that fixes the bad password attempts
Filename:
MIME Type:
Creator:
David Mulder
Created:
2018-01-11 23:46:58 UTC
Size:
9.25 KB
patch
obsolete
>From 778b58dd80e8fd0fe9f0487d219c0fde48b2a6dc 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 | 109 +++++++++++++++++++++++++++++++-- > source3/winbindd/winbindd_pam.c | 7 ++- > source3/winbindd/winbindd_proto.h | 3 +- > 6 files changed, 142 insertions(+), 7 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..0720cd65362 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 = atoll(values[0]); >+ 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..eb34c35aea7 100644 >--- a/source3/winbindd/winbindd_cred_cache.c >+++ b/source3/winbindd/winbindd_cred_cache.c >@@ -26,6 +26,9 @@ > #include "../libcli/auth/libcli_auth.h" > #include "smb_krb5.h" > #include "libads/kerberos_proto.h" >+#include "ads.h" >+#include "secrets.h" >+#include "flags.h" > > #undef DBGC_CLASS > #define DBGC_CLASS DBGC_WINBIND >@@ -100,6 +103,87 @@ 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; >+ LDAPMessage *res = NULL; >+ char *ldap_exp; >+ char *passwd = NULL; >+ uint64_t ret = 0; >+ const char *attr_list[] = { >+ "pwdLastSet", >+ NULL >+ }; >+ char *sam = NULL, *at_ptr; >+ >+ if ((at_ptr = strchr(entry->principal_name, '@')) != NULL) { >+ int strlen = at_ptr-entry->principal_name; >+ sam = talloc_zero_size(ctx, strlen+1); >+ strncpy(sam, entry->principal_name, strlen); >+ } else { >+ DEBUG(5,("Could not determine samAccountName from %s\n", >+ entry->principal_name)); >+ goto fail; >+ } >+ >+ if ((ldap_exp = talloc_asprintf(ctx, >+ "(samAccountName=%s)", >+ sam)) == NULL) { >+ goto fail; >+ } >+ >+ ads = ads_init(entry->realm, lp_workgroup(), >+ saf_fetch(ctx, entry->realm)); >+ if (ads == NULL) { >+ goto fail; >+ } >+ >+ ads->auth.user_name = talloc_asprintf(ctx, "%s$", lp_netbios_name()); >+ if (!ads->auth.user_name) { >+ goto fail; >+ } >+ >+ ads->auth.flags |= ADS_AUTH_USER_CREDS; >+ if (!secrets_init()) { >+ goto fail; >+ } >+ >+ passwd = secrets_fetch_machine_password(ads->server.workgroup, NULL, >+ NULL); >+ if (passwd == NULL) { >+ goto fail; >+ } >+ ads->auth.password = smb_xstrdup(passwd); >+ ads->auth.realm = smb_xstrdup(ads->server.realm); >+ if (!strupper_m(ads->auth.realm)) { >+ goto fail; >+ } >+ >+ status = ads_connect(ads); >+ if (!ADS_ERR_OK(status)) { >+ 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)) { >+ if (ads_count_replies(ads, res) != 1) { >+ goto fail; >+ } >+ if (!ads_pull_uint64(ads, res, "pwdLastSet", &ret)) { >+ goto fail; >+ } >+ } >+ >+fail: >+ SAFE_FREE(passwd); >+ TALLOC_FREE(ctx); >+ return ret; >+} >+ > /**************************************************************** > Do the work of refreshing the ticket. > ****************************************************************/ >@@ -128,9 +212,15 @@ static void krb5_ticket_refresh_handler(struct tevent_context *event_ctx, > /* Kinit again if we have the user password and we can't renew the old > * tgt anymore > * NB >- * This happens when machine are put to sleep for a very long time. */ >- >- if (entry->renew_until < time(NULL)) { >+ * This happens when machine are put to sleep for a very long time. >+ * >+ * 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 (entry->renew_until < time(NULL) && >+ fetch_last_password_change(entry) <= entry->last_password_change) { > rekinit: > if (cred_ptr && cred_ptr->pass) { > >@@ -331,6 +421,15 @@ static void krb5_ticket_gain_handler(struct tevent_context *event_ctx, > goto retry_later; > } > >+ /* 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) { >+ DEBUG(10,("krb5_ticket_gain_handler: old cached password\n")); >+ return; >+ } >+ > set_effective_uid(entry->uid); > > ret = kerberos_kinit_password_ext(entry->principal_name, >@@ -494,7 +593,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 +725,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..19efca272e6 100644 >--- a/source3/winbindd/winbindd_pam.c >+++ b/source3/winbindd/winbindd_pam.c >@@ -617,6 +617,7 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, > const char *local_service; > uint32_t i; > struct netr_SamInfo3 *info3_copy = NULL; >+ struct netr_SamBaseInfo *info_base = NULL; > > *info3 = NULL; > >@@ -749,6 +750,7 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, > if (!NT_STATUS_IS_OK(result)) { > goto failed; > } >+ info_base = &(info3_copy->base); > > /* if we had a user's ccache then return that string for the pam > * environment */ >@@ -767,7 +769,8 @@ static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx, > time(NULL), > ticket_lifetime, > renewal_until, >- false); >+ false, >+ info_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 +1106,7 @@ 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, 0); > > 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