From d07fd22984bea7b950c167b7c8f0745ce7739be6 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 5 Jan 2016 13:39:25 -0700 Subject: [PATCH 1/7] winbindd: Reset connection for expired session before reconnecting A RPC call on a expired SMB2 session returns IO_DEVICE_ERROR. In this case, reset the connection before issuing the same call again. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit fb5b0cec3c0c2e0cf9cb04f8b52ee910ac245aeb) --- source3/winbindd/winbindd_reconnect.c | 39 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c index e45f9b1..9442f34 100644 --- a/source3/winbindd/winbindd_reconnect.c +++ b/source3/winbindd/winbindd_reconnect.c @@ -27,7 +27,8 @@ extern struct winbindd_methods msrpc_methods; -static bool reconnect_need_retry(NTSTATUS status) +static bool reconnect_need_retry(NTSTATUS status, + struct winbindd_domain *domain) { if (NT_STATUS_IS_OK(status)) { return false; @@ -69,6 +70,14 @@ static bool reconnect_need_retry(NTSTATUS status) return false; } + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR)) { + /* + * RPC call sent on expired session, needs + * reauthentication. + */ + invalidate_cm_connection(domain); + } + return true; } @@ -83,7 +92,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain, result = msrpc_methods.query_user_list(domain, mem_ctx, num_entries, info); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.query_user_list(domain, mem_ctx, num_entries, info); return result; @@ -100,7 +109,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, result = msrpc_methods.enum_dom_groups(domain, mem_ctx, num_entries, info); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.enum_dom_groups(domain, mem_ctx, num_entries, info); return result; @@ -118,7 +127,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain, result = msrpc_methods.enum_local_groups(domain, mem_ctx, num_entries, info); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.enum_local_groups(domain, mem_ctx, num_entries, info); @@ -139,7 +148,7 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, result = msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name, flags, sid, type); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name, flags, sid, type); @@ -162,7 +171,7 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, result = msrpc_methods.sid_to_name(domain, mem_ctx, sid, domain_name, name, type); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.sid_to_name(domain, mem_ctx, sid, domain_name, name, type); @@ -183,7 +192,7 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, result = msrpc_methods.rids_to_names(domain, mem_ctx, sid, rids, num_rids, domain_name, names, types); - if (reconnect_need_retry(result)) { + if (reconnect_need_retry(result, domain)) { result = msrpc_methods.rids_to_names(domain, mem_ctx, sid, rids, num_rids, domain_name, names, @@ -204,7 +213,7 @@ static NTSTATUS query_user(struct winbindd_domain *domain, result = msrpc_methods.query_user(domain, mem_ctx, user_sid, user_info); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.query_user(domain, mem_ctx, user_sid, user_info); @@ -223,7 +232,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, user_sid, num_groups, user_gids); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.lookup_usergroups(domain, mem_ctx, user_sid, num_groups, user_gids); @@ -243,7 +252,7 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, num_aliases, alias_rids); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids, num_aliases, @@ -268,7 +277,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, sid_mem, names, name_types); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.lookup_groupmem(domain, mem_ctx, group_sid, type, num_names, @@ -285,7 +294,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq) result = msrpc_methods.sequence_number(domain, seq); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.sequence_number(domain, seq); return result; @@ -300,7 +309,7 @@ static NTSTATUS lockout_policy(struct winbindd_domain *domain, result = msrpc_methods.lockout_policy(domain, mem_ctx, policy); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.lockout_policy(domain, mem_ctx, policy); return result; @@ -315,7 +324,7 @@ static NTSTATUS password_policy(struct winbindd_domain *domain, result = msrpc_methods.password_policy(domain, mem_ctx, policy); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.password_policy(domain, mem_ctx, policy); return result; @@ -330,7 +339,7 @@ static NTSTATUS trusted_domains(struct winbindd_domain *domain, result = msrpc_methods.trusted_domains(domain, mem_ctx, trusts); - if (reconnect_need_retry(result)) + if (reconnect_need_retry(result, domain)) result = msrpc_methods.trusted_domains(domain, mem_ctx, trusts); -- 2.6.0.rc2.230.g3dd15c0 From 371e1b2a94fe23f3764c2b575333546236847c83 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 5 Jan 2016 14:37:30 -0700 Subject: [PATCH 2/7] winbindd: Add retry also for ADS method calls RPC calls can return IO_DEVICE_ERROR on expired SMB2 sessions. Retrying on a new connection avoids surfacing this error to winbindd clients. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit e4adf55e242aa5f000570bf554fcd15d7e86c126) --- source3/winbindd/winbindd_cache.c | 4 +- source3/winbindd/winbindd_ndr.c | 3 + source3/winbindd/winbindd_proto.h | 4 + source3/winbindd/winbindd_reconnect.c | 3 +- source3/winbindd/winbindd_reconnect_ads.c | 324 ++++++++++++++++++++++++++++++ source3/wscript_build | 1 + 6 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 source3/winbindd/winbindd_reconnect_ads.c diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 4e270ca..3562217 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -46,7 +46,7 @@ extern struct winbindd_methods reconnect_methods; #ifdef HAVE_ADS -extern struct winbindd_methods ads_methods; +extern struct winbindd_methods reconnect_ads_methods; #endif extern struct winbindd_methods builtin_passdb_methods; extern struct winbindd_methods sam_passdb_methods; @@ -168,7 +168,7 @@ static struct winbind_cache *get_cache(struct winbindd_domain *domain) && domain->active_directory && !lp_winbind_rpc_only()) { DEBUG(5,("get_cache: Setting ADS methods for domain %s\n", domain->name)); - domain->backend = &ads_methods; + domain->backend = &reconnect_ads_methods; } else { #endif /* HAVE_ADS */ DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n", domain->name)); diff --git a/source3/winbindd/winbindd_ndr.c b/source3/winbindd/winbindd_ndr.c index 37b7e02..029e883 100644 --- a/source3/winbindd/winbindd_ndr.c +++ b/source3/winbindd/winbindd_ndr.c @@ -75,6 +75,7 @@ void ndr_print_winbindd_cm_conn(struct ndr_print *ndr, #ifdef HAVE_ADS extern struct winbindd_methods ads_methods; +extern struct winbindd_methods reconnect_ads_methods; #endif extern struct winbindd_methods msrpc_methods; extern struct winbindd_methods builtin_passdb_methods; @@ -100,6 +101,8 @@ void ndr_print_winbindd_methods(struct ndr_print *ndr, #ifdef HAVE_ADS } else if (r == &ads_methods) { ndr_print_string(ndr, name, "ads_methods"); + } else if (r == &reconnect_ads_methods) { + ndr_print_string(ndr, name, "reconnect_ads_methods"); #endif } else if (r == &builtin_passdb_methods) { ndr_print_string(ndr, name, "builtin_passdb_methods"); diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 9920a3f..6e50718 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -933,4 +933,8 @@ ADS_STATUS ads_idmap_cached_connection(ADS_STRUCT **adsp, const char *dom_name); /* The following definitions come from winbindd/winbindd_irpc.c */ NTSTATUS wb_irpc_register(void); + +/* The following definitions come from winbindd/winbindd_reconnect.c */ +bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain); + #endif /* _WINBINDD_PROTO_H_ */ diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c index 9442f34..f7dd805 100644 --- a/source3/winbindd/winbindd_reconnect.c +++ b/source3/winbindd/winbindd_reconnect.c @@ -27,8 +27,7 @@ extern struct winbindd_methods msrpc_methods; -static bool reconnect_need_retry(NTSTATUS status, - struct winbindd_domain *domain) +bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain) { if (NT_STATUS_IS_OK(status)) { return false; diff --git a/source3/winbindd/winbindd_reconnect_ads.c b/source3/winbindd/winbindd_reconnect_ads.c new file mode 100644 index 0000000..7ea8298 --- /dev/null +++ b/source3/winbindd/winbindd_reconnect_ads.c @@ -0,0 +1,324 @@ +/* + Unix SMB/CIFS implementation. + + Wrapper around winbindd_ads.c to centralize retry logic. + Copyright (C) Christof Schmitt 2016 + + Based on winbindd_reconnect.c + Copyright (C) Volker Lendecke 2005 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "winbindd.h" + +#ifdef HAVE_ADS + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +extern struct winbindd_methods ads_methods; + +/* List all users */ +static NTSTATUS query_user_list(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32_t *num_entries, + struct wbint_userinfo **info) +{ + NTSTATUS result; + + result = ads_methods.query_user_list(domain, mem_ctx, + num_entries, info); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.query_user_list(domain, mem_ctx, + num_entries, info); + } + + return result; +} + +/* list all domain groups */ +static NTSTATUS enum_dom_groups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32_t *num_entries, + struct wb_acct_info **info) +{ + NTSTATUS result; + + result = ads_methods.enum_dom_groups(domain, mem_ctx, + num_entries, info); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.enum_dom_groups(domain, mem_ctx, + num_entries, info); + } + + return result; +} + +/* List all domain groups */ +static NTSTATUS enum_local_groups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32_t *num_entries, + struct wb_acct_info **info) +{ + NTSTATUS result; + + result = ads_methods.enum_local_groups(domain, mem_ctx, + num_entries, info); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.enum_local_groups(domain, mem_ctx, + num_entries, info); + } + + return result; +} + +/* convert a single name to a sid in a domain */ +static NTSTATUS name_to_sid(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *domain_name, + const char *name, + uint32_t flags, + struct dom_sid *sid, + enum lsa_SidType *type) +{ + NTSTATUS result; + + result = ads_methods.name_to_sid(domain, mem_ctx, domain_name, name, + flags, sid, type); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.name_to_sid(domain, mem_ctx, + domain_name, name, flags, + sid, type); + } + + return result; +} + +/* + convert a domain SID to a user or group name +*/ +static NTSTATUS sid_to_name(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *sid, + char **domain_name, + char **name, + enum lsa_SidType *type) +{ + NTSTATUS result; + + result = ads_methods.sid_to_name(domain, mem_ctx, sid, + domain_name, name, type); + + if (reconnect_need_retry(result, domain)) + result = ads_methods.sid_to_name(domain, mem_ctx, sid, + domain_name, name, type); + + return result; +} + +static NTSTATUS rids_to_names(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *sid, + uint32_t *rids, + size_t num_rids, + char **domain_name, + char ***names, + enum lsa_SidType **types) +{ + NTSTATUS result; + + result = ads_methods.rids_to_names(domain, mem_ctx, sid, + rids, num_rids, + domain_name, names, types); + if (reconnect_need_retry(result, domain)) { + result = ads_methods.rids_to_names(domain, mem_ctx, sid, + rids, num_rids, domain_name, + names, types); + } + + return result; +} + +/* Lookup user information from a rid or username. */ +static NTSTATUS query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + struct wbint_userinfo *user_info) +{ + NTSTATUS result; + + result = ads_methods.query_user(domain, mem_ctx, user_sid, user_info); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.query_user(domain, mem_ctx, user_sid, + user_info); + } + + return result; +} + +/* Lookup groups a user is a member of. I wish Unix had a call like this! */ +static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + uint32_t *num_groups, + struct dom_sid **user_gids) +{ + NTSTATUS result; + + result = ads_methods.lookup_usergroups(domain, mem_ctx, user_sid, + num_groups, user_gids); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.lookup_usergroups(domain, mem_ctx, + user_sid, num_groups, + user_gids); + } + + return result; +} + +static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + uint32_t num_sids, + const struct dom_sid *sids, + uint32_t *num_aliases, uint32_t **alias_rids) +{ + NTSTATUS result; + + result = ads_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids, + num_aliases, alias_rids); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.lookup_useraliases(domain, mem_ctx, + num_sids, sids, + num_aliases, + alias_rids); + } + + return result; +} + +/* Lookup group membership given a rid. */ +static NTSTATUS lookup_groupmem(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const struct dom_sid *group_sid, + enum lsa_SidType type, + uint32_t *num_names, + struct dom_sid **sid_mem, char ***names, + uint32_t **name_types) +{ + NTSTATUS result; + + result = ads_methods.lookup_groupmem(domain, mem_ctx, group_sid, type, + num_names, sid_mem, names, + name_types); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.lookup_groupmem(domain, mem_ctx, group_sid, + type, num_names, sid_mem, + names, name_types); + } + + return result; +} + +/* find the sequence number for a domain */ +static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq) +{ + NTSTATUS result; + + result = ads_methods.sequence_number(domain, seq); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.sequence_number(domain, seq); + } + + return result; +} + +/* find the lockout policy of a domain */ +static NTSTATUS lockout_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo12 *policy) +{ + NTSTATUS result; + + result = ads_methods.lockout_policy(domain, mem_ctx, policy); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.lockout_policy(domain, mem_ctx, policy); + } + + return result; +} + +/* find the password policy of a domain */ +static NTSTATUS password_policy(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct samr_DomInfo1 *policy) +{ + NTSTATUS result; + + result = ads_methods.password_policy(domain, mem_ctx, policy); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.password_policy(domain, mem_ctx, policy); + } + + return result; +} + +/* get a list of trusted domains */ +static NTSTATUS trusted_domains(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + struct netr_DomainTrustList *trusts) +{ + NTSTATUS result; + + result = ads_methods.trusted_domains(domain, mem_ctx, trusts); + + if (reconnect_need_retry(result, domain)) { + result = ads_methods.trusted_domains(domain, mem_ctx, trusts); + } + + return result; +} + +/* the rpc backend methods are exposed via this structure */ +struct winbindd_methods reconnect_ads_methods = { + true, + query_user_list, + enum_dom_groups, + enum_local_groups, + name_to_sid, + sid_to_name, + rids_to_names, + query_user, + lookup_usergroups, + lookup_useraliases, + lookup_groupmem, + sequence_number, + lockout_policy, + password_policy, + trusted_domains, +}; + +#endif diff --git a/source3/wscript_build b/source3/wscript_build index ace4b99..c0296c0 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -908,6 +908,7 @@ bld.SAMBA3_BINARY('winbindd/winbindd', winbindd/winbindd_msrpc.c winbindd/winbindd_rpc.c winbindd/winbindd_reconnect.c + winbindd/winbindd_reconnect_ads.c winbindd/winbindd_ads.c winbindd/winbindd_samr.c winbindd/winbindd_dual.c -- 2.6.0.rc2.230.g3dd15c0 From ae111619ebbbf65af47fe50240eea968ecd51073 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 5 Jan 2016 14:42:09 -0700 Subject: [PATCH 3/7] winbindd: Remove double retry from some ADS methods The retry through the new reconnect_ads layer is enough. This structure also makes the distinction between retry layer and actual methods call a bit clearer. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit 4c6804e414087fb61e66133cefbe5590d1d9b283) --- source3/winbindd/winbindd_ads.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index 78350fd..791b05f 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -38,6 +38,7 @@ #define DBGC_CLASS DBGC_WINBIND extern struct winbindd_methods reconnect_methods; +extern struct winbindd_methods msrpc_methods; #define WINBIND_CCACHE_NAME "MEMORY:winbind_ccache" @@ -563,9 +564,8 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, struct dom_sid *sid, enum lsa_SidType *type) { - return reconnect_methods.name_to_sid(domain, mem_ctx, - domain_name, name, flags, - sid, type); + return msrpc_methods.name_to_sid(domain, mem_ctx, domain_name, name, + flags, sid, type); } /* convert a domain SID to a user or group name - use rpc methods */ @@ -576,8 +576,8 @@ static NTSTATUS sid_to_name(struct winbindd_domain *domain, char **name, enum lsa_SidType *type) { - return reconnect_methods.sid_to_name(domain, mem_ctx, sid, - domain_name, name, type); + return msrpc_methods.sid_to_name(domain, mem_ctx, sid, + domain_name, name, type); } /* convert a list of rids to names - use rpc methods */ @@ -590,9 +590,9 @@ static NTSTATUS rids_to_names(struct winbindd_domain *domain, char ***names, enum lsa_SidType **types) { - return reconnect_methods.rids_to_names(domain, mem_ctx, sid, - rids, num_rids, - domain_name, names, types); + return msrpc_methods.rids_to_names(domain, mem_ctx, sid, + rids, num_rids, + domain_name, names, types); } /* If you are looking for "dn_lookup": Yes, it used to be here! @@ -1142,10 +1142,8 @@ static NTSTATUS lookup_useraliases(struct winbindd_domain *domain, uint32_t num_sids, const struct dom_sid *sids, uint32_t *num_aliases, uint32_t **alias_rids) { - return reconnect_methods.lookup_useraliases(domain, mem_ctx, - num_sids, sids, - num_aliases, - alias_rids); + return msrpc_methods.lookup_useraliases(domain, mem_ctx, num_sids, sids, + num_aliases, alias_rids); } static NTSTATUS add_primary_group_members( @@ -1527,7 +1525,7 @@ static NTSTATUS lockout_policy(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct samr_DomInfo12 *policy) { - return reconnect_methods.lockout_policy(domain, mem_ctx, policy); + return msrpc_methods.lockout_policy(domain, mem_ctx, policy); } /* find the password policy of a domain - use rpc methods */ @@ -1535,7 +1533,7 @@ static NTSTATUS password_policy(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, struct samr_DomInfo1 *policy) { - return reconnect_methods.password_policy(domain, mem_ctx, policy); + return msrpc_methods.password_policy(domain, mem_ctx, policy); } /* get a list of trusted domains */ -- 2.6.0.rc2.230.g3dd15c0 From 22f34cfa3b50d1dcf63cbfb26e6a0d40f6fab448 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Wed, 6 Jan 2016 14:15:30 -0700 Subject: [PATCH 4/7] winbindd: Retry on expired session in cm_connect_lsa BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit 3b6b5456424be6997b32c23b7c149c8060c3102d) --- source3/winbindd/winbindd_cm.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 842307f..9f4fdbf 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -2960,7 +2960,9 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, NTSTATUS result = NT_STATUS_UNSUCCESSFUL; struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; + bool retry = false; /* allow one retry attempt for expired session */ +retry: result = init_dc_connection_rpc(domain, false); if (!NT_STATUS_IS_OK(result)) return result; @@ -2995,6 +2997,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, smbXcli_conn_remote_name(conn->cli->conn), creds, &conn->lsa_pipe); + + if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(result)) { DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for " "domain %s using NTLMSSP authenticated pipe: user " @@ -3012,6 +3022,13 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True, SEC_FLAG_MAXIMUM_ALLOWED, &conn->lsa_policy); + if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->lsa_pipe); + retry = true; + goto retry; + } + if (NT_STATUS_IS_OK(result)) { goto done; } @@ -3047,6 +3064,13 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, (conn->cli, &ndr_table_lsarpc, NCACN_NP, creds, p_creds, &conn->lsa_pipe); + if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(result)) { DEBUG(10,("cm_connect_lsa: failed to connect to LSA pipe for " "domain %s using schannel. Error was %s\n", @@ -3059,6 +3083,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True, SEC_FLAG_MAXIMUM_ALLOWED, &conn->lsa_policy); + + if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->lsa_pipe); + retry = true; + goto retry; + } + if (NT_STATUS_IS_OK(result)) { goto done; } @@ -3083,6 +3115,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, result = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_lsarpc, &conn->lsa_pipe); + + if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(result)) { goto done; } @@ -3090,6 +3130,14 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, result = rpccli_lsa_open_policy(conn->lsa_pipe, mem_ctx, True, SEC_FLAG_MAXIMUM_ALLOWED, &conn->lsa_policy); + + if (NT_STATUS_EQUAL(result, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->lsa_pipe); + retry = true; + goto retry; + } + done: if (!NT_STATUS_IS_OK(result)) { invalidate_cm_connection(domain); -- 2.6.0.rc2.230.g3dd15c0 From 6765d7c31fd7a29113668e69cc5d4c05d278e8dc Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 7 Jan 2016 15:03:22 -0700 Subject: [PATCH 5/7] winbindd: Retry on expired session in cm_connect_sam BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit 276d604aa5ccc32d18b69c04ae13e2dc7c21f3ee) --- source3/winbindd/winbindd_cm.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 9f4fdbf..80ea582 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -2683,6 +2683,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, NTSTATUS status, result; struct netlogon_creds_cli_context *p_creds; struct cli_credentials *creds = NULL; + bool retry = false; /* allow one retry attempt for expired session */ if (sid_check_is_our_sam(&domain->sid)) { if (domain->rodc == false || need_rw_dc == false) { @@ -2690,6 +2691,7 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, } } +retry: status = init_dc_connection_rpc(domain, need_rw_dc); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2733,6 +2735,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, smbXcli_conn_remote_name(conn->cli->conn), creds, &conn->samr_pipe); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cm_connect_sam: failed to connect to SAMR " "pipe for domain %s using NTLMSSP " @@ -2753,6 +2763,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, SEC_FLAG_MAXIMUM_ALLOWED, &conn->sam_connect_handle, &result); + + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->samr_pipe); + retry = true; + goto retry; + } + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) { goto open_domain; } @@ -2790,6 +2808,13 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, (conn->cli, &ndr_table_samr, NCACN_NP, creds, p_creds, &conn->samr_pipe); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cm_connect_sam: failed to connect to SAMR pipe for " "domain %s using schannel. Error was %s\n", @@ -2804,6 +2829,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, SEC_FLAG_MAXIMUM_ALLOWED, &conn->sam_connect_handle, &result); + + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->samr_pipe); + retry = true; + goto retry; + } + if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) { goto open_domain; } @@ -2830,6 +2863,13 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, status = cli_rpc_pipe_open_noauth(conn->cli, &ndr_table_samr, &conn->samr_pipe); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED) + && !retry) { + invalidate_cm_connection(domain); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(status)) { goto done; } @@ -2839,6 +2879,14 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, SEC_FLAG_MAXIMUM_ALLOWED, &conn->sam_connect_handle, &result); + + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) { + invalidate_cm_connection(domain); + TALLOC_FREE(conn->samr_pipe); + retry = true; + goto retry; + } + if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("cm_connect_sam: rpccli_samr_Connect2 failed " "for domain %s Error was %s\n", -- 2.6.0.rc2.230.g3dd15c0 From 6e4453779feb7664bca0e46c42fbc0ccd5c5404c Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Tue, 5 Jan 2016 15:10:45 -0700 Subject: [PATCH 6/7] winbindd: Retry on expired session in cm_connect_netlogon BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison (cherry picked from commit aa3883eae6e7891efb1e6f9ec74e6073bee43250) --- source3/winbindd/winbindd_cm.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 80ea582..1964fcff 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -3408,6 +3408,14 @@ NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain, } status = cm_connect_netlogon_transport(domain, NCACN_NP, cli); + if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { + /* + * SMB2 session expired, needs reauthentication. Drop + * connection and retry. + */ + invalidate_cm_connection(domain); + status = cm_connect_netlogon_transport(domain, NCACN_NP, cli); + } return status; } -- 2.6.0.rc2.230.g3dd15c0 From a42311f63960046fa85df7acde3dc1373e997857 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 7 Jan 2016 13:27:49 -0700 Subject: [PATCH 7/7] Revert "winbind: Retry after SESSION_EXPIRED error in ping-dc" This reverts commit a2670f15dea27c10e3827216adf572f9c3894f85. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11670 cm_connect_netlogon now handles the retry for an expired session. Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Wed Jan 13 03:35:57 CET 2016 on sn-devel-144 (cherry picked from commit 6f3656c47d8ae6a3ac10591ffd7a60797775b469) --- source3/winbindd/winbindd_dual_srv.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 44e4842..cdd9bbd 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -741,14 +741,6 @@ NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r) reconnect: status = cm_connect_netlogon(domain, &netlogon_pipe); - if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { - /* - * Retry to open new connection with new kerberos ticket. - */ - invalidate_cm_connection(domain); - status = cm_connect_netlogon(domain, &netlogon_pipe); - } - reset_cm_connection_on_error(domain, status); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n", -- 2.6.0.rc2.230.g3dd15c0