[PATCH] winbindd doesn't recover loss of netlogon secure channel in case the peer DC is rebooted

Ralph Böhme slow at samba.org
Thu Mar 15 12:18:21 UTC 2018


Hi!

Attached is a fix for this bug:
<https://bugzilla.samba.org/show_bug.cgi?id=13332>

Already reviewed by Volker, so I'm going to push later if noone objects.

-slow

-- 
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/
GPG Key Fingerprint:           FAE2 C608 8A24 2520 51C5
                               59E4 AA1E 9B71 2639 9E46
-------------- next part --------------
From fb15916f779f8d1e4966754d77175f287387c482 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Feb 2018 07:59:08 +0000
Subject: [PATCH 01/15] utils: Add destroy_netlogon_creds_cli

This is a pure testing utility that will garble the netlogon_creds_cli
session_key. This creates a similar effect to our schannel credentials
as does a domain controller reboot.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/utils/destroy_netlogon_creds_cli.c | 137 +++++++++++++++++++++++++++++
 source3/utils/wscript_build                |   9 ++
 2 files changed, 146 insertions(+)
 create mode 100644 source3/utils/destroy_netlogon_creds_cli.c

diff --git a/source3/utils/destroy_netlogon_creds_cli.c b/source3/utils/destroy_netlogon_creds_cli.c
new file mode 100644
index 00000000000..137ac8393e7
--- /dev/null
+++ b/source3/utils/destroy_netlogon_creds_cli.c
@@ -0,0 +1,137 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Garble the netlogon_creds_cli key for testing purposes
+ * Copyright (C) Volker Lendecke 2018
+ *
+ * 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 "system/filesys.h"
+#include <talloc.h>
+#include <tevent.h>
+#include "messages.h"
+#include "lib/util/talloc_stack.h"
+#include "popt_common.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param.h"
+#include "libcli/auth/netlogon_creds_cli.h"
+#include "lib/dbwrap/dbwrap.h"
+#include "lib/dbwrap/dbwrap_open.h"
+
+int main(int argc, const char *argv[])
+{
+	TALLOC_CTX *mem_ctx = talloc_stackframe();
+	struct tevent_context *ev;
+	struct messaging_context *msg_ctx;
+	struct loadparm_context *lp_ctx;
+	struct db_context *global_db;
+	struct netlogon_creds_cli_context *ctx;
+	struct netlogon_creds_CredentialState *creds;
+	NTSTATUS status;
+	int ret = 1;
+
+	smb_init_locale();
+
+	if (!lp_load_global(get_dyn_CONFIGFILE())) {
+		fprintf(stderr, "error opening config file %s. Error was %s\n",
+			get_dyn_CONFIGFILE(), strerror(errno));
+		goto done;
+	}
+
+	if (argc != 4) {
+		fprintf(stderr, "usage: %s cli_computer domain dc\n", argv[0]);
+		goto done;
+	}
+
+	lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers());
+	if (lp_ctx == NULL) {
+		fprintf(stderr, "loadparm_init_s3 failed\n");
+		goto done;
+	}
+
+	ev = samba_tevent_context_init(mem_ctx);
+	if (ev == NULL) {
+		fprintf(stderr, "samba3_tevent_context_init failed\n");
+		goto done;
+	}
+	msg_ctx = messaging_init(mem_ctx, ev);
+	if (msg_ctx == NULL) {
+		fprintf(stderr, "messaging_init failed\n");
+		goto done;
+	}
+
+	global_db = db_open(
+		mem_ctx,
+		lpcfg_private_db_path(mem_ctx, lp_ctx, "netlogon_creds_cli"),
+		0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
+		O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_2,
+		DBWRAP_FLAG_OPTIMIZE_READONLY_ACCESS);
+	if (global_db == NULL) {
+		fprintf(stderr, "db_open failed\n");
+		goto done;
+	}
+
+	status = netlogon_creds_cli_set_global_db(&global_db);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr,
+			"netlogon_creds_cli_set_global_db failed: %s\n",
+			nt_errstr(status));
+		goto done;
+	}
+
+	status = netlogon_creds_cli_context_global(
+		lp_ctx,
+		msg_ctx,
+		talloc_asprintf(mem_ctx, "%s$", argv[1]),
+		SEC_CHAN_WKSTA,
+		argv[3],
+		argv[2],
+		"",
+		mem_ctx,
+		&ctx);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr,
+			"netlogon_creds_cli_context_global failed: %s\n",
+			nt_errstr(status));
+		goto done;
+	}
+
+	status = netlogon_creds_cli_lock(ctx,
+					 mem_ctx,
+					 &creds);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr,
+			"netlogon_creds_cli_get failed: %s\n",
+			nt_errstr(status));
+		goto done;
+	}
+
+	creds->session_key[0]++;
+
+	status = netlogon_creds_cli_store(ctx, creds);
+	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr,
+			"netlogon_creds_cli_store failed: %s\n",
+			nt_errstr(status));
+		goto done;
+	}
+
+	TALLOC_FREE(creds);
+
+	ret = 0;
+done:
+	TALLOC_FREE(mem_ctx);
+	return ret;
+}
diff --git a/source3/utils/wscript_build b/source3/utils/wscript_build
index 04eaf077f67..8b4d890d485 100644
--- a/source3/utils/wscript_build
+++ b/source3/utils/wscript_build
@@ -257,3 +257,12 @@ bld.SAMBA3_BINARY('mvxattr',
                  popt_samba3
                  ''',
                  enabled=bld.env.build_mvxattr)
+
+bld.SAMBA3_BINARY('destroy_netlogon_creds_cli',
+                  source='destroy_netlogon_creds_cli.c',
+                  deps = '''
+                      talloc
+                      popt_samba3
+                      NETLOGON_CREDS_CLI
+                  ''',
+                  install=False)
-- 
2.11.0


From 85e912f9ff2085b743184355989c63f2514e4250 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Feb 2018 15:08:44 +0000
Subject: [PATCH 02/15] winbind: Add smbcontrol disconnect-dc

Make a winbind child drop all DC connections

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Ralph Boehme <slow at samba.org>
---
 librpc/idl/messaging.idl          |  1 +
 source3/utils/smbcontrol.c        | 14 ++++++++++++++
 source3/winbindd/winbindd.c       |  4 ++++
 source3/winbindd/winbindd_cm.c    | 16 ++++++++++++++++
 source3/winbindd/winbindd_dual.c  | 19 ++++++++++++++++++-
 source3/winbindd/winbindd_proto.h | 10 ++++++++++
 6 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/librpc/idl/messaging.idl b/librpc/idl/messaging.idl
index 5468334b77b..14a6f92d583 100644
--- a/librpc/idl/messaging.idl
+++ b/librpc/idl/messaging.idl
@@ -124,6 +124,7 @@ interface messaging
 		MSG_WINBIND_DOMAIN_ONLINE	= 0x040B,
 		MSG_WINBIND_DOMAIN_OFFLINE	= 0x040C,
 		MSG_WINBIND_RELOAD_TRUSTED_DOMAINS = 0x040D,
+		MSG_WINBIND_DISCONNECT_DC       = 0x040E,
 
 		/* event messages */
 		/* MSG_DUMP_EVENT_LIST		= 0x0500, Obsoleted */
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index 4ecfb3e6dff..bd89b9ebf0a 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -1225,6 +1225,19 @@ static bool do_winbind_dump_domain_list(struct tevent_context *ev_ctx,
 	return num_replies;
 }
 
+static bool do_msg_disconnect_dc(struct tevent_context *ev_ctx,
+				 struct messaging_context *msg_ctx,
+				 const struct server_id pid,
+				 const int argc, const char **argv)
+{
+	if (argc != 1) {
+		fprintf(stderr, "Usage: smbcontrol <dest> disconnect-dc\n");
+		return False;
+	}
+
+	return send_message(msg_ctx, pid, MSG_WINBIND_DISCONNECT_DC, NULL, 0);
+}
+
 static void winbind_validate_cache_cb(struct messaging_context *msg,
 				      void *private_data,
 				      uint32_t msg_type,
@@ -1402,6 +1415,7 @@ static const struct {
 	{ "validate-cache" , do_winbind_validate_cache,
 	  "Validate winbind's credential cache" },
 	{ "dump-domain-list", do_winbind_dump_domain_list, "Dump winbind domain list"},
+	{ "disconnect-dc", do_msg_disconnect_dc },
 	{ "notify-cleanup", do_notify_cleanup },
 	{ "num-children", do_num_children,
 	  "Print number of smbd child processes" },
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index 81b86df2ffa..8821f39a0da 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -1346,6 +1346,10 @@ static void winbindd_register_handlers(struct messaging_context *msg_ctx,
 			   MSG_DEBUG,
 			   winbind_msg_debug);
 
+	messaging_register(msg_ctx, NULL,
+			   MSG_WINBIND_DISCONNECT_DC,
+			   winbind_disconnect_dc_parent);
+
 	netsamlogon_cache_init(); /* Non-critical */
 
 	/* clear the cached list of trusted domains */
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 1e44e9bd3ce..0f6a0a9ba1f 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -3509,3 +3509,19 @@ void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
 	}
 	TALLOC_FREE(freeit);
 }
+
+void winbind_msg_disconnect_dc(struct messaging_context *msg_ctx,
+			       void *private_data,
+			       uint32_t msg_type,
+			       struct server_id server_id,
+			       DATA_BLOB *data)
+{
+	struct winbindd_domain *domain;
+
+	for (domain = domain_list(); domain; domain = domain->next) {
+		if (domain->internal) {
+			continue;
+		}
+		invalidate_cm_connection(domain);
+	}
+}
diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c
index 2a4950b56bf..5ae5bbd9468 100644
--- a/source3/winbindd/winbindd_dual.c
+++ b/source3/winbindd/winbindd_dual.c
@@ -882,6 +882,21 @@ void winbind_msg_debug(struct messaging_context *msg_ctx,
 	forall_children(winbind_msg_relay_fn, &state);
 }
 
+void winbind_disconnect_dc_parent(struct messaging_context *msg_ctx,
+				  void *private_data,
+				  uint32_t msg_type,
+				  struct server_id server_id,
+				  DATA_BLOB *data)
+{
+	struct winbind_msg_relay_state state = {
+		.msg_ctx = msg_ctx, .msg_type = msg_type, .data = data
+	};
+
+	DBG_DEBUG("Got disconnect_dc message\n");
+
+	forall_children(winbind_msg_relay_fn, &state);
+}
+
 /* Set our domains as offline and forward the offline message to our children. */
 
 struct winbind_msg_on_offline_state {
@@ -1710,7 +1725,9 @@ static bool fork_domain_child(struct winbindd_child *child)
 	messaging_register(server_messaging_context(), NULL,
 			   MSG_WINBIND_IP_DROPPED,
 			   winbind_msg_ip_dropped);
-
+	messaging_register(server_messaging_context(), NULL,
+			   MSG_WINBIND_DISCONNECT_DC,
+			   winbind_msg_disconnect_dc);
 
 	primary_domain = find_our_domain();
 
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index b70227c9b91..f8ffeea74cf 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -297,6 +297,11 @@ void winbind_msg_debug(struct messaging_context *msg_ctx,
 			 uint32_t msg_type,
 			 struct server_id server_id,
 			 DATA_BLOB *data);
+void winbind_disconnect_dc_parent(struct messaging_context *msg_ctx,
+				  void *private_data,
+				  uint32_t msg_type,
+				  struct server_id server_id,
+				  DATA_BLOB *data);
 void winbind_msg_offline(struct messaging_context *msg_ctx,
 			 void *private_data,
 			 uint32_t msg_type,
@@ -327,6 +332,11 @@ void winbind_msg_ip_dropped(struct messaging_context *msg_ctx,
 			    uint32_t msg_type,
 			    struct server_id server_id,
 			    DATA_BLOB *data);
+void winbind_msg_disconnect_dc(struct messaging_context *msg_ctx,
+			       void *private_data,
+			       uint32_t msg_type,
+			       struct server_id server_id,
+			       DATA_BLOB *data);
 void winbind_msg_ip_dropped_parent(struct messaging_context *msg_ctx,
 				   void *private_data,
 				   uint32_t msg_type,
-- 
2.11.0


From a7b39324ea38538838a21ded1f2599fc0e68df80 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 28 Feb 2018 15:09:28 +0000
Subject: [PATCH 03/15] winbind: Keep "force_reauth" in
 invalidate_cm_connection

Right now I don't see a way to actually force a re-serverauth
from the client side as long as an entry in netlogon_creds_cli.tdb
exists. cm_connect_netlogon goes through invalidate_cm_connection, and
this wipes our wish to force a reauthenticatoin. Keep this intact until
we actually did reauthenticate.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Volker Lendecke <vl at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_cm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 0f6a0a9ba1f..bf5a2b4d7b1 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -2081,7 +2081,6 @@ void invalidate_cm_connection(struct winbindd_domain *domain)
 	}
 
 	conn->auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
-	conn->netlogon_force_reauth = false;
 	TALLOC_FREE(conn->netlogon_creds_ctx);
 
 	if (conn->cli) {
@@ -3368,6 +3367,7 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 		conn->cli, transport,
 		conn->netlogon_creds_ctx, conn->netlogon_force_reauth, creds,
 		&conn->netlogon_pipe);
+	conn->netlogon_force_reauth = false;
 	if (!NT_STATUS_IS_OK(result)) {
 		DBG_DEBUG("rpccli_connect_netlogon failed: %s\n",
 			  nt_errstr(result));
-- 
2.11.0


From de45b731b1395524f506f981f2746b321319ab75 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 13:30:01 +0100
Subject: [PATCH 04/15] winbindd: add and use ldap_reconnect_need_retry() in
 winbindd_reconnect_ads.c

ldap_reconnect_need_retry() is a copy of reconnect_need_retry() minus
the RPC connection invalidation.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_reconnect_ads.c | 58 +++++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 6 deletions(-)

diff --git a/source3/winbindd/winbindd_reconnect_ads.c b/source3/winbindd/winbindd_reconnect_ads.c
index 3bb8b5ecba1..0a0a14f6dd0 100644
--- a/source3/winbindd/winbindd_reconnect_ads.c
+++ b/source3/winbindd/winbindd_reconnect_ads.c
@@ -31,6 +31,52 @@
 
 extern struct winbindd_methods ads_methods;
 
+static bool ldap_reconnect_need_retry(NTSTATUS status,
+				      struct winbindd_domain *domain)
+{
+	if (NT_STATUS_IS_OK(status)) {
+		return false;
+	}
+
+	if (!NT_STATUS_IS_ERR(status)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_GROUP)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_ALIAS)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_MEMBER)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_DOMAIN)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_PRIVILEGE)) {
+		return false;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
+		return false;
+	}
+
+	return true;
+}
+
 /* List all users */
 static NTSTATUS query_user_list(struct winbindd_domain *domain,
 				TALLOC_CTX *mem_ctx,
@@ -40,7 +86,7 @@ static NTSTATUS query_user_list(struct winbindd_domain *domain,
 
 	result = ads_methods.query_user_list(domain, mem_ctx, rids);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.query_user_list(domain, mem_ctx, rids);
 	}
 
@@ -58,7 +104,7 @@ static NTSTATUS enum_dom_groups(struct winbindd_domain *domain,
 	result = ads_methods.enum_dom_groups(domain, mem_ctx,
 					     num_entries, info);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.enum_dom_groups(domain, mem_ctx,
 						     num_entries, info);
 	}
@@ -77,7 +123,7 @@ static NTSTATUS enum_local_groups(struct winbindd_domain *domain,
 	result = ads_methods.enum_local_groups(domain, mem_ctx,
 					       num_entries, info);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.enum_local_groups(domain, mem_ctx,
 						       num_entries, info);
 	}
@@ -165,7 +211,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain,
 	result = ads_methods.lookup_usergroups(domain, mem_ctx, user_sid,
 					       num_groups, user_gids);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.lookup_usergroups(domain, mem_ctx,
 						       user_sid, num_groups,
 						       user_gids);
@@ -210,7 +256,7 @@ static NTSTATUS lookup_groupmem(struct winbindd_domain *domain,
 					     num_names, sid_mem, names,
 					     name_types);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.lookup_groupmem(domain, mem_ctx, group_sid,
 						     type, num_names, sid_mem,
 						     names, name_types);
@@ -226,7 +272,7 @@ static NTSTATUS sequence_number(struct winbindd_domain *domain, uint32_t *seq)
 
 	result = ads_methods.sequence_number(domain, seq);
 
-	if (reconnect_need_retry(result, domain)) {
+	if (ldap_reconnect_need_retry(result, domain)) {
 		result = ads_methods.sequence_number(domain, seq);
 	}
 
-- 
2.11.0


From 33ccccac4e60dd2cbf0d588bfabdaa2e83f6c7f7 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 11:12:34 +0100
Subject: [PATCH 05/15] winbindd: check for NT_STATUS_IO_DEVICE_ERROR in
 reset_cm_connection_on_error()

reconnect_need_retry() already checks for this error, it surfaces up
from tstream_smbXcli_np as a mapping for EIO.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 66b4ee82a25..7eff25a5bdf 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -44,7 +44,9 @@ void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
 					NTSTATUS status)
 {
-	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
+	    NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
+	{
 		invalidate_cm_connection(domain);
 		/* We invalidated the connection. */
 		return true;
-- 
2.11.0


From 028506e1c74fdcc731c999e0bae604395e5a1d4c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 11:29:22 +0100
Subject: [PATCH 06/15] winbindd: make reset_cm_connection_on_error() public

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 4 ++--
 source3/winbindd/winbindd_proto.h    | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 7eff25a5bdf..861451c0fc9 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -41,8 +41,8 @@ void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 	*r->out.out_data = r->in.in_data;
 }
 
-static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
-					NTSTATUS status)
+bool reset_cm_connection_on_error(struct winbindd_domain *domain,
+				  NTSTATUS status)
 {
 	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
 	    NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index f8ffeea74cf..a8ecfafc997 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -961,4 +961,8 @@ bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain);
 /* The following definitions come from winbindd/winbindd_gpupdate.c  */
 void gpupdate_init(void);
 
+/* The following comes from winbindd/winbindd_dual_srv.c */
+bool reset_cm_connection_on_error(struct winbindd_domain *domain,
+				  NTSTATUS status);
+
 #endif /*  _WINBINDD_PROTO_H_  */
-- 
2.11.0


From 15789afad4c45b3db735e562bc9eabc1b5f715fd Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 12:20:04 +0100
Subject: [PATCH 07/15] winbindd: call reset_cm_connection_on_error() from
 reconnect_need_retry()

This ensures we use the same disconnect logic in the reconnect backend,
which calls reconnect_need_retry(), and in the dual_srv frontend which
calls reset_cm_connection_on_error.

Both reset_cm_connection_on_error() and reconnect_need_retry() are very
similar, both return a bool indicating whether a retry should be
attempted, unfortunately the functions have a different default return,
so I don't dare unifying them, but instead just call one from the other.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_reconnect.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c
index bbb5a37f390..aa7cd12e8b4 100644
--- a/source3/winbindd/winbindd_reconnect.c
+++ b/source3/winbindd/winbindd_reconnect.c
@@ -69,13 +69,7 @@ bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain)
 		return false;
 	}
 
-	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR)) {
-		/*
-		 * RPC call sent on expired session, needs
-		 * reauthentication.
-		 */
-		invalidate_cm_connection(domain);
-	}
+	reset_cm_connection_on_error(domain, status);
 
 	return true;
 }
-- 
2.11.0


From 9c38aa749867f757665334b69463250a33963b9a Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 13:39:59 +0100
Subject: [PATCH 08/15] winbindd: force netlogon reauth for certain errors in
 reset_cm_connection_on_error()

NT_STATUS_RPC_SEC_PKG_ERROR is returned by the server if the server
doesn't know the server-side netlogon credentials anymore, eg after a
reboot. If this happens we must force a full netlogon reauth.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Volker Lendecke <vl at samba.org>
Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 861451c0fc9..10345fb81d2 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -44,6 +44,14 @@ void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
 				  NTSTATUS status)
 {
+	if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
+	    NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
+	    NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+		invalidate_cm_connection(domain);
+		domain->conn.netlogon_force_reauth = true;
+		return true;
+	}
+
 	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
 	    NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
 	{
-- 
2.11.0


From 999bfc67240e98bfb80461385691bddd0bc8763d Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 16:11:37 +0100
Subject: [PATCH 09/15] winbindd: call dcerpc_binding_handle_is_connected()
 from reset_cm_connection_on_error()

To consolidate the error handling for RPC calls, add the binding handle
as an additional argument to reset_cm_connection_on_error().

All callers pass NULL for now, so no change in behaviour up to here.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c  | 51 ++++++++++++++++++++---------------
 source3/winbindd/winbindd_proto.h     |  1 +
 source3/winbindd/winbindd_reconnect.c |  2 +-
 3 files changed, 31 insertions(+), 23 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 10345fb81d2..d9760e0fc1c 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -42,6 +42,7 @@ void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
 }
 
 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
+				  struct dcerpc_binding_handle *b,
 				  NTSTATUS status)
 {
 	if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
@@ -59,6 +60,12 @@ bool reset_cm_connection_on_error(struct winbindd_domain *domain,
 		/* We invalidated the connection. */
 		return true;
 	}
+
+	if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
+		invalidate_cm_connection(domain);
+		return true;
+	}
+
 	return false;
 }
 
@@ -76,7 +83,7 @@ NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
 
 	status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
 				      &dom_name, &name, &type);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -110,7 +117,7 @@ NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
 		r->out.domains = domains;
 	}
 
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	return status;
 }
 
@@ -126,7 +133,7 @@ NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
 	status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
 				      r->in.name, r->in.flags,
 				      r->out.sid, r->out.type);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	return status;
 }
 
@@ -314,7 +321,7 @@ NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
 					     r->in.sids->sids,
 					     &r->out.rids->num_rids,
 					     &r->out.rids->rids);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	return status;
 }
 
@@ -331,7 +338,7 @@ NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
 	status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
 					    &r->out.sids->num_sids,
 					    &r->out.sids->sids);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	return status;
 }
 
@@ -346,7 +353,7 @@ NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
 	}
 
 	status = wb_cache_sequence_number(domain, r->out.sequence);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	return status;
 }
 
@@ -367,7 +374,7 @@ NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
 	status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
 					  r->in.type, &num_names, &sid_mem,
 					  &names, &name_types);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -434,7 +441,7 @@ NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
 		status = wb_cache_enum_local_groups(domain, frame,
 						    &num_local_groups,
 						    &local_groups);
-		reset_cm_connection_on_error(domain, status);
+		reset_cm_connection_on_error(domain, NULL, status);
 		if (!NT_STATUS_IS_OK(status)) {
 			goto out;
 		}
@@ -443,7 +450,7 @@ NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
 	status = wb_cache_enum_dom_groups(domain, frame,
 					  &num_dom_groups,
 					  &dom_groups);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		goto out;
 	}
@@ -514,7 +521,7 @@ NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
 
 	status = wb_cache_query_user_list(domain, p->mem_ctx,
 					  &r->out.rids->rids);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
@@ -545,7 +552,7 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 
 	status = cm_connect_netlogon(domain, &netlogon_pipe);
 
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
 		return status;
@@ -566,11 +573,11 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 		if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
 			goto done;
 		}
-		if (reset_cm_connection_on_error(domain, status)) {
+		if (reset_cm_connection_on_error(domain, NULL, status)) {
 			/* Re-initialize. */
 			status = cm_connect_netlogon(domain, &netlogon_pipe);
 
-			reset_cm_connection_on_error(domain, status);
+			reset_cm_connection_on_error(domain, NULL, status);
 			if (!NT_STATUS_IS_OK(status)) {
 				DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
 				return status;
@@ -605,7 +612,7 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 			r->in.domain_name, &dc_info->dc_unc, &werr);
 	}
 
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
 			   nt_errstr(status)));
@@ -645,7 +652,7 @@ NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
 	status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
 					r->in.rids->rids, r->in.rids->num_rids,
 					&domain_name, &names, &types);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -789,7 +796,7 @@ NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
 
 reconnect:
 	status = cm_connect_netlogon(domain, &netlogon_pipe);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
         if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
 			  nt_errstr(status)));
@@ -823,7 +830,7 @@ reconnect:
 		goto reconnect;
 	}
 
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
 			nt_errstr(status)));
@@ -1036,7 +1043,7 @@ static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
 		status = NT_STATUS_NO_LOGON_SERVERS;
 	}
@@ -1108,7 +1115,7 @@ static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
 		status = NT_STATUS_NO_LOGON_SERVERS;
 	}
@@ -1290,7 +1297,7 @@ reconnect:
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
 		status = NT_STATUS_NO_LOGON_SERVERS;
 	}
@@ -1513,7 +1520,7 @@ reconnect:
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
 		status = NT_STATUS_NO_LOGON_SERVERS;
 	}
@@ -1721,7 +1728,7 @@ reconnect:
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
 		status = NT_STATUS_NO_LOGON_SERVERS;
 	}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index a8ecfafc997..6a63b151720 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -963,6 +963,7 @@ void gpupdate_init(void);
 
 /* The following comes from winbindd/winbindd_dual_srv.c */
 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
+				  struct dcerpc_binding_handle *b,
 				  NTSTATUS status);
 
 #endif /*  _WINBINDD_PROTO_H_  */
diff --git a/source3/winbindd/winbindd_reconnect.c b/source3/winbindd/winbindd_reconnect.c
index aa7cd12e8b4..1d0e8e6d472 100644
--- a/source3/winbindd/winbindd_reconnect.c
+++ b/source3/winbindd/winbindd_reconnect.c
@@ -69,7 +69,7 @@ bool reconnect_need_retry(NTSTATUS status, struct winbindd_domain *domain)
 		return false;
 	}
 
-	reset_cm_connection_on_error(domain, status);
+	reset_cm_connection_on_error(domain, NULL, status);
 
 	return true;
 }
-- 
2.11.0


From 15036d4c624947383c84c0ceb3a0e542ca9c6e79 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 16:15:02 +0100
Subject: [PATCH 10/15] winbindd: fix logic calling
 dcerpc_binding_handle_is_connected()

The calls were missing the negation operator, a retry should be
attempted is the binding handle got somehow disconnected behind the
scenes and is NOT connected.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index d9760e0fc1c..e80f3dd8d45 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -1327,7 +1327,7 @@ reconnect:
 			status = NT_STATUS_OK;
 		}
 		if (!NT_STATUS_IS_OK(status)) {
-			if (!retry && dcerpc_binding_handle_is_connected(b)) {
+			if (!retry && !dcerpc_binding_handle_is_connected(b)) {
 				invalidate_cm_connection(domain);
 				retry = true;
 				goto reconnect;
@@ -1393,7 +1393,7 @@ reconnect:
 		goto verify_return;
 	}
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && dcerpc_binding_handle_is_connected(b)) {
+		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
 			invalidate_cm_connection(domain);
 			retry = true;
 			goto reconnect;
@@ -1547,7 +1547,7 @@ reconnect:
 				 domain->dcname,
 				 true); /* force */
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && dcerpc_binding_handle_is_connected(b)) {
+		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
 			invalidate_cm_connection(domain);
 			retry = true;
 			goto reconnect;
@@ -1744,7 +1744,7 @@ reconnect:
 							      b, p->mem_ctx,
 							      &new_fti);
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && dcerpc_binding_handle_is_connected(b)) {
+		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
 			invalidate_cm_connection(domain);
 			retry = true;
 			goto reconnect;
-- 
2.11.0


From c3bda8abe46205ebf73ac4eaa3fb1821a5cdc80f Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 16:53:49 +0100
Subject: [PATCH 11/15] winbindd: use reset_cm_connection_on_error() instead of
 dcerpc_binding_handle_is_connected()

This catches more errors and triggers retry as appropriate.

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index e80f3dd8d45..f7f01431c91 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -822,15 +822,11 @@ reconnect:
 					  logon_server, NETLOGON_CONTROL_QUERY,
 					  2, &info, &werr);
 
-	if (!dcerpc_binding_handle_is_connected(b) && !retry) {
-		DEBUG(10, ("Session might have expired. "
-			   "Reconnect and retry once.\n"));
-		invalidate_cm_connection(domain);
+	if (!retry && reset_cm_connection_on_error(domain, b, status)) {
 		retry = true;
 		goto reconnect;
 	}
 
-	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
 			nt_errstr(status)));
@@ -1327,8 +1323,9 @@ reconnect:
 			status = NT_STATUS_OK;
 		}
 		if (!NT_STATUS_IS_OK(status)) {
-			if (!retry && !dcerpc_binding_handle_is_connected(b)) {
-				invalidate_cm_connection(domain);
+			if (!retry &&
+			    reset_cm_connection_on_error(domain, b, status))
+			{
 				retry = true;
 				goto reconnect;
 			}
@@ -1393,8 +1390,7 @@ reconnect:
 		goto verify_return;
 	}
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
-			invalidate_cm_connection(domain);
+		if (!retry && reset_cm_connection_on_error(domain, b, status)) {
 			retry = true;
 			goto reconnect;
 		}
@@ -1547,8 +1543,7 @@ reconnect:
 				 domain->dcname,
 				 true); /* force */
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
-			invalidate_cm_connection(domain);
+		if (!retry && reset_cm_connection_on_error(domain, b, status)) {
 			retry = true;
 			goto reconnect;
 		}
@@ -1744,8 +1739,7 @@ reconnect:
 							      b, p->mem_ctx,
 							      &new_fti);
 	if (!NT_STATUS_IS_OK(status)) {
-		if (!retry && !dcerpc_binding_handle_is_connected(b)) {
-			invalidate_cm_connection(domain);
+		if (!retry && reset_cm_connection_on_error(domain, b, status)) {
 			retry = true;
 			goto reconnect;
 		}
-- 
2.11.0


From d747d41f0e1990adcad79b976cf719102ed18f4b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 17:09:34 +0100
Subject: [PATCH 12/15] winbindd: add retry to _wbint_LookupSids()

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index f7f01431c91..4df2c5388c9 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -99,6 +99,7 @@ NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
 	struct winbindd_domain *domain = wb_child_domain();
 	struct lsa_RefDomainList *domains = r->out.domains;
 	NTSTATUS status;
+	bool retry = false;
 
 	if (domain == NULL) {
 		return NT_STATUS_REQUEST_NOT_ACCEPTED;
@@ -110,6 +111,7 @@ NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
 	 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
 	 * done at the wbint RPC layer.
 	 */
+again:
 	status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
 				 &domains, &r->out.names);
 
@@ -117,7 +119,11 @@ NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
 		r->out.domains = domains;
 	}
 
-	reset_cm_connection_on_error(domain, NULL, status);
+	if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
+		retry = true;
+		goto again;
+	}
+
 	return status;
 }
 
-- 
2.11.0


From ef0e3d88883bfbd787ca335023704418e063fd3e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 19:53:26 +0100
Subject: [PATCH 13/15] winbindd: add retry to _wbint_DsGetDcName

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 37 ++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 4df2c5388c9..1acba3a29e3 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -547,6 +547,8 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 	WERROR werr;
 	unsigned int orig_timeout;
 	struct dcerpc_binding_handle *b;
+	bool retry = false;
+	bool try_dsrgetdcname = false;
 
 	if (domain == NULL) {
 		return dsgetdcname(p->mem_ctx, server_messaging_context(),
@@ -556,6 +558,11 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 				   r->out.dc_info);
 	}
 
+	if (domain->active_directory) {
+		try_dsrgetdcname = true;
+	}
+
+reconnect:
 	status = cm_connect_netlogon(domain, &netlogon_pipe);
 
 	reset_cm_connection_on_error(domain, NULL, status);
@@ -571,7 +578,7 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 
 	orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
 
-	if (domain->active_directory) {
+	if (try_dsrgetdcname) {
 		status = dcerpc_netr_DsRGetDCName(b,
 			p->mem_ctx, domain->dcname,
 			r->in.domain_name, NULL, r->in.domain_guid,
@@ -579,23 +586,14 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 		if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
 			goto done;
 		}
-		if (reset_cm_connection_on_error(domain, NULL, status)) {
-			/* Re-initialize. */
-			status = cm_connect_netlogon(domain, &netlogon_pipe);
-
-			reset_cm_connection_on_error(domain, NULL, status);
-			if (!NT_STATUS_IS_OK(status)) {
-				DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
-				return status;
-			}
-
-			b = netlogon_pipe->binding_handle;
-
-			/* This call can take a long time - allow the server to time out.
-			   35 seconds should do it. */
-
-			orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
+		if (!retry &&
+		    reset_cm_connection_on_error(domain, NULL, status))
+		{
+			retry = true;
+			goto reconnect;
 		}
+		try_dsrgetdcname = false;
+		retry = false;
 	}
 
 	/*
@@ -618,7 +616,10 @@ NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
 			r->in.domain_name, &dc_info->dc_unc, &werr);
 	}
 
-	reset_cm_connection_on_error(domain, NULL, status);
+	if (!retry && reset_cm_connection_on_error(domain, b, status)) {
+		retry = true;
+		goto reconnect;
+	}
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
 			   nt_errstr(status)));
-- 
2.11.0


From fd5c3246094b9948d7a2f211c7da924bcd8bf1b1 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 19:53:53 +0100
Subject: [PATCH 14/15] winbindd: add retry to
 _winbind_DsrUpdateReadOnlyServerDnsRecords

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 1acba3a29e3..20b919ca3b7 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -858,12 +858,15 @@ NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
 	NTSTATUS status;
 	struct rpc_pipe_client *netlogon_pipe = NULL;
 	struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
+	struct dcerpc_binding_handle *b = NULL;
+	bool retry = false;
 
 	domain = wb_child_domain();
 	if (domain == NULL) {
 		return NT_STATUS_REQUEST_NOT_ACCEPTED;
 	}
 
+reconnect:
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
@@ -872,12 +875,19 @@ NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
 		goto done;
 	}
 
+	b = netlogon_pipe->binding_handle;
+
 	status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
 								      netlogon_pipe->binding_handle,
 								      r->in.site_name,
 								      r->in.dns_ttl,
 								      r->in.dns_names);
 
+	if (!retry && reset_cm_connection_on_error(domain, b, status)) {
+		retry = true;
+		goto reconnect;
+	}
+
 	/* Pass back result code - zero for success, other values for
 	   specific failures. */
 
-- 
2.11.0


From 3562e387109d75ee69e5a67cf1f4ea19b0a76cd0 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 12 Mar 2018 19:54:37 +0100
Subject: [PATCH 15/15] winbindd: add retry to _winbind_SendToSam

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13332

Signed-off-by: Ralph Boehme <slow at samba.org>
Reviewed-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_dual_srv.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c
index 20b919ca3b7..4cea73feaf9 100644
--- a/source3/winbindd/winbindd_dual_srv.c
+++ b/source3/winbindd/winbindd_dual_srv.c
@@ -1851,6 +1851,8 @@ NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
 	NTSTATUS status;
 	struct rpc_pipe_client *netlogon_pipe;
 	struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
+	struct dcerpc_binding_handle *b = NULL;
+	bool retry = false;
 
 	DEBUG(5, ("_winbind_SendToSam received\n"));
 	domain = wb_child_domain();
@@ -1858,17 +1860,25 @@ NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
 		return NT_STATUS_REQUEST_NOT_ACCEPTED;
 	}
 
+reconnect:
 	status = cm_connect_netlogon_secure(domain,
 					    &netlogon_pipe,
 					    &netlogon_creds_ctx);
+	reset_cm_connection_on_error(domain, NULL, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
 		return status;
 	}
 
+	b = netlogon_pipe->binding_handle;
+
 	status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
-					      netlogon_pipe->binding_handle,
+					      b,
 					      &r->in.message);
+	if (!retry && reset_cm_connection_on_error(domain, b, status)) {
+		retry = true;
+		goto reconnect;
+	}
 
 	return status;
 }
-- 
2.11.0



More information about the samba-technical mailing list