[PATCHES] Handle expired sessions in winbindd
Christof Schmitt
cs at samba.org
Thu Jan 7 23:11:37 UTC 2016
A SMB session from winbind to the DC can expire any time, when trying to
connect to a pipe or when issuing a RPC call. Depending on which
codepath receives the corresponding error code (SESSION_EXPIRED or
IO_DEVICE_ERROR for RPC calls), the error is surfaced to the winbindd
client, and can e.g. fail a SESSION_SETUP in smbd. This happened
recently in a member server that is seeing many short-lived SMB
connections and occassionally some of the getpwnam calls to winbindd
fail due to the expired sessions.
The attached patches catch the error and retry the same request on a new
connection. The first patch is a hack to use the admember selftest
environment for some testing. I was not sure of the best approach of
getting some test coverage here. Maybe change the config of admember to
use short-lived tickets, or create a new admember2 environment that uses
a short ticket lifetime.
Christof
-------------- next part --------------
From cb4baad6baab60a6c211d698981dccb8b705ca96 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Tue, 22 Dec 2015 12:47:55 -0700
Subject: [PATCH 1/8] DONOTPUSH: Hack admember selftest to have winbind receive SESSION_EXPIRED
---
lib/param/util.c | 20 +++++++++-----------
selftest/target/Samba4.pm | 10 ++++++----
2 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/lib/param/util.c b/lib/param/util.c
index 7e4232d..7a805e9 100644
--- a/lib/param/util.c
+++ b/lib/param/util.c
@@ -275,17 +275,15 @@ void lpcfg_default_kdc_policy(struct loadparm_context *lp_ctx,
time_t *usr_tkt_lifetime,
time_t *renewal_lifetime)
{
- long val;
+ *svc_tkt_lifetime = lpcfg_parm_long(lp_ctx, NULL,
+ "kdc", "service ticket lifetime",
+ 10 * 60 * 60);
- val = lpcfg_parm_long(lp_ctx, NULL,
- "kdc", "service ticket lifetime", 10);
- *svc_tkt_lifetime = val * 60 * 60;
+ *usr_tkt_lifetime = lpcfg_parm_long(lp_ctx, NULL,
+ "kdc", "user ticket lifetime",
+ 10 * 60 * 60);
- val = lpcfg_parm_long(lp_ctx, NULL,
- "kdc", "user ticket lifetime", 10);
- *usr_tkt_lifetime = val * 60 * 60;
-
- val = lpcfg_parm_long(lp_ctx, NULL,
- "kdc", "renewal lifetime", 24 * 7);
- *renewal_lifetime = val * 60 * 60;
+ *renewal_lifetime = lpcfg_parm_long(lp_ctx, NULL,
+ "kdc", "renewal lifetime",
+ 24 * 7 * 60 * 60);
}
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index fbefda7..5396c5b 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -1816,7 +1816,7 @@ sub provision_ad_dc($$)
create mask = 755
dos filemode = yes
- dcerpc endpoint servers = -winreg -srvsvc
+ dcerpc endpoint servers = -winreg -srvsvc -epmapper
printcap name = /dev/null
@@ -1833,6 +1833,8 @@ sub provision_ad_dc($$)
queue resume command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb queueresume %p
lpq cache time = 0
print notify backchannel = yes
+ winbind max domain connections = 5
+ kdc:service ticket lifetime = 30
";
my $extra_smbconf_shares = "
@@ -2089,10 +2091,10 @@ sub setup_env($$$)
} elsif ($envname eq "chgdcpass") {
return $self->setup_chgdcpass("$path/chgdcpass", $self->{vars}->{chgdcpass});
} elsif ($envname eq "ad_member") {
- if (not defined($self->{vars}->{ad_dc_ntvfs})) {
- $self->setup_ad_dc_ntvfs("$path/ad_dc_ntvfs");
+ if (not defined($self->{vars}->{ad_dc})) {
+ $self->setup_ad_dc("$path/ad_dc");
}
- return $target3->setup_admember("$path/ad_member", $self->{vars}->{ad_dc_ntvfs}, 29);
+ return $target3->setup_admember("$path/ad_member", $self->{vars}->{ad_dc}, 29);
} elsif ($envname eq "ad_dc") {
return $self->setup_ad_dc("$path/ad_dc");
} elsif ($envname eq "ad_dc_no_nss") {
--
1.7.1
From 312e842f1a71de6f244c26588cfe6ba5b0547072 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Tue, 5 Jan 2016 13:39:25 -0700
Subject: [PATCH 2/8] 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.
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_reconnect.c | 39 ++++++++++++++++++++------------
1 files 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);
--
1.7.1
From 278cff5eb99af42b046a162f0db8f6dbbdcd52ad Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Tue, 5 Jan 2016 14:37:30 -0700
Subject: [PATCH 3/8] winbindd: Add retry also for ADS method calls
RPC calls can return IO_DEVICE_ERROR on expired SMB2 sessions. Retrying
on a new connections avoids surfacing this errors to winbindd clients.
Signed-off-by: Christof Schmitt <cs at samba.org>
---
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 ae9d11f..cf3ed71 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..dc93181
--- /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 <http://www.gnu.org/licenses/>.
+*/
+
+#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 d40dd7e..87b0910 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -904,6 +904,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
--
1.7.1
From 59e7e496069708ea7aa2ae273719afe08944930c Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Tue, 5 Jan 2016 14:42:09 -0700
Subject: [PATCH 4/8] 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.
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_ads.c | 26 ++++++++++++--------------
1 files changed, 12 insertions(+), 14 deletions(-)
diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c
index b373be5..a9a23db 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 */
--
1.7.1
From 0dee804a166a9d8b25b20dbdfff6ef56d7110cbd Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Wed, 6 Jan 2016 14:15:30 -0700
Subject: [PATCH 5/8] winbindd: Retry on expired session in cm_connect_lsa
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_cm.c | 48 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 48 insertions(+), 0 deletions(-)
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 93a2dde..35fd89a 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);
--
1.7.1
From e9c6311a416ad90a6a943ca31e6c8d8d60b04eb5 Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Thu, 7 Jan 2016 15:03:22 -0700
Subject: [PATCH 6/8] winbindd: Retry on expired session in cm_connect_sam
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_cm.c | 48 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 48 insertions(+), 0 deletions(-)
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 35fd89a..c0891ce 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",
--
1.7.1
From 61703c97deb1c6c125c564a01dddbf1a9b12605f Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Tue, 5 Jan 2016 15:10:45 -0700
Subject: [PATCH 7/8] winbindd: Retry on expired session in cm_connect_netlogon
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_cm.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index c0891ce..f593d24 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -3406,6 +3406,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;
}
--
1.7.1
From a97c31b39b1f0a5f7a81fe8a2de1023edce3af9d Mon Sep 17 00:00:00 2001
From: Christof Schmitt <cs at samba.org>
Date: Thu, 7 Jan 2016 13:27:49 -0700
Subject: [PATCH 8/8] Revert "winbind: Retry after SESSION_EXPIRED error in ping-dc"
This reverts commit a2670f15dea27c10e3827216adf572f9c3894f85.
cm_connect_netlogon now handles the retry for an expired session.
Signed-off-by: Christof Schmitt <cs at samba.org>
---
source3/winbindd/winbindd_dual_srv.c | 8 --------
1 files changed, 0 insertions(+), 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",
--
1.7.1
More information about the samba-technical
mailing list