[PATCH] Next round of netlogon_cli_creds refactoring

Volker Lendecke Volker.Lendecke at SerNet.DE
Wed Sep 20 22:02:06 UTC 2017


On Sun, Sep 17, 2017 at 03:36:17PM +1200, Andrew Bartlett via samba-technical wrote:
> I remember writing (part of) that comment you moved about SamLogonEx,
> and it is so nice to have an infrastructure like the netlogon_cli_creds
> that solves the problem properly.  It was really easy to plug in for
> more calls when we had to implement SendToSam recently. 

Attached find the whole patchset. rpccli_connect_netlogon might be a
bit subtle, but I think this properly covers connecting to netlogon in
a scalable manner.

Comments?

Thanks, Volker

-- 
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:kontakt at sernet.de
-------------- next part --------------
From f7cd33517c9af99b7c9ef05e63678c5dcf03af76 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 04:10:59 -0700
Subject: [PATCH 01/28] netlogon_creds_cli: Fix talloc_stackframe leaks

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index dc05316ac13..847922c0256 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -272,11 +272,13 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 	*_context = NULL;
 
 	if (msg_ctx == NULL) {
+		TALLOC_FREE(frame);
 		return NT_STATUS_INVALID_PARAMETER_MIX;
 	}
 
 	client_computer = lpcfg_netbios_name(lp_ctx);
 	if (strlen(client_computer) > 15) {
+		TALLOC_FREE(frame);
 		return NT_STATUS_INVALID_PARAMETER_MIX;
 	}
 
-- 
2.11.0


From 2ccd1bde50afb3a19690a97aec355143c9a494ac Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 5 Sep 2017 15:35:17 +0200
Subject: [PATCH 02/28] netlogon_creds_cli: Simplify
 netlogon_creds_cli_context_global

netlogon_creds_cli_open_global_db() already contains the NULL check. Use that.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 847922c0256..4a79b7c56e1 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -434,13 +434,6 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (netlogon_creds_cli_global_db != NULL) {
-		context->db.ctx = netlogon_creds_cli_global_db;
-		*_context = context;
-		TALLOC_FREE(frame);
-		return NT_STATUS_OK;
-	}
-
 	status = netlogon_creds_cli_open_global_db(lp_ctx);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(context);
-- 
2.11.0


From 106a871cd6829c6da9861b911053d5b1bd916194 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 5 Sep 2017 16:17:58 +0200
Subject: [PATCH 03/28] cli_netlogon: Rename "netlogon_creds" to "creds_ctx"

Trying to understand this code it's important for me to name variables
indicating their use: A netlogon_creds_cli_context is a context with access to
credentials, it's not the credentials itself.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 70 +++++++++++++++++++--------------------
 source3/rpc_client/cli_netlogon.h |  4 +--
 2 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 2c3e205e2f4..4b8beb5f44f 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -132,7 +132,7 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 	const char *server_computer,
 	struct messaging_context *msg_ctx,
 	TALLOC_CTX *mem_ctx,
-	struct netlogon_creds_cli_context **netlogon_creds)
+	struct netlogon_creds_cli_context **creds_ctx)
 {
 	enum netr_SchannelType sec_chan_type;
 	const char *server_netbios_domain;
@@ -154,13 +154,13 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 					    client_account,
 					    sec_chan_type,
 					    msg_ctx, mem_ctx,
-					    netlogon_creds);
+					    creds_ctx);
 }
 
 NTSTATUS rpccli_setup_netlogon_creds(
 	struct cli_state *cli,
 	enum dcerpc_transport_t transport,
-	struct netlogon_creds_cli_context *netlogon_creds,
+	struct netlogon_creds_cli_context *creds_ctx,
 	bool force_reauth,
 	struct cli_credentials *cli_creds)
 {
@@ -172,8 +172,7 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	uint8_t idx_nt_hashes = 0;
 	NTSTATUS status;
 
-	status = netlogon_creds_cli_get(netlogon_creds,
-					frame, &creds);
+	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
 	if (NT_STATUS_IS_OK(status)) {
 		const char *action = "using";
 
@@ -219,7 +218,7 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	}
 	talloc_steal(frame, netlogon_pipe);
 
-	status = netlogon_creds_cli_auth(netlogon_creds,
+	status = netlogon_creds_cli_auth(creds_ctx,
 					 netlogon_pipe->binding_handle,
 					 num_nt_hashes,
 					 nt_hashes,
@@ -229,8 +228,7 @@ NTSTATUS rpccli_setup_netlogon_creds(
 		return status;
 	}
 
-	status = netlogon_creds_cli_get(netlogon_creds,
-					frame, &creds);
+	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(frame);
 		return NT_STATUS_INTERNAL_ERROR;
@@ -294,18 +292,19 @@ static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 
 /* Logon domain user */
 
-NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
-					struct dcerpc_binding_handle *binding_handle,
-					TALLOC_CTX *mem_ctx,
-					uint32_t logon_parameters,
-					const char *domain,
-					const char *username,
-					const char *password,
-					const char *workstation,
-					enum netr_LogonInfoClass logon_type,
-					uint8_t *authoritative,
-					uint32_t *flags,
-					struct netr_SamInfo3 **info3)
+NTSTATUS rpccli_netlogon_password_logon(
+	struct netlogon_creds_cli_context *creds_ctx,
+	struct dcerpc_binding_handle *binding_handle,
+	TALLOC_CTX *mem_ctx,
+	uint32_t logon_parameters,
+	const char *domain,
+	const char *username,
+	const char *password,
+	const char *workstation,
+	enum netr_LogonInfoClass logon_type,
+	uint8_t *authoritative,
+	uint32_t *flags,
+	struct netr_SamInfo3 **info3)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	NTSTATUS status;
@@ -412,7 +411,7 @@ NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds
 		return NT_STATUS_INVALID_INFO_CLASS;
 	}
 
-	status = netlogon_creds_cli_LogonSamLogon(creds,
+	status = netlogon_creds_cli_LogonSamLogon(creds_ctx,
 						  binding_handle,
 						  logon_type,
 						  logon,
@@ -445,19 +444,20 @@ NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds
  **/
 
 
-NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
-				       struct dcerpc_binding_handle *binding_handle,
-				       TALLOC_CTX *mem_ctx,
-				       uint32_t logon_parameters,
-				       const char *username,
-				       const char *domain,
-				       const char *workstation,
-				       const uint8_t chal[8],
-				       DATA_BLOB lm_response,
-				       DATA_BLOB nt_response,
-				       uint8_t *authoritative,
-				       uint32_t *flags,
-				       struct netr_SamInfo3 **info3)
+NTSTATUS rpccli_netlogon_network_logon(
+	struct netlogon_creds_cli_context *creds_ctx,
+	struct dcerpc_binding_handle *binding_handle,
+	TALLOC_CTX *mem_ctx,
+	uint32_t logon_parameters,
+	const char *username,
+	const char *domain,
+	const char *workstation,
+	const uint8_t chal[8],
+	DATA_BLOB lm_response,
+	DATA_BLOB nt_response,
+	uint8_t *authoritative,
+	uint32_t *flags,
+	struct netr_SamInfo3 **info3)
 {
 	NTSTATUS status;
 	const char *workstation_name_slash;
@@ -516,7 +516,7 @@ NTSTATUS rpccli_netlogon_network_logon(struct netlogon_creds_cli_context *creds,
 
 	/* Marshall data and send request */
 
-	status = netlogon_creds_cli_LogonSamLogon(creds,
+	status = netlogon_creds_cli_LogonSamLogon(creds_ctx,
 						  binding_handle,
 						  NetlogonNetworkInformation,
 						  logon,
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index d66bcd3b55b..04a370fba88 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -38,11 +38,11 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 	const char *server_computer,
 	struct messaging_context *msg_ctx,
 	TALLOC_CTX *mem_ctx,
-	struct netlogon_creds_cli_context **netlogon_creds);
+	struct netlogon_creds_cli_context **creds_ctx);
 NTSTATUS rpccli_setup_netlogon_creds(
 	struct cli_state *cli,
 	enum dcerpc_transport_t transport,
-	struct netlogon_creds_cli_context *netlogon_creds,
+	struct netlogon_creds_cli_context *creds_ctx,
 	bool force_reauth,
 	struct cli_credentials *cli_creds);
 NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
-- 
2.11.0


From df2fa69f050e136b90750049d393e73a3d05e797 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 5 Sep 2017 16:26:11 +0200
Subject: [PATCH 04/28] cli_netlogon: Remove an unnecessary if-condition

We don't need to check this here. rpccli_create_netlogon_creds_ctx via
netlogon_creds_cli_context_global returns NT_STATUS_INVALID_PARAMETER for an
unknown schannel type. Slightly different error code, but we could change the
one in netlogon_creds_cli_context_global if necessary.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 4b8beb5f44f..752a1574919 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -140,10 +140,6 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 	const char *client_account;
 
 	sec_chan_type = cli_credentials_get_secure_channel_type(creds);
-	if (sec_chan_type == SEC_CHAN_NULL) {
-		return NT_STATUS_INVALID_PARAMETER_MIX;
-	}
-
 	client_account = cli_credentials_get_username(creds);
 	server_netbios_domain = cli_credentials_get_domain(creds);
 	server_dns_domain = cli_credentials_get_realm(creds);
-- 
2.11.0


From f42f429973a58f9b679ba4bb30e2313df2311b3c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 10 Sep 2017 14:55:13 +0200
Subject: [PATCH 05/28] netlogon_creds_cli: Simplify netlogon_creds_cli_store

Don't implicitly TALLOC_FREE(creds) in the pure store routine. This
mixes up responsibilities, and there's not enough callers to justify
the TALLOC_FREE to be centralized.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 33 +++++++++++++++++----------------
 libcli/auth/netlogon_creds_cli.h |  2 +-
 2 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 4a79b7c56e1..a56a348edd2 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -672,21 +672,17 @@ bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
 }
 
 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
-				  struct netlogon_creds_CredentialState **_creds)
+				  struct netlogon_creds_CredentialState *creds)
 {
-	struct netlogon_creds_CredentialState *creds = *_creds;
 	NTSTATUS status;
 	enum ndr_err_code ndr_err;
 	DATA_BLOB blob;
 	TDB_DATA data;
 
-	*_creds = NULL;
-
 	if (context->db.locked_state == NULL) {
 		/*
 		 * this was not the result of netlogon_creds_cli_lock*()
 		 */
-		TALLOC_FREE(creds);
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
@@ -694,14 +690,12 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 		/*
 		 * this was not the result of netlogon_creds_cli_lock*()
 		 */
-		TALLOC_FREE(creds);
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
 	ndr_err = ndr_push_struct_blob(&blob, creds, creds,
 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-		TALLOC_FREE(creds);
 		status = ndr_map_error2ntstatus(ndr_err);
 		return status;
 	}
@@ -712,7 +706,7 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 	status = dbwrap_store(context->db.ctx,
 			      context->db.key_data,
 			      data, TDB_REPLACE);
-	TALLOC_FREE(creds);
+	TALLOC_FREE(data.dptr);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -1666,8 +1660,8 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
-	netlogon_creds_cli_check_cleanup(req, status);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
@@ -2018,7 +2012,8 @@ static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
 		return;
@@ -2514,7 +2509,9 @@ static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
 
 	*state->lk_creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->lk_creds);
+					  state->lk_creds);
+	TALLOC_FREE(state->lk_creds);
+
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
 		return;
@@ -2811,7 +2808,8 @@ static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tev
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
@@ -3077,7 +3075,8 @@ static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
 		return;
@@ -3359,7 +3358,8 @@ static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
@@ -3638,7 +3638,8 @@ static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
 
 	*state->creds = state->tmp_creds;
 	status = netlogon_creds_cli_store(state->context,
-					  &state->creds);
+					  state->creds);
+	TALLOC_FREE(state->creds);
 
 	if (tevent_req_nterror(req, status)) {
 		netlogon_creds_cli_SendToSam_cleanup(req, status);
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index fbc59f6fe57..e42f5f76a0f 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -68,7 +68,7 @@ bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
 			const struct netlogon_creds_CredentialState *creds1);
 
 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
-				  struct netlogon_creds_CredentialState **_creds);
+				  struct netlogon_creds_CredentialState *creds);
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 				   struct netlogon_creds_CredentialState **_creds);
 
-- 
2.11.0


From f18a7251a45cbe1d1a60bc2a77a4b065941c1c1c Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 10 Sep 2017 14:55:13 +0200
Subject: [PATCH 06/28] netlogon_creds_cli: Simplify netlogon_creds_cli_delete

Don't implicitly TALLOC_FREE(creds) in the pure delete routine

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 29 +++++++++++++++--------------
 libcli/auth/netlogon_creds_cli.h |  2 +-
 source3/rpc_client/cli_pipe.c    |  3 ++-
 3 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index a56a348edd2..f95c97bafb7 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -715,18 +715,14 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 }
 
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
-				   struct netlogon_creds_CredentialState **_creds)
+				   struct netlogon_creds_CredentialState *creds)
 {
-	struct netlogon_creds_CredentialState *creds = *_creds;
 	NTSTATUS status;
 
-	*_creds = NULL;
-
 	if (context->db.locked_state == NULL) {
 		/*
 		 * this was not the result of netlogon_creds_cli_lock*()
 		 */
-		TALLOC_FREE(creds);
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
@@ -734,13 +730,11 @@ NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 		/*
 		 * this was not the result of netlogon_creds_cli_lock*()
 		 */
-		TALLOC_FREE(creds);
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
 	status = dbwrap_delete(context->db.ctx,
 			       context->db.key_data);
-	TALLOC_FREE(creds);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -1470,7 +1464,8 @@ static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
@@ -1843,7 +1838,8 @@ static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
@@ -2225,7 +2221,8 @@ static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->lk_creds);
+	netlogon_creds_cli_delete(state->context, state->lk_creds);
+	TALLOC_FREE(state->lk_creds);
 }
 
 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
@@ -2689,7 +2686,8 @@ static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
@@ -2955,7 +2953,8 @@ static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
@@ -3241,7 +3240,8 @@ static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_r
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
@@ -3518,7 +3518,8 @@ static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, &state->creds);
+	netlogon_creds_cli_delete(state->context, state->creds);
+	TALLOC_FREE(state->creds);
 }
 
 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index e42f5f76a0f..8f473372760 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -70,7 +70,7 @@ bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 				  struct netlogon_creds_CredentialState *creds);
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
-				   struct netlogon_creds_CredentialState **_creds);
+				   struct netlogon_creds_CredentialState *creds);
 
 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 6cdb5df0bfd..07476c745fe 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3322,7 +3322,8 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	cli_credentials_set_netlogon_creds(cli_creds, NULL);
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
 		rpc_pipe_bind_dbglvl = 1;
-		netlogon_creds_cli_delete(netlogon_creds, &ncreds);
+		netlogon_creds_cli_delete(netlogon_creds, ncreds);
+		TALLOC_FREE(ncreds);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(rpc_pipe_bind_dbglvl,
-- 
2.11.0


From 349464c57187e11f1302e75f8f55d85f9d2f7b53 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 5 Sep 2017 13:37:56 +0200
Subject: [PATCH 07/28] netlogon_creds_cli: Remove unused code

According to metze this was meant for test code that never materialized

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 41 ----------------------------------------
 libcli/auth/netlogon_creds_cli.h | 10 ----------
 2 files changed, 51 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index f95c97bafb7..bfa9fa0c2c4 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -447,47 +447,6 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 	return NT_STATUS_OK;
 }
 
-NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
-				const char *client_account,
-				enum netr_SchannelType type,
-				uint32_t proposed_flags,
-				uint32_t required_flags,
-				enum dcerpc_AuthLevel auth_level,
-				const char *server_computer,
-				const char *server_netbios_domain,
-				TALLOC_CTX *mem_ctx,
-				struct netlogon_creds_cli_context **_context)
-{
-	NTSTATUS status;
-	struct netlogon_creds_cli_context *context = NULL;
-
-	*_context = NULL;
-
-	status = netlogon_creds_cli_context_common(client_computer,
-						   client_account,
-						   type,
-						   auth_level,
-						   proposed_flags,
-						   required_flags,
-						   server_computer,
-						   server_netbios_domain,
-						   "",
-						   mem_ctx,
-						   &context);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	context->db.ctx = db_open_rbt(context);
-	if (context->db.ctx == NULL) {
-		talloc_free(context);
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	*_context = context;
-	return NT_STATUS_OK;
-}
-
 char *netlogon_creds_cli_debug_string(
 		const struct netlogon_creds_cli_context *context,
 		TALLOC_CTX *mem_ctx)
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 8f473372760..1e7df6600cb 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -43,16 +43,6 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 				const char *server_dns_domain,
 				TALLOC_CTX *mem_ctx,
 				struct netlogon_creds_cli_context **_context);
-NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
-				const char *client_account,
-				enum netr_SchannelType type,
-				uint32_t proposed_flags,
-				uint32_t required_flags,
-				enum dcerpc_AuthLevel auth_level,
-				const char *server_computer,
-				const char *server_netbios_domain,
-				TALLOC_CTX *mem_ctx,
-				struct netlogon_creds_cli_context **_context);
 
 char *netlogon_creds_cli_debug_string(
 		const struct netlogon_creds_cli_context *context,
-- 
2.11.0


From 524d4f22a7007bd82662c8bafc123add39d9ed3f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 08:51:25 -0700
Subject: [PATCH 08/28] netlogon_creds_cli: Remove tevent_req handling from
 netlogon_creds_cli_lock_fetch

Disentangle concerns, make netlogon_creds_cli_lock_fetch usable for
other callers

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 47 ++++++++++++++++++++++------------------
 1 file changed, 26 insertions(+), 21 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index bfa9fa0c2c4..73d6bb97988 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -707,7 +707,9 @@ struct netlogon_creds_cli_lock_state {
 };
 
 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
-static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
+static NTSTATUS netlogon_creds_cli_lock_fetch(
+	struct netlogon_creds_cli_context *context,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
 
 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
@@ -741,8 +743,11 @@ struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 	state->locked_state = locked_state;
 
 	if (context->db.g_ctx == NULL) {
-		netlogon_creds_cli_lock_fetch(req);
-		if (!tevent_req_is_in_progress(req)) {
+		NTSTATUS status;
+
+		status = netlogon_creds_cli_lock_fetch(
+			context, state, &state->creds);
+		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
 		}
 
@@ -778,38 +783,39 @@ static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
 	}
 	state->locked_state->is_glocked = true;
 
-	netlogon_creds_cli_lock_fetch(req);
+	status = netlogon_creds_cli_lock_fetch(state->locked_state->context,
+					       state, &state->creds);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	tevent_req_done(req);
 }
 
-static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
+static NTSTATUS netlogon_creds_cli_lock_fetch(
+	struct netlogon_creds_cli_context *context,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
 {
-	struct netlogon_creds_cli_lock_state *state =
-		tevent_req_data(req,
-		struct netlogon_creds_cli_lock_state);
-	struct netlogon_creds_cli_context *context = state->locked_state->context;
 	struct netlogon_creds_cli_fetch_state fstate = {
 		.status = NT_STATUS_INTERNAL_ERROR,
 		.required_flags = context->client.required_flags,
 	};
 	NTSTATUS status;
 
-	fstate.mem_ctx = state;
+	fstate.mem_ctx = mem_ctx;
 	status = dbwrap_parse_record(context->db.ctx,
 				     context->db.key_data,
 				     netlogon_creds_cli_fetch_parser,
 				     &fstate);
-	if (tevent_req_nterror(req, status)) {
-		return;
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
 	}
-	status = fstate.status;
-	if (tevent_req_nterror(req, status)) {
-		return;
+	if (!NT_STATUS_IS_OK(fstate.status)) {
+		return fstate.status;
 	}
 
 	if (context->server.cached_flags == fstate.creds->negotiate_flags) {
-		state->creds = fstate.creds;
-		tevent_req_done(req);
-		return;
+		*pcreds = fstate.creds;
+		return NT_STATUS_OK;
 	}
 
 	context->server.cached_flags = fstate.creds->negotiate_flags;
@@ -825,9 +831,8 @@ static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
 		context->server.try_validation6 = false;
 	}
 
-	state->creds = fstate.creds;
-	tevent_req_done(req);
-	return;
+	*pcreds = fstate.creds;
+	return NT_STATUS_OK;
 }
 
 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
-- 
2.11.0


From 165213b9cb51d4d183f124e585b8d598d9d501b5 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 11:37:00 -0700
Subject: [PATCH 09/28] netlogon_creds_cli: Transfer a comment

This part of from netlogon_creds_cli_get will go

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 73d6bb97988..656a3786043 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -818,6 +818,38 @@ static NTSTATUS netlogon_creds_cli_lock_fetch(
 		return NT_STATUS_OK;
 	}
 
+	/*
+	 * It is really important to try SamLogonEx here,
+	 * because multiple processes can talk to the same
+	 * domain controller, without using the credential
+	 * chain.
+	 *
+	 * With a normal SamLogon call, we must keep the
+	 * credentials chain updated and intact between all
+	 * users of the machine account (which would imply
+	 * cross-node communication for every NTLM logon).
+	 *
+	 * The credentials chain is not per NETLOGON pipe
+	 * connection, but globally on the server/client pair
+	 * by computer name.
+	 *
+	 * It's also important to use NetlogonValidationSamInfo4 (6),
+	 * because it relies on the rpc transport encryption
+	 * and avoids using the global netlogon schannel
+	 * session key to en/decrypt secret information
+	 * like the user_session_key for network logons.
+	 *
+	 * [MS-APDS] 3.1.5.2 NTLM Network Logon
+	 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
+	 * NETLOGON_NEG_AUTHENTICATED_RPC set together
+	 * are the indication that the server supports
+	 * NetlogonValidationSamInfo4 (6). And it must only
+	 * be used if "SealSecureChannel" is used.
+	 *
+	 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
+	 * check is done in netlogon_creds_cli_LogonSamLogon*().
+	 */
+
 	context->server.cached_flags = fstate.creds->negotiate_flags;
 	context->server.try_validation6 = true;
 	context->server.try_logon_ex = true;
-- 
2.11.0


From 4462c80614c1a115a71c301674ea234afc1b0887 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 11:38:11 -0700
Subject: [PATCH 10/28] netlogon_creds_cli: Rename
 netlogon_creds_cli_lock_fetch->get_internal

---
 libcli/auth/netlogon_creds_cli.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 656a3786043..6b044cd0bb9 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -707,7 +707,7 @@ struct netlogon_creds_cli_lock_state {
 };
 
 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
-static NTSTATUS netlogon_creds_cli_lock_fetch(
+static NTSTATUS netlogon_creds_cli_get_internal(
 	struct netlogon_creds_cli_context *context,
 	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
 
@@ -745,7 +745,7 @@ struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 	if (context->db.g_ctx == NULL) {
 		NTSTATUS status;
 
-		status = netlogon_creds_cli_lock_fetch(
+		status = netlogon_creds_cli_get_internal(
 			context, state, &state->creds);
 		if (tevent_req_nterror(req, status)) {
 			return tevent_req_post(req, ev);
@@ -783,7 +783,7 @@ static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
 	}
 	state->locked_state->is_glocked = true;
 
-	status = netlogon_creds_cli_lock_fetch(state->locked_state->context,
+	status = netlogon_creds_cli_get_internal(state->locked_state->context,
 					       state, &state->creds);
 	if (tevent_req_nterror(req, status)) {
 		return;
@@ -791,7 +791,7 @@ static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-static NTSTATUS netlogon_creds_cli_lock_fetch(
+static NTSTATUS netlogon_creds_cli_get_internal(
 	struct netlogon_creds_cli_context *context,
 	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
 {
-- 
2.11.0


From b620d246b3127c48f20933993d7ba119e758b806 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 11:40:24 -0700
Subject: [PATCH 11/28] netlogon_creds_cli: Simplify netlogon_creds_cli_get

netlogon_creds_cli_get_internal almost does everything needed, only
the invalidating for credential chain use is missing.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 81 ++++++----------------------------------
 1 file changed, 11 insertions(+), 70 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 6b044cd0bb9..7a6c630b78c 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -506,27 +506,20 @@ static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
 	state->status = NT_STATUS_OK;
 }
 
+static NTSTATUS netlogon_creds_cli_get_internal(
+	struct netlogon_creds_cli_context *context,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
+
 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
 				TALLOC_CTX *mem_ctx,
 				struct netlogon_creds_CredentialState **_creds)
 {
 	NTSTATUS status;
-	struct netlogon_creds_cli_fetch_state fstate = {
-		.mem_ctx = mem_ctx,
-		.status = NT_STATUS_INTERNAL_ERROR,
-		.required_flags = context->client.required_flags,
-	};
+	struct netlogon_creds_CredentialState *creds;
 
 	*_creds = NULL;
 
-	status = dbwrap_parse_record(context->db.ctx,
-				     context->db.key_data,
-				     netlogon_creds_cli_fetch_parser,
-				     &fstate);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-	status = fstate.status;
+	status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
@@ -534,61 +527,12 @@ NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
 	/*
 	 * mark it as invalid for step operations.
 	 */
-	fstate.creds->sequence = 0;
-	fstate.creds->seed = (struct netr_Credential) {{0}};
-	fstate.creds->client = (struct netr_Credential) {{0}};
-	fstate.creds->server = (struct netr_Credential) {{0}};
-
-	if (context->server.cached_flags == fstate.creds->negotiate_flags) {
-		*_creds = fstate.creds;
-		return NT_STATUS_OK;
-	}
+	creds->sequence = 0;
+	creds->seed = (struct netr_Credential) {{0}};
+	creds->client = (struct netr_Credential) {{0}};
+	creds->server = (struct netr_Credential) {{0}};
 
-	/*
-	 * It is really important to try SamLogonEx here,
-	 * because multiple processes can talk to the same
-	 * domain controller, without using the credential
-	 * chain.
-	 *
-	 * With a normal SamLogon call, we must keep the
-	 * credentials chain updated and intact between all
-	 * users of the machine account (which would imply
-	 * cross-node communication for every NTLM logon).
-	 *
-	 * The credentials chain is not per NETLOGON pipe
-	 * connection, but globally on the server/client pair
-	 * by computer name.
-	 *
-	 * It's also important to use NetlogonValidationSamInfo4 (6),
-	 * because it relies on the rpc transport encryption
-	 * and avoids using the global netlogon schannel
-	 * session key to en/decrypt secret information
-	 * like the user_session_key for network logons.
-	 *
-	 * [MS-APDS] 3.1.5.2 NTLM Network Logon
-	 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
-	 * NETLOGON_NEG_AUTHENTICATED_RPC set together
-	 * are the indication that the server supports
-	 * NetlogonValidationSamInfo4 (6). And it must only
-	 * be used if "SealSecureChannel" is used.
-	 *
-	 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
-	 * check is done in netlogon_creds_cli_LogonSamLogon*().
-	 */
-	context->server.cached_flags = fstate.creds->negotiate_flags;
-	context->server.try_validation6 = true;
-	context->server.try_logon_ex = true;
-	context->server.try_logon_with = true;
-
-	if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
-		context->server.try_validation6 = false;
-		context->server.try_logon_ex = false;
-	}
-	if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
-		context->server.try_validation6 = false;
-	}
-
-	*_creds = fstate.creds;
+	*_creds = creds;
 	return NT_STATUS_OK;
 }
 
@@ -707,9 +651,6 @@ struct netlogon_creds_cli_lock_state {
 };
 
 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
-static NTSTATUS netlogon_creds_cli_get_internal(
-	struct netlogon_creds_cli_context *context,
-	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
 
 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
-- 
2.11.0


From e643e2ca1b090b63df4478d368445b719150e3dc Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 10 Sep 2017 19:11:21 +0200
Subject: [PATCH 12/28] netlogon_creds_cli: Print
 netlogon_creds_CredentialState

Add some debugging for the tdb records

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 7a6c630b78c..178d9c88b92 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -495,6 +495,10 @@ static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
 		return;
 	}
 
+	if (DEBUGLEVEL >= 10) {
+		NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
+	}
+
 	tmp_flags = state->creds->negotiate_flags;
 	tmp_flags &= state->required_flags;
 	if (tmp_flags != state->required_flags) {
@@ -596,6 +600,10 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
+	if (DEBUGLEVEL >= 10) {
+		NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
+	}
+
 	ndr_err = ndr_push_struct_blob(&blob, creds, creds,
 		(ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
 	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-- 
2.11.0


From c5e200123b8e0bb67e868f077ee85263efc88286 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 09:32:36 -0700
Subject: [PATCH 13/28] netlogon_creds_cli: Factor out
 netlogon_creds_cli_store_internal

In a future commit we'll need a version that does not check for
context->db.locked_state

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 42 +++++++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 178d9c88b92..f1aa8d03ca5 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -578,28 +578,15 @@ bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
 	return (cmp == 0);
 }
 
-NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
-				  struct netlogon_creds_CredentialState *creds)
+static NTSTATUS netlogon_creds_cli_store_internal(
+	struct netlogon_creds_cli_context *context,
+	struct netlogon_creds_CredentialState *creds)
 {
 	NTSTATUS status;
 	enum ndr_err_code ndr_err;
 	DATA_BLOB blob;
 	TDB_DATA data;
 
-	if (context->db.locked_state == NULL) {
-		/*
-		 * this was not the result of netlogon_creds_cli_lock*()
-		 */
-		return NT_STATUS_INVALID_PAGE_PROTECTION;
-	}
-
-	if (context->db.locked_state->creds != creds) {
-		/*
-		 * this was not the result of netlogon_creds_cli_lock*()
-		 */
-		return NT_STATUS_INVALID_PAGE_PROTECTION;
-	}
-
 	if (DEBUGLEVEL >= 10) {
 		NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
 	}
@@ -625,6 +612,29 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
+				  struct netlogon_creds_CredentialState *creds)
+{
+	NTSTATUS status;
+
+	if (context->db.locked_state == NULL) {
+		/*
+		 * this was not the result of netlogon_creds_cli_lock*()
+		 */
+		return NT_STATUS_INVALID_PAGE_PROTECTION;
+	}
+
+	if (context->db.locked_state->creds != creds) {
+		/*
+		 * this was not the result of netlogon_creds_cli_lock*()
+		 */
+		return NT_STATUS_INVALID_PAGE_PROTECTION;
+	}
+
+	status = netlogon_creds_cli_store_internal(context, creds);
+	return status;
+}
+
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 				   struct netlogon_creds_CredentialState *creds)
 {
-- 
2.11.0


From 85f1c2d48bda89f931065138954e451fda230c76 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 09:33:56 -0700
Subject: [PATCH 14/28] netlogon_creds_cli: Factor out
 netlogon_creds_cli_delete_internal

In a future commit we'll need a version that does not check for
context->db.locked_state

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 17 ++++++++++-------
 1 file changed, 10 insertions(+), 7 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index f1aa8d03ca5..c3b302addc4 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -635,6 +635,14 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 	return status;
 }
 
+static NTSTATUS netlogon_creds_cli_delete_internal(
+	struct netlogon_creds_cli_context *context)
+{
+	NTSTATUS status;
+	status = dbwrap_delete(context->db.ctx, context->db.key_data);
+	return status;
+}
+
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 				   struct netlogon_creds_CredentialState *creds)
 {
@@ -654,13 +662,8 @@ NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 		return NT_STATUS_INVALID_PAGE_PROTECTION;
 	}
 
-	status = dbwrap_delete(context->db.ctx,
-			       context->db.key_data);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	return NT_STATUS_OK;
+	status = netlogon_creds_cli_delete_internal(context);
+	return status;
 }
 
 struct netlogon_creds_cli_lock_state {
-- 
2.11.0


From 8a4f14dadbad4fec7d5e947efd541edebbe5fb80 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 7 Sep 2017 12:36:14 +0200
Subject: [PATCH 15/28] netlogon_creds_cli: Create cli_credentials from
 netlogon creds ctx

A netlogon_creds_cli_context holds all information required to do an
schannel bind. Used in the next commit.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 32 ++++++++++++++++++++++++++++++++
 libcli/auth/netlogon_creds_cli.h |  4 ++++
 2 files changed, 36 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index c3b302addc4..25f14316dc2 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -38,6 +38,7 @@
 #include "source3/include/g_lock.h"
 #include "libds/common/roles.h"
 #include "lib/crypto/crypto.h"
+#include "auth/credentials/credentials.h"
 
 struct netlogon_creds_cli_locked_state;
 
@@ -447,6 +448,37 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 	return NT_STATUS_OK;
 }
 
+NTSTATUS netlogon_creds_bind_cli_credentials(
+	struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+	struct cli_credentials **pcli_creds)
+{
+	struct cli_credentials *cli_creds;
+	struct netlogon_creds_CredentialState *ncreds;
+	NTSTATUS status;
+
+	cli_creds = cli_credentials_init(mem_ctx);
+	if (cli_creds == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	cli_credentials_set_secure_channel_type(cli_creds,
+						context->client.type);
+	cli_credentials_set_username(cli_creds, context->client.account,
+				     CRED_SPECIFIED);
+	cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
+				   CRED_SPECIFIED);
+	cli_credentials_set_realm(cli_creds, context->server.dns_domain,
+				  CRED_SPECIFIED);
+
+	status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
+	if (!NT_STATUS_IS_OK(status)) {
+		TALLOC_FREE(cli_creds);
+		return status;
+	}
+
+	*pcli_creds = cli_creds;
+	return NT_STATUS_OK;
+}
+
 char *netlogon_creds_cli_debug_string(
 		const struct netlogon_creds_cli_context *context,
 		TALLOC_CTX *mem_ctx)
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 1e7df6600cb..7664387ab95 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -26,6 +26,7 @@
 #include "librpc/gen_ndr/schannel.h"
 
 struct netlogon_creds_cli_context;
+struct cli_credentials;
 struct messaging_context;
 struct dcerpc_binding_handle;
 struct db_context;
@@ -43,6 +44,9 @@ NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
 				const char *server_dns_domain,
 				TALLOC_CTX *mem_ctx,
 				struct netlogon_creds_cli_context **_context);
+NTSTATUS netlogon_creds_bind_cli_credentials(
+	struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
+	struct cli_credentials **pcli_creds);
 
 char *netlogon_creds_cli_debug_string(
 		const struct netlogon_creds_cli_context *context,
-- 
2.11.0


From f75682897df88ec150e0069c4b272f424ad32919 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Thu, 7 Sep 2017 12:43:00 +0200
Subject: [PATCH 16/28] rpc_client3: Avoid "cli_credentials" in
 cli_rpc_pipe_open_schannel_with_creds

This provides cleaner data dependencies. A netlogon_creds_ctx contains
everything required to open an schannel, there is no good reason to
require cli_credentials here.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c       |  1 +
 source3/libnet/libnet_join.c           |  1 -
 source3/rpc_client/cli_pipe.c          | 17 ++++++++++++++---
 source3/rpc_client/cli_pipe.h          |  1 -
 source3/rpc_client/cli_pipe_schannel.c |  1 -
 source3/winbindd/winbindd_cm.c         | 14 ++++++--------
 6 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 25f14316dc2..3209f6cf871 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -474,6 +474,7 @@ NTSTATUS netlogon_creds_bind_cli_credentials(
 		TALLOC_FREE(cli_creds);
 		return status;
 	}
+	cli_credentials_set_netlogon_creds(cli_creds, ncreds);
 
 	*pcli_creds = cli_creds;
 	return NT_STATUS_OK;
diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c
index 5880913a39f..eb6b894908f 100644
--- a/source3/libnet/libnet_join.c
+++ b/source3/libnet/libnet_join.c
@@ -1662,7 +1662,6 @@ NTSTATUS libnet_join_ok(struct messaging_context *msg_ctx,
 
 	status = cli_rpc_pipe_open_schannel_with_creds(
 		cli, &ndr_table_netlogon, NCACN_NP,
-		cli_creds,
 		netlogon_creds, &netlogon_pipe);
 
 	TALLOC_FREE(netlogon_pipe);
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 07476c745fe..5e87bad46a2 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3275,7 +3275,6 @@ NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 					       const struct ndr_interface_table *table,
 					       enum dcerpc_transport_t transport,
-					       struct cli_credentials *cli_creds,
 					       struct netlogon_creds_cli_context *netlogon_creds,
 					       struct rpc_pipe_client **_rpccli)
 {
@@ -3283,6 +3282,7 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	struct pipe_auth_data *rpcauth;
 	const char *target_service = table->authservices->names[0];
 	struct netlogon_creds_CredentialState *ncreds = NULL;
+	struct cli_credentials *cli_creds;
 	enum dcerpc_AuthLevel auth_level;
 	NTSTATUS status;
 	int rpc_pipe_bind_dbglvl = 0;
@@ -3302,7 +3302,14 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 
 	auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
 
-	cli_credentials_set_netlogon_creds(cli_creds, ncreds);
+	status = netlogon_creds_bind_cli_credentials(
+		netlogon_creds, rpccli, &cli_creds);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("netlogon_creds_bind_cli_credentials failed: %s\n",
+			  nt_errstr(status));
+		TALLOC_FREE(rpccli);
+		return status;
+	}
 
 	status = rpccli_generic_bind_data_from_creds(rpccli,
 						     DCERPC_AUTH_TYPE_SCHANNEL,
@@ -3319,7 +3326,11 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	}
 
 	status = rpc_pipe_bind(rpccli, rpcauth);
-	cli_credentials_set_netlogon_creds(cli_creds, NULL);
+
+	/* No TALLOC_FREE, gensec takes references */
+	talloc_unlink(rpccli, cli_creds);
+	cli_creds = NULL;
+
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
 		rpc_pipe_bind_dbglvl = 1;
 		netlogon_creds_cli_delete(netlogon_creds, ncreds);
diff --git a/source3/rpc_client/cli_pipe.h b/source3/rpc_client/cli_pipe.h
index 2290d62b49d..5df43c57e95 100644
--- a/source3/rpc_client/cli_pipe.h
+++ b/source3/rpc_client/cli_pipe.h
@@ -102,7 +102,6 @@ NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 					       const struct ndr_interface_table *table,
 					       enum dcerpc_transport_t transport,
-					       struct cli_credentials *cli_creds,
 					       struct netlogon_creds_cli_context *netlogon_creds,
 					       struct rpc_pipe_client **_rpccli);
 
diff --git a/source3/rpc_client/cli_pipe_schannel.c b/source3/rpc_client/cli_pipe_schannel.c
index a94429538c7..8a8177be2e5 100644
--- a/source3/rpc_client/cli_pipe_schannel.c
+++ b/source3/rpc_client/cli_pipe_schannel.c
@@ -93,7 +93,6 @@ NTSTATUS cli_rpc_pipe_open_schannel(struct cli_state *cli,
 	if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
 		status = cli_rpc_pipe_open_schannel_with_creds(cli, table,
 							       transport,
-							       cli_creds,
 							       netlogon_creds,
 							       &result);
 		if (!NT_STATUS_IS_OK(status)) {
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index afde0c87b7a..a5e5ab3f4e3 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -2771,9 +2771,9 @@ retry:
 			   nt_errstr(result)));
 		goto anonymous;
 	}
-	status = cli_rpc_pipe_open_schannel_with_creds
-		(conn->cli, &ndr_table_samr, NCACN_NP,
-		 creds, p_creds, &conn->samr_pipe);
+	status = cli_rpc_pipe_open_schannel_with_creds(
+		conn->cli, &ndr_table_samr, NCACN_NP, p_creds,
+		&conn->samr_pipe);
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)
 	    && !retry) {
@@ -2950,7 +2950,6 @@ static NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 	status = cli_rpc_pipe_open_schannel_with_creds(conn->cli,
 						       &ndr_table_lsarpc,
 						       NCACN_IP_TCP,
-						       creds,
 						       p_creds,
 						       &conn->lsa_pipe_tcp);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -3077,9 +3076,9 @@ retry:
 			   nt_errstr(result)));
 		goto anonymous;
 	}
-	result = cli_rpc_pipe_open_schannel_with_creds
-		(conn->cli, &ndr_table_lsarpc, NCACN_NP,
-		 creds, p_creds, &conn->lsa_pipe);
+	result = cli_rpc_pipe_open_schannel_with_creds(
+		conn->cli, &ndr_table_lsarpc, NCACN_NP, p_creds,
+		&conn->lsa_pipe);
 
 	if (NT_STATUS_EQUAL(result, NT_STATUS_NETWORK_SESSION_EXPIRED)
 	    && !retry) {
@@ -3343,7 +3342,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 
 	result = cli_rpc_pipe_open_schannel_with_creds(
 		conn->cli, &ndr_table_netlogon, transport,
-		creds,
 		conn->netlogon_creds_ctx,
 		&conn->netlogon_pipe);
 	if (!NT_STATUS_IS_OK(result)) {
-- 
2.11.0


From 0bbb14a6ebe90d17c95cdee24aa59df907f5463e Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 11 Sep 2017 16:48:27 -0700
Subject: [PATCH 17/28] netlogon_creds_cli: Add netlogon_creds_cli_lck

This adds an external locking scheme to protect our
netlogon_creds_CredentialState. This is needed because the routines
exposed by netlogon_creds_cli.h need a more flexible locking to
set up our credentials in a properly protected way.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 143 +++++++++++++++++++++++++++++++++++++++
 libcli/auth/netlogon_creds_cli.h |  20 ++++++
 2 files changed, 163 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 3209f6cf871..06d7260c8b6 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -68,6 +68,7 @@ struct netlogon_creds_cli_context {
 		struct db_context *ctx;
 		struct g_lock_ctx *g_ctx;
 		struct netlogon_creds_cli_locked_state *locked_state;
+		enum netlogon_creds_cli_lck_type lock;
 	} db;
 };
 
@@ -909,6 +910,148 @@ NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
 	return status;
 }
 
+struct netlogon_creds_cli_lck {
+	struct netlogon_creds_cli_context *context;
+};
+
+struct netlogon_creds_cli_lck_state {
+	struct netlogon_creds_cli_lck *lck;
+	enum netlogon_creds_cli_lck_type type;
+};
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
+static int netlogon_creds_cli_lck_destructor(
+	struct netlogon_creds_cli_lck *lck);
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct netlogon_creds_cli_context *context,
+	enum netlogon_creds_cli_lck_type type)
+{
+	struct tevent_req *req, *subreq;
+	struct netlogon_creds_cli_lck_state *state;
+	enum g_lock_type gtype;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct netlogon_creds_cli_lck_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
+		DBG_DEBUG("context already locked\n");
+		tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+		return tevent_req_post(req, ev);
+	}
+
+	switch (type) {
+	    case NETLOGON_CREDS_CLI_LCK_SHARED:
+		    gtype = G_LOCK_READ;
+		    break;
+	    case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
+		    gtype = G_LOCK_WRITE;
+		    break;
+	    default:
+		    tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		    return tevent_req_post(req, ev);
+	}
+
+	state->lck = talloc(state, struct netlogon_creds_cli_lck);
+	if (tevent_req_nomem(state->lck, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->lck->context = context;
+	state->type = type;
+
+	subreq = g_lock_lock_send(state, ev,
+				  context->db.g_ctx,
+				  context->db.key_name,
+				  gtype);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
+
+	return req;
+}
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+		req, struct netlogon_creds_cli_lck_state);
+	NTSTATUS status;
+
+	status = g_lock_lock_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	state->lck->context->db.lock = state->type;
+	talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
+
+	tevent_req_done(req);
+}
+
+static int netlogon_creds_cli_lck_destructor(
+	struct netlogon_creds_cli_lck *lck)
+{
+	struct netlogon_creds_cli_context *ctx = lck->context;
+	NTSTATUS status;
+
+	status = g_lock_unlock(ctx->db.g_ctx, ctx->db.key_name);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
+		smb_panic("g_lock_unlock failed");
+	}
+	ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
+	return 0;
+}
+
+NTSTATUS netlogon_creds_cli_lck_recv(
+	struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	struct netlogon_creds_cli_lck **lck)
+{
+	struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+		req, struct netlogon_creds_cli_lck_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		return status;
+	}
+	*lck = talloc_move(mem_ctx, &state->lck);
+	return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lck(
+	struct netlogon_creds_cli_context *context,
+	enum netlogon_creds_cli_lck_type type,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = netlogon_creds_cli_lck_send(frame, ev, context, type);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+		goto fail;
+	}
+	status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
+ fail:
+	TALLOC_FREE(frame);
+	return status;
+}
+
 struct netlogon_creds_cli_auth_state {
 	struct tevent_context *ev;
 	struct netlogon_creds_cli_context *context;
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 7664387ab95..b3e30eb67bf 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -76,6 +76,26 @@ NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
 			TALLOC_CTX *mem_ctx,
 			struct netlogon_creds_CredentialState **creds);
 
+struct netlogon_creds_cli_lck;
+
+enum netlogon_creds_cli_lck_type {
+	NETLOGON_CREDS_CLI_LCK_NONE,
+	NETLOGON_CREDS_CLI_LCK_SHARED,
+	NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+};
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct netlogon_creds_cli_context *context,
+	enum netlogon_creds_cli_lck_type type);
+NTSTATUS netlogon_creds_cli_lck_recv(
+	struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	struct netlogon_creds_cli_lck **lck);
+NTSTATUS netlogon_creds_cli_lck(
+	struct netlogon_creds_cli_context *context,
+	enum netlogon_creds_cli_lck_type type,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck);
+
 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
-- 
2.11.0


From c592282a8b1165b66ed902954ff6323ae73d9d3f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 15 Sep 2017 19:39:01 -0700
Subject: [PATCH 18/28] netlogon_creds_cli: Add netlogon_creds_cli_delete_lck

Like netlogon_creds_cli_delete, protected by netlogon_creds_cli_lck
instead of netlogon_creds_cli_lock.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 13 +++++++++++++
 libcli/auth/netlogon_creds_cli.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 06d7260c8b6..248fb371fed 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -677,6 +677,19 @@ static NTSTATUS netlogon_creds_cli_delete_internal(
 	return status;
 }
 
+NTSTATUS netlogon_creds_cli_delete_lck(
+	struct netlogon_creds_cli_context *context)
+{
+	NTSTATUS status;
+
+	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+		return NT_STATUS_NOT_LOCKED;
+	}
+
+	status = netlogon_creds_cli_delete_internal(context);
+	return status;
+}
+
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 				   struct netlogon_creds_CredentialState *creds)
 {
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index b3e30eb67bf..62d11ac283e 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -65,6 +65,8 @@ NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
 				  struct netlogon_creds_CredentialState *creds);
 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 				   struct netlogon_creds_CredentialState *creds);
+NTSTATUS netlogon_creds_cli_delete_lck(
+	struct netlogon_creds_cli_context *context);
 
 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
-- 
2.11.0


From ed4b9775075ed48dca4a7d1999f72207c40ae19a Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 09:40:57 -0700
Subject: [PATCH 19/28] netlogon_creds_cli: Protect netlogon_creds_cli_check by
 _lck

netlogon_creds_cli_lck provides the locking around the operation

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 101 +++++++++++++++------------------------
 source3/rpc_client/cli_pipe.c    |  18 +++----
 2 files changed, 47 insertions(+), 72 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 248fb371fed..081b18efb0e 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -1525,14 +1525,13 @@ struct netlogon_creds_cli_check_state {
 	union netr_Capabilities caps;
 
 	struct netlogon_creds_CredentialState *creds;
-	struct netlogon_creds_CredentialState tmp_creds;
 	struct netr_Authenticator req_auth;
 	struct netr_Authenticator rep_auth;
 };
 
 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
 					     NTSTATUS status);
-static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
 
 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
@@ -1544,6 +1543,7 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 	struct tevent_req *subreq;
 	enum dcerpc_AuthType auth_type;
 	enum dcerpc_AuthLevel auth_level;
+	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct netlogon_creds_cli_check_state);
@@ -1555,6 +1555,17 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 	state->context = context;
 	state->binding_handle = b;
 
+	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+		tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+		return tevent_req_post(req, ev);
+	}
+
+	status = netlogon_creds_cli_get_internal(context, state,
+						 &state->creds);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
 						context->server.computer);
 	if (tevent_req_nomem(state->srv_name_slash, req)) {
@@ -1578,14 +1589,29 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	subreq = netlogon_creds_cli_lock_send(state, state->ev,
-					      state->context);
+	/*
+	 * we defer all callbacks in order to cleanup
+	 * the database record.
+	 */
+	tevent_req_defer_callback(req, state->ev);
+
+	netlogon_creds_client_authenticator(state->creds, &state->req_auth);
+	ZERO_STRUCT(state->rep_auth);
+
+	subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
+						state->binding_handle,
+						state->srv_name_slash,
+						state->context->client.computer,
+						&state->req_auth,
+						&state->rep_auth,
+						1,
+						&state->caps);
 	if (tevent_req_nomem(subreq, req)) {
 		return tevent_req_post(req, ev);
 	}
 
 	tevent_req_set_callback(subreq,
-				netlogon_creds_cli_check_locked,
+				netlogon_creds_cli_check_caps,
 				req);
 
 	return req;
@@ -1611,58 +1637,10 @@ static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
 		return;
 	}
 
-	netlogon_creds_cli_delete(state->context, state->creds);
+	netlogon_creds_cli_delete_lck(state->context);
 	TALLOC_FREE(state->creds);
 }
 
-static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
-
-static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
-{
-	struct tevent_req *req =
-		tevent_req_callback_data(subreq,
-		struct tevent_req);
-	struct netlogon_creds_cli_check_state *state =
-		tevent_req_data(req,
-		struct netlogon_creds_cli_check_state);
-	NTSTATUS status;
-
-	status = netlogon_creds_cli_lock_recv(subreq, state,
-					      &state->creds);
-	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		return;
-	}
-
-	/*
-	 * we defer all callbacks in order to cleanup
-	 * the database record.
-	 */
-	tevent_req_defer_callback(req, state->ev);
-
-	state->tmp_creds = *state->creds;
-	netlogon_creds_client_authenticator(&state->tmp_creds,
-					    &state->req_auth);
-	ZERO_STRUCT(state->rep_auth);
-
-	subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
-						state->binding_handle,
-						state->srv_name_slash,
-						state->context->client.computer,
-						&state->req_auth,
-						&state->rep_auth,
-						1,
-						&state->caps);
-	if (tevent_req_nomem(subreq, req)) {
-		status = NT_STATUS_NO_MEMORY;
-		netlogon_creds_cli_check_cleanup(req, status);
-		return;
-	}
-	tevent_req_set_callback(subreq,
-				netlogon_creds_cli_check_caps,
-				req);
-}
-
 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 {
 	struct tevent_req *req =
@@ -1683,7 +1661,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 		 * Note that the negotiated flags are already checked
 		 * for our required flags after the ServerAuthenticate3/2 call.
 		 */
-		uint32_t negotiated = state->tmp_creds.negotiate_flags;
+		uint32_t negotiated = state->creds->negotiate_flags;
 
 		if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
 			/*
@@ -1738,7 +1716,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 		 * Note that the negotiated flags are already checked
 		 * for our required flags after the ServerAuthenticate3/2 call.
 		 */
-		uint32_t negotiated = state->tmp_creds.negotiate_flags;
+		uint32_t negotiated = state->creds->negotiate_flags;
 
 		if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
 			/*
@@ -1764,8 +1742,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 		return;
 	}
 
-	ok = netlogon_creds_client_check(&state->tmp_creds,
-					 &state->rep_auth.cred);
+	ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
 	if (!ok) {
 		status = NT_STATUS_ACCESS_DENIED;
 		tevent_req_nterror(req, status);
@@ -1778,7 +1755,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 		return;
 	}
 
-	if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
+	if (state->caps.server_capabilities != state->creds->negotiate_flags) {
 		status = NT_STATUS_DOWNGRADE_DETECTED;
 		tevent_req_nterror(req, status);
 		netlogon_creds_cli_check_cleanup(req, status);
@@ -1800,10 +1777,8 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 		return;
 	}
 
-	*state->creds = state->tmp_creds;
-	status = netlogon_creds_cli_store(state->context,
-					  state->creds);
-	TALLOC_FREE(state->creds);
+	status = netlogon_creds_cli_store_internal(state->context,
+						   state->creds);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 5e87bad46a2..710d95a0316 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3281,21 +3281,23 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	struct rpc_pipe_client *rpccli;
 	struct pipe_auth_data *rpcauth;
 	const char *target_service = table->authservices->names[0];
-	struct netlogon_creds_CredentialState *ncreds = NULL;
 	struct cli_credentials *cli_creds;
 	enum dcerpc_AuthLevel auth_level;
 	NTSTATUS status;
 	int rpc_pipe_bind_dbglvl = 0;
+	struct netlogon_creds_cli_lck *lck;
 
 	status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-	status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
+	status = netlogon_creds_cli_lck(
+		netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+		rpccli, &lck);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("netlogon_creds_cli_lock returned %s\n",
-			  nt_errstr(status)));
+		DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
+			    nt_errstr(status));
 		TALLOC_FREE(rpccli);
 		return status;
 	}
@@ -3333,8 +3335,7 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 
 	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
 		rpc_pipe_bind_dbglvl = 1;
-		netlogon_creds_cli_delete(netlogon_creds, ncreds);
-		TALLOC_FREE(ncreds);
+		netlogon_creds_cli_delete_lck(netlogon_creds);
 	}
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(rpc_pipe_bind_dbglvl,
@@ -3344,8 +3345,6 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 		return status;
 	}
 
-	TALLOC_FREE(ncreds);
-
 	if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
 		goto done;
 	}
@@ -3359,13 +3358,14 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 		return status;
 	}
 
-
 done:
 	DEBUG(10,("%s: opened pipe %s to machine %s "
 		  "for domain %s and bound using schannel.\n",
 		  __func__, table->name,
 		  rpccli->desthost, cli_credentials_get_domain(cli_creds)));
 
+	TALLOC_FREE(lck);
+
 	*_rpccli = rpccli;
 	return NT_STATUS_OK;
 }
-- 
2.11.0


From 95b68bd0e2b47d130e49f37345140c41cebd0d5d Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Wed, 13 Sep 2017 11:51:47 -0700
Subject: [PATCH 20/28] netlogon_creds_cli: Protect netlogon_creds_cli_auth by
 _lck

This widens the lock range to cover the check for established
credentials. Before this patch it could happen that more than one
winbind finds no credentials and does the auth3. This can pile up.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c  | 62 ++-------------------------------------
 source3/libsmb/trusts_util.c      | 46 ++++++++++++++++++++++++-----
 source3/rpc_client/cli_netlogon.c | 13 ++++++++
 3 files changed, 53 insertions(+), 68 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 081b18efb0e..31bd98ddc94 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -1084,10 +1084,8 @@ struct netlogon_creds_cli_auth_state {
 	bool try_auth3;
 	bool try_auth2;
 	bool require_auth2;
-	struct netlogon_creds_cli_locked_state *locked_state;
 };
 
-static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
 
 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
@@ -1099,7 +1097,6 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 {
 	struct tevent_req *req;
 	struct netlogon_creds_cli_auth_state *state;
-	struct netlogon_creds_cli_locked_state *locked_state;
 	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state,
@@ -1124,21 +1121,10 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 	state->idx_nt_hashes = 0;
 	state->nt_hashes = nt_hashes;
 
-	if (context->db.locked_state != NULL) {
-		tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
-		return tevent_req_post(req, ev);
-	}
-
-	locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
-	if (tevent_req_nomem(locked_state, req)) {
+	if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+		tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
 		return tevent_req_post(req, ev);
 	}
-	talloc_set_destructor(locked_state,
-			      netlogon_creds_cli_locked_state_destructor);
-	locked_state->context = context;
-
-	context->db.locked_state = locked_state;
-	state->locked_state = locked_state;
 
 	state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
 						context->server.computer);
@@ -1156,23 +1142,6 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 	state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
 	state->current_flags = context->client.proposed_flags;
 
-	if (context->db.g_ctx != NULL) {
-		struct tevent_req *subreq;
-
-		subreq = g_lock_lock_send(state, ev,
-					  context->db.g_ctx,
-					  context->db.key_name,
-					  G_LOCK_WRITE);
-		if (tevent_req_nomem(subreq, req)) {
-			return tevent_req_post(req, ev);
-		}
-		tevent_req_set_callback(subreq,
-					netlogon_creds_cli_auth_locked,
-					req);
-
-		return req;
-	}
-
 	status = dbwrap_purge(state->context->db.ctx,
 			      state->context->db.key_data);
 	if (tevent_req_nterror(req, status)) {
@@ -1187,32 +1156,6 @@ struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
 	return req;
 }
 
-static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
-{
-	struct tevent_req *req =
-		tevent_req_callback_data(subreq,
-		struct tevent_req);
-	struct netlogon_creds_cli_auth_state *state =
-		tevent_req_data(req,
-		struct netlogon_creds_cli_auth_state);
-	NTSTATUS status;
-
-	status = g_lock_lock_recv(subreq);
-	TALLOC_FREE(subreq);
-	if (tevent_req_nterror(req, status)) {
-		return;
-	}
-	state->locked_state->is_glocked = true;
-
-	status = dbwrap_purge(state->context->db.ctx,
-			      state->context->db.key_data);
-	if (tevent_req_nterror(req, status)) {
-		return;
-	}
-
-	netlogon_creds_cli_auth_challenge_start(req);
-}
-
 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
 
 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
@@ -1456,7 +1399,6 @@ static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
 	status = dbwrap_store(state->context->db.ctx,
 			      state->context->db.key_data,
 			      data, TDB_REPLACE);
-	TALLOC_FREE(state->locked_state);
 	if (tevent_req_nterror(req, status)) {
 		return;
 	}
diff --git a/source3/libsmb/trusts_util.c b/source3/libsmb/trusts_util.c
index 57cd542e08a..27e77e6cc60 100644
--- a/source3/libsmb/trusts_util.c
+++ b/source3/libsmb/trusts_util.c
@@ -104,6 +104,36 @@ char *trust_pw_new_value(TALLOC_CTX *mem_ctx,
 	return generate_random_machine_password(mem_ctx, min, max);
 }
 
+/*
+ * Temporary function to wrap cli_auth in a lck
+ */
+
+static NTSTATUS netlogon_creds_cli_lck_auth(
+	struct netlogon_creds_cli_context *context,
+	struct dcerpc_binding_handle *b,
+	uint8_t num_nt_hashes,
+	const struct samr_Password * const *nt_hashes,
+	uint8_t *idx_nt_hashes)
+{
+	struct netlogon_creds_cli_lck *lck;
+	NTSTATUS status;
+
+	status = netlogon_creds_cli_lck(
+		context, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+		talloc_tos(), &lck);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
+			    nt_errstr(status));
+		return status;
+	}
+
+	status = netlogon_creds_cli_auth(context, b, num_nt_hashes, nt_hashes,
+					 idx_nt_hashes);
+	TALLOC_FREE(lck);
+
+	return status;
+}
+
 NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 			 struct messaging_context *msg_ctx,
 			 struct dcerpc_binding_handle *b,
@@ -358,10 +388,10 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	 * ServerTrustPasswordsGet() or netr_ServerGetTrustInfo() to fix our
 	 * local secrets before doing the change.
 	 */
-	status = netlogon_creds_cli_auth(context, b,
-					 num_nt_hashes,
-					 nt_hashes,
-					 &idx_nt_hashes);
+	status = netlogon_creds_cli_lck_auth(context, b,
+					     num_nt_hashes,
+					     nt_hashes,
+					     &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for old passwords (%u) - %s!\n",
 			  context_name, num_nt_hashes, nt_errstr(status)));
@@ -571,10 +601,10 @@ NTSTATUS trust_pw_change(struct netlogon_creds_cli_context *context,
 	idx_current = idx;
 	nt_hashes[idx++] = current_nt_hash;
 	num_nt_hashes = idx;
-	status = netlogon_creds_cli_auth(context, b,
-					 num_nt_hashes,
-					 nt_hashes,
-					 &idx_nt_hashes);
+	status = netlogon_creds_cli_lck_auth(context, b,
+					     num_nt_hashes,
+					     nt_hashes,
+					     &idx_nt_hashes);
 	if (!NT_STATUS_IS_OK(status)) {
 		DEBUG(0, ("netlogon_creds_cli_auth(%s) failed for new password - %s!\n",
 			  context_name, nt_errstr(status)));
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 752a1574919..ccbba960a52 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -166,8 +166,19 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	uint8_t num_nt_hashes = 0;
 	const struct samr_Password *nt_hashes[2] = { NULL, NULL };
 	uint8_t idx_nt_hashes = 0;
+	struct netlogon_creds_cli_lck *lck = NULL;
 	NTSTATUS status;
 
+	status = netlogon_creds_cli_lck(
+		creds_ctx, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+		frame, &lck);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
+			    nt_errstr(status));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
 	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
 	if (NT_STATUS_IS_OK(status)) {
 		const char *action = "using";
@@ -230,6 +241,8 @@ NTSTATUS rpccli_setup_netlogon_creds(
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
+	TALLOC_FREE(lck);
+
 	DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
 		 __FUNCTION__,
 		 creds->account_name, creds->computer_name,
-- 
2.11.0


From 2c5c0434a5805c041327e7772b640682825f3aa6 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 17 Sep 2017 07:31:28 -0700
Subject: [PATCH 21/28] cli_netlogon: Factor out
 rpccli_setup_netlogon_creds_locked

This does the reqchallenge/serverauth while assuming we have the
netlogon_creds_cli_lck already held. The _locked flavor will be called
from a routine that covers more under one single lock.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 44 ++++++++++++++++++++++++++-------------
 source3/rpc_client/cli_netlogon.h |  6 ++++++
 2 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index ccbba960a52..8a866fe8aa5 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -153,7 +153,7 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 					    creds_ctx);
 }
 
-NTSTATUS rpccli_setup_netlogon_creds(
+NTSTATUS rpccli_setup_netlogon_creds_locked(
 	struct cli_state *cli,
 	enum dcerpc_transport_t transport,
 	struct netlogon_creds_cli_context *creds_ctx,
@@ -166,19 +166,8 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	uint8_t num_nt_hashes = 0;
 	const struct samr_Password *nt_hashes[2] = { NULL, NULL };
 	uint8_t idx_nt_hashes = 0;
-	struct netlogon_creds_cli_lck *lck = NULL;
 	NTSTATUS status;
 
-	status = netlogon_creds_cli_lck(
-		creds_ctx, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
-		frame, &lck);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
-			    nt_errstr(status));
-		TALLOC_FREE(frame);
-		return status;
-	}
-
 	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
 	if (NT_STATUS_IS_OK(status)) {
 		const char *action = "using";
@@ -241,8 +230,6 @@ NTSTATUS rpccli_setup_netlogon_creds(
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	TALLOC_FREE(lck);
-
 	DEBUG(5,("%s: using new netlogon_creds cli[%s/%s] to %s\n",
 		 __FUNCTION__,
 		 creds->account_name, creds->computer_name,
@@ -252,6 +239,35 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	return NT_STATUS_OK;
 }
 
+NTSTATUS rpccli_setup_netlogon_creds(
+	struct cli_state *cli,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *creds_ctx,
+	bool force_reauth,
+	struct cli_credentials *cli_creds)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct netlogon_creds_cli_lck *lck;
+	NTSTATUS status;
+
+	status = netlogon_creds_cli_lck(
+		creds_ctx, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+		frame, &lck);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("netlogon_creds_cli_lck failed: %s\n",
+			    nt_errstr(status));
+		TALLOC_FREE(frame);
+		return status;
+	}
+
+	status = rpccli_setup_netlogon_creds_locked(
+		cli, transport, creds_ctx, force_reauth, cli_creds);
+
+	TALLOC_FREE(frame);
+
+	return status;
+}
+
 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 					uint16_t validation_level,
 					union netr_Validation *validation,
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index 04a370fba88..63db4762fb6 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -39,6 +39,12 @@ NTSTATUS rpccli_create_netlogon_creds_ctx(
 	struct messaging_context *msg_ctx,
 	TALLOC_CTX *mem_ctx,
 	struct netlogon_creds_cli_context **creds_ctx);
+NTSTATUS rpccli_setup_netlogon_creds_locked(
+	struct cli_state *cli,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *creds_ctx,
+	bool force_reauth,
+	struct cli_credentials *cli_creds);
 NTSTATUS rpccli_setup_netlogon_creds(
 	struct cli_state *cli,
 	enum dcerpc_transport_t transport,
-- 
2.11.0


From fa6bb30fb15e46fa1fb53edd055109b85992c897 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Sun, 17 Sep 2017 14:28:44 -0700
Subject: [PATCH 22/28] rpcclient3: Factor out
 cli_rpc_pipe_open_bind_schannel()

This will be used for the "fast path" to netlogon when we already have
credentials.

This slightly widens the area of code covered by the netlogon_creds
lock: cli_rpc_pipe_open is now also covered by the lock.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_pipe.c | 94 ++++++++++++++++++++++++++-----------------
 source3/rpc_client/cli_pipe.h |  6 +++
 2 files changed, 63 insertions(+), 37 deletions(-)

diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index 710d95a0316..c7042947b24 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3272,11 +3272,12 @@ NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
 	return status;
 }
 
-NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
-					       const struct ndr_interface_table *table,
-					       enum dcerpc_transport_t transport,
-					       struct netlogon_creds_cli_context *netlogon_creds,
-					       struct rpc_pipe_client **_rpccli)
+NTSTATUS cli_rpc_pipe_open_bind_schannel(
+	struct cli_state *cli,
+	const struct ndr_interface_table *table,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *netlogon_creds,
+	struct rpc_pipe_client **_rpccli)
 {
 	struct rpc_pipe_client *rpccli;
 	struct pipe_auth_data *rpcauth;
@@ -3284,24 +3285,12 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	struct cli_credentials *cli_creds;
 	enum dcerpc_AuthLevel auth_level;
 	NTSTATUS status;
-	int rpc_pipe_bind_dbglvl = 0;
-	struct netlogon_creds_cli_lck *lck;
 
 	status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
 
-	status = netlogon_creds_cli_lck(
-		netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
-		rpccli, &lck);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
-			    nt_errstr(status));
-		TALLOC_FREE(rpccli);
-		return status;
-	}
-
 	auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
 
 	status = netlogon_creds_bind_cli_credentials(
@@ -3333,38 +3322,69 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	talloc_unlink(rpccli, cli_creds);
 	cli_creds = NULL;
 
-	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
-		rpc_pipe_bind_dbglvl = 1;
-		netlogon_creds_cli_delete_lck(netlogon_creds);
-	}
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(rpc_pipe_bind_dbglvl,
-		      ("%s: rpc_pipe_bind failed with error %s\n",
-		       __func__, nt_errstr(status)));
+		DBG_DEBUG("rpc_pipe_bind failed with error %s\n",
+			  nt_errstr(status));
 		TALLOC_FREE(rpccli);
 		return status;
 	}
 
-	if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
-		goto done;
+	*_rpccli = rpccli;
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
+					       const struct ndr_interface_table *table,
+					       enum dcerpc_transport_t transport,
+					       struct netlogon_creds_cli_context *netlogon_creds,
+					       struct rpc_pipe_client **_rpccli)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct rpc_pipe_client *rpccli;
+	struct netlogon_creds_cli_lck *lck;
+	NTSTATUS status;
+
+	status = netlogon_creds_cli_lck(
+		netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+		frame, &lck);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
+			    nt_errstr(status));
+		TALLOC_FREE(frame);
+		return status;
 	}
 
-	status = netlogon_creds_cli_check(netlogon_creds,
-					  rpccli->binding_handle);
+	status = cli_rpc_pipe_open_bind_schannel(
+		cli, table, transport, netlogon_creds, &rpccli);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+		netlogon_creds_cli_delete_lck(netlogon_creds);
+	}
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
-			  nt_errstr(status)));
-		TALLOC_FREE(rpccli);
+		DBG_DEBUG("cli_rpc_pipe_open_bind_schannel failed: %s\n",
+			  nt_errstr(status));
+		TALLOC_FREE(frame);
 		return status;
 	}
 
-done:
-	DEBUG(10,("%s: opened pipe %s to machine %s "
-		  "for domain %s and bound using schannel.\n",
-		  __func__, table->name,
-		  rpccli->desthost, cli_credentials_get_domain(cli_creds)));
+	if (ndr_syntax_id_equal(&table->syntax_id,
+				&ndr_table_netlogon.syntax_id)) {
+		status = netlogon_creds_cli_check(netlogon_creds,
+						  rpccli->binding_handle);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
+				  nt_errstr(status)));
+			TALLOC_FREE(frame);
+			return status;
+		}
+	}
+
+	DBG_DEBUG("opened pipe %s to machine %s with key %s "
+		  "and bound using schannel.\n",
+		  table->name, rpccli->desthost,
+		  netlogon_creds_cli_debug_string(netlogon_creds, lck));
 
-	TALLOC_FREE(lck);
+	TALLOC_FREE(frame);
 
 	*_rpccli = rpccli;
 	return NT_STATUS_OK;
diff --git a/source3/rpc_client/cli_pipe.h b/source3/rpc_client/cli_pipe.h
index 5df43c57e95..88dda8d4fbf 100644
--- a/source3/rpc_client/cli_pipe.h
+++ b/source3/rpc_client/cli_pipe.h
@@ -99,6 +99,12 @@ NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
 					const char *password,
 					struct rpc_pipe_client **presult);
 
+NTSTATUS cli_rpc_pipe_open_bind_schannel(
+	struct cli_state *cli,
+	const struct ndr_interface_table *table,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *netlogon_creds,
+	struct rpc_pipe_client **_rpccli);
 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 					       const struct ndr_interface_table *table,
 					       enum dcerpc_transport_t transport,
-- 
2.11.0


From 71d001f71fc3e13005c56bd540a2390b7d3801f1 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 18 Sep 2017 13:17:01 -0700
Subject: [PATCH 23/28] cli_netlogon: Return flags from
 rpccli_setup_netlogon_creds_locked

This will be used in a later commit in the rpcclient "capabilities"
command. Avoids another netlogon_creds_cli_get in the next commit.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 13 +++++++++----
 source3/rpc_client/cli_netlogon.h |  3 ++-
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 8a866fe8aa5..6734442cd0d 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -158,7 +158,8 @@ NTSTATUS rpccli_setup_netlogon_creds_locked(
 	enum dcerpc_transport_t transport,
 	struct netlogon_creds_cli_context *creds_ctx,
 	bool force_reauth,
-	struct cli_credentials *cli_creds)
+	struct cli_credentials *cli_creds,
+	uint32_t *negotiate_flags)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct rpc_pipe_client *netlogon_pipe = NULL;
@@ -181,8 +182,7 @@ NTSTATUS rpccli_setup_netlogon_creds_locked(
 			 creds->account_name, creds->computer_name,
 			 smbXcli_conn_remote_name(cli->conn)));
 		if (!force_reauth) {
-			TALLOC_FREE(frame);
-			return NT_STATUS_OK;
+			goto done;
 		}
 		TALLOC_FREE(creds);
 	}
@@ -235,6 +235,11 @@ NTSTATUS rpccli_setup_netlogon_creds_locked(
 		 creds->account_name, creds->computer_name,
 		 smbXcli_conn_remote_name(cli->conn)));
 
+done:
+	if (negotiate_flags != NULL) {
+		*negotiate_flags = creds->negotiate_flags;
+	}
+
 	TALLOC_FREE(frame);
 	return NT_STATUS_OK;
 }
@@ -261,7 +266,7 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	}
 
 	status = rpccli_setup_netlogon_creds_locked(
-		cli, transport, creds_ctx, force_reauth, cli_creds);
+		cli, transport, creds_ctx, force_reauth, cli_creds, NULL);
 
 	TALLOC_FREE(frame);
 
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index 63db4762fb6..ca5589e46ef 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -44,7 +44,8 @@ NTSTATUS rpccli_setup_netlogon_creds_locked(
 	enum dcerpc_transport_t transport,
 	struct netlogon_creds_cli_context *creds_ctx,
 	bool force_reauth,
-	struct cli_credentials *cli_creds);
+	struct cli_credentials *cli_creds,
+	uint32_t *negotiate_flags);
 NTSTATUS rpccli_setup_netlogon_creds(
 	struct cli_state *cli,
 	enum dcerpc_transport_t transport,
-- 
2.11.0


From d50e4f4f22e2801e330fa07928d38e8616eb3918 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 18 Sep 2017 13:26:03 -0700
Subject: [PATCH 24/28] cli_netlogon: rpccli_connect_netlogon

This is the one-stop shop to a working, schannel'ed connection to the
netlogon RPC interface. Jeremy tells me it needs more comments :-)

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpc_client/cli_netlogon.c | 190 ++++++++++++++++++++++++++++++++++++++
 source3/rpc_client/cli_netlogon.h |   7 ++
 2 files changed, 197 insertions(+)

diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index 6734442cd0d..c315e69a902 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -273,6 +273,196 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	return status;
 }
 
+NTSTATUS rpccli_connect_netlogon(
+	struct cli_state *cli,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *creds_ctx,
+	bool force_reauth,
+	struct cli_credentials *trust_creds,
+	struct rpc_pipe_client **_rpccli)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct netlogon_creds_CredentialState *creds = NULL;
+	enum netlogon_creds_cli_lck_type lck_type;
+	enum netr_SchannelType sec_chan_type;
+	struct netlogon_creds_cli_lck *lck;
+	uint32_t negotiate_flags;
+	uint8_t found_session_key[16] = {0};
+	bool found_existing_creds = false;
+	bool do_serverauth;
+	struct rpc_pipe_client *rpccli;
+	NTSTATUS status;
+
+again:
+
+	/*
+	 * See whether we can use existing netlogon_creds or
+	 * whether we have to serverauthenticate.
+	 */
+	status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
+
+	if (NT_STATUS_IS_OK(status)) {
+		int cmp = memcmp(found_session_key,
+				 creds->session_key,
+				 sizeof(found_session_key));
+		found_existing_creds = (cmp != 0);
+
+		memcpy(found_session_key,
+		       creds->session_key,
+		       sizeof(found_session_key));
+
+		TALLOC_FREE(creds);
+	}
+
+	lck_type = (force_reauth || !found_existing_creds) ?
+		NETLOGON_CREDS_CLI_LCK_EXCLUSIVE :
+		NETLOGON_CREDS_CLI_LCK_SHARED;
+
+	status = netlogon_creds_cli_lck(creds_ctx, lck_type, frame, &lck);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("netlogon_creds_cli_lck failed: %s\n",
+			  nt_errstr(status));
+		goto fail;
+	}
+
+	if (!found_existing_creds) {
+		/*
+		 * Try to find creds under the lock again. Someone
+		 * else might have done it for us.
+		 */
+		status = netlogon_creds_cli_get(creds_ctx, frame, &creds);
+
+		if (NT_STATUS_IS_OK(status)) {
+			int cmp = memcmp(found_session_key,
+					 creds->session_key,
+					 sizeof(found_session_key));
+			found_existing_creds = (cmp != 0);
+
+			memcpy(found_session_key, creds->session_key,
+			       sizeof(found_session_key));
+
+			TALLOC_FREE(creds);
+		}
+	}
+
+	do_serverauth = force_reauth || !found_existing_creds;
+
+	if (!do_serverauth) {
+		/*
+		 * Do the quick schannel bind without a reauth
+		 */
+		status = cli_rpc_pipe_open_bind_schannel(
+			cli, &ndr_table_netlogon, transport, creds_ctx,
+			&rpccli);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
+				  "failed: %s\n", nt_errstr(status));
+		}
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
+			DBG_DEBUG("Retrying with serverauthenticate\n");
+			TALLOC_FREE(lck);
+			goto again;
+		}
+		goto done;
+	}
+
+	if (cli_credentials_is_anonymous(trust_creds)) {
+		DBG_WARNING("get_trust_credential for %s only gave anonymous,"
+			    "unable to make get NETLOGON credentials\n",
+			    netlogon_creds_cli_debug_string(
+				    creds_ctx, frame));
+		status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+		goto fail;
+	}
+
+	sec_chan_type = cli_credentials_get_secure_channel_type(trust_creds);
+	if (sec_chan_type == SEC_CHAN_NULL) {
+		if (transport == NCACN_IP_TCP) {
+			DBG_NOTICE("secure_channel_type gave SEC_CHAN_NULL "
+				   "for %s, deny NCACN_IP_TCP and let the "
+				   "caller fallback to NCACN_NP.\n",
+				   netlogon_creds_cli_debug_string(
+					   creds_ctx, frame));
+			status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+			goto fail;
+		}
+
+		DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL "
+			   "for %s, fallback to noauth on NCACN_NP.\n",
+			   netlogon_creds_cli_debug_string(
+				   creds_ctx, frame));
+
+		TALLOC_FREE(lck);
+
+		status = cli_rpc_pipe_open_noauth_transport(
+			cli, transport, &ndr_table_netlogon, &rpccli);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_DEBUG("cli_rpc_pipe_open_noauth_transport "
+				  "failed: %s\n", nt_errstr(status));
+		}
+		goto done;
+	}
+
+	status = rpccli_setup_netlogon_creds_locked(
+		cli, transport, creds_ctx, true, trust_creds,
+		&negotiate_flags);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("rpccli_setup_netlogon_creds failed for %s, "
+			  "unable to setup NETLOGON credentials: %s\n",
+			  netlogon_creds_cli_debug_string(
+				  creds_ctx, frame),
+			  nt_errstr(status));
+		goto fail;
+	}
+
+	if (!(negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
+		if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
+			status = NT_STATUS_DOWNGRADE_DETECTED;
+			DBG_WARNING("Unwilling to make connection to %s"
+				    "without connection level security, "
+				    "must set 'winbind sealed pipes = false'"
+				    " and 'require strong key = false' "
+				    "to proceed: %s\n",
+				    netlogon_creds_cli_debug_string(
+					    creds_ctx, frame),
+				    nt_errstr(status));
+			goto fail;
+		}
+
+		status = cli_rpc_pipe_open_noauth_transport(
+			cli, transport, &ndr_table_netlogon, &rpccli);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_DEBUG("cli_rpc_pipe_open_noauth_transport "
+				  "failed: %s\n", nt_errstr(status));
+		}
+		goto done;
+	}
+
+	status = cli_rpc_pipe_open_bind_schannel(
+		cli, &ndr_table_netlogon, transport, creds_ctx, &rpccli);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_DEBUG("cli_rpc_pipe_open_bind_schannel "
+			  "failed: %s\n", nt_errstr(status));
+		goto fail;
+	}
+
+	status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_WARNING("netlogon_creds_cli_check failed: %s\n",
+			    nt_errstr(status));
+		goto fail;
+	}
+
+done:
+	*_rpccli = rpccli;
+	status = NT_STATUS_OK;
+fail:
+	ZERO_STRUCT(found_session_key);
+	TALLOC_FREE(lck);
+	TALLOC_FREE(frame);
+	return status;
+}
+
 static NTSTATUS map_validation_to_info3(TALLOC_CTX *mem_ctx,
 					uint16_t validation_level,
 					union netr_Validation *validation,
diff --git a/source3/rpc_client/cli_netlogon.h b/source3/rpc_client/cli_netlogon.h
index ca5589e46ef..da562e056d3 100644
--- a/source3/rpc_client/cli_netlogon.h
+++ b/source3/rpc_client/cli_netlogon.h
@@ -52,6 +52,13 @@ NTSTATUS rpccli_setup_netlogon_creds(
 	struct netlogon_creds_cli_context *creds_ctx,
 	bool force_reauth,
 	struct cli_credentials *cli_creds);
+NTSTATUS rpccli_connect_netlogon(
+	struct cli_state *cli,
+	enum dcerpc_transport_t transport,
+	struct netlogon_creds_cli_context *creds_ctx,
+	bool force_reauth,
+	struct cli_credentials *trust_creds,
+	struct rpc_pipe_client **_rpccli);
 NTSTATUS rpccli_netlogon_password_logon(struct netlogon_creds_cli_context *creds,
 					struct dcerpc_binding_handle *binding_handle,
 					TALLOC_CTX *mem_ctx,
-- 
2.11.0


From f8d1b0072282c1350478d3c978e8d26a246deb7f Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Mon, 18 Sep 2017 16:19:12 -0700
Subject: [PATCH 25/28] winbindd: Use rpccli_connect_netlogon

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/winbindd_cm.c | 99 +++---------------------------------------
 1 file changed, 5 insertions(+), 94 deletions(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index a5e5ab3f4e3..1fa688241dd 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -3214,8 +3214,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 	struct messaging_context *msg_ctx = winbind_messaging_context();
 	struct winbindd_cm_conn *conn;
 	NTSTATUS result;
-	enum netr_SchannelType sec_chan_type;
-	struct netlogon_creds_CredentialState *netlogon_creds = NULL;
 	struct cli_credentials *creds = NULL;
 
 	*cli = NULL;
@@ -3243,38 +3241,6 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 	}
 
-	if (cli_credentials_is_anonymous(creds)) {
-		DEBUG(1, ("get_trust_credential only gave anonymous for %s, unable to make get NETLOGON credentials\n",
-			  domain->name));
-		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-	}
-
-	sec_chan_type = cli_credentials_get_secure_channel_type(creds);
-	if (sec_chan_type == SEC_CHAN_NULL) {
-		if (transport == NCACN_IP_TCP) {
-			DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
-				   " deny NCACN_IP_TCP and let the caller fallback to NCACN_NP.\n",
-				   domain->name);
-			return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
-		}
-
-		DBG_NOTICE("get_secure_channel_type gave SEC_CHAN_NULL for %s, "
-			   "fallback to noauth on NCACN_NP.\n",
-			   domain->name);
-
-		result = cli_rpc_pipe_open_noauth_transport(conn->cli,
-							    transport,
-							    &ndr_table_netlogon,
-							    &conn->netlogon_pipe);
-		if (!NT_STATUS_IS_OK(result)) {
-			invalidate_cm_connection(domain);
-			return result;
-		}
-
-		*cli = conn->netlogon_pipe;
-		return NT_STATUS_OK;
-	}
-
 	result = rpccli_create_netlogon_creds_ctx(creds,
 						  domain->dcname,
 						  msg_ctx,
@@ -3287,68 +3253,13 @@ static NTSTATUS cm_connect_netlogon_transport(struct winbindd_domain *domain,
 		return result;
 	}
 
-	result = rpccli_setup_netlogon_creds(conn->cli, transport,
-					     conn->netlogon_creds_ctx,
-					     conn->netlogon_force_reauth,
-					     creds);
-	conn->netlogon_force_reauth = false;
-	if (!NT_STATUS_IS_OK(result)) {
-		DEBUG(1, ("rpccli_setup_netlogon_creds failed for %s, "
-			  "unable to setup NETLOGON credentials: %s\n",
-			  domain->name, nt_errstr(result)));
-		return result;
-	}
-
-	result = netlogon_creds_cli_get(conn->netlogon_creds_ctx,
-					talloc_tos(),
-					&netlogon_creds);
-	if (!NT_STATUS_IS_OK(result)) {
-		DEBUG(1, ("netlogon_creds_cli_get failed for %s, "
-			  "unable to get NETLOGON credentials: %s\n",
-			  domain->name, nt_errstr(result)));
-		return result;
-	}
-	conn->netlogon_flags = netlogon_creds->negotiate_flags;
-	TALLOC_FREE(netlogon_creds);
-
-	if (!(conn->netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
-		if (lp_winbind_sealed_pipes() || lp_require_strong_key()) {
-			result = NT_STATUS_DOWNGRADE_DETECTED;
-			DEBUG(1, ("Unwilling to make connection to domain %s"
-				  "without connection level security, "
-				  "must set 'winbind sealed pipes = false' and "
-				  "'require strong key = false' to proceed: %s\n",
-				  domain->name, nt_errstr(result)));
-			invalidate_cm_connection(domain);
-			return result;
-		}
-		result = cli_rpc_pipe_open_noauth_transport(conn->cli,
-							    transport,
-							    &ndr_table_netlogon,
-							    &conn->netlogon_pipe);
-		if (!NT_STATUS_IS_OK(result)) {
-			invalidate_cm_connection(domain);
-			return result;
-		}
-
-		*cli = conn->netlogon_pipe;
-		return NT_STATUS_OK;
-	}
-
-	/* Using the credentials from the first pipe, open a signed and sealed
-	   second netlogon pipe. The session key is stored in the schannel
-	   part of the new pipe auth struct.
-	*/
-
-	result = cli_rpc_pipe_open_schannel_with_creds(
-		conn->cli, &ndr_table_netlogon, transport,
-		conn->netlogon_creds_ctx,
+	result = rpccli_connect_netlogon(
+		conn->cli, transport,
+		conn->netlogon_creds_ctx, conn->netlogon_force_reauth, creds,
 		&conn->netlogon_pipe);
 	if (!NT_STATUS_IS_OK(result)) {
-		DEBUG(3, ("Could not open schannel'ed NETLOGON pipe. Error "
-			  "was %s\n", nt_errstr(result)));
-
-		invalidate_cm_connection(domain);
+		DBG_DEBUG("rpccli_connect_netlogon failed: %s\n",
+			  nt_errstr(result));
 		return result;
 	}
 
-- 
2.11.0


From 0434b965bd3ef38405d46dd3c3c44817f8528dfc Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 19 Sep 2017 16:45:27 -0700
Subject: [PATCH 26/28] netlogon_creds_cli: Pass "capabilities" up from
 creds_cli_check

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c  | 14 +++++++++++---
 libcli/auth/netlogon_creds_cli.h  |  6 ++++--
 source3/rpc_client/cli_netlogon.c |  3 ++-
 source3/rpc_client/cli_pipe.c     |  3 ++-
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index 31bd98ddc94..cb3d6a9eeb4 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -1728,8 +1728,11 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 	tevent_req_done(req);
 }
 
-NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+				       union netr_Capabilities *capabilities)
 {
+	struct netlogon_creds_cli_check_state *state = tevent_req_data(
+		req, struct netlogon_creds_cli_check_state);
 	NTSTATUS status;
 
 	if (tevent_req_is_nterror(req, &status)) {
@@ -1738,12 +1741,17 @@ NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
 		return status;
 	}
 
+	if (capabilities != NULL) {
+		*capabilities = state->caps;
+	}
+
 	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
-				  struct dcerpc_binding_handle *b)
+				  struct dcerpc_binding_handle *b,
+				  union netr_Capabilities *capabilities)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct tevent_context *ev;
@@ -1761,7 +1769,7 @@ NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
 	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
 		goto fail;
 	}
-	status = netlogon_creds_cli_check_recv(req);
+	status = netlogon_creds_cli_check_recv(req, capabilities);
  fail:
 	TALLOC_FREE(frame);
 	return status;
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 62d11ac283e..56a2dd9bc77 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -116,9 +116,11 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
 				struct netlogon_creds_cli_context *context,
 				struct dcerpc_binding_handle *b);
-NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req);
+NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
+				       union netr_Capabilities *capabilities);
 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
-				  struct dcerpc_binding_handle *b);
+				  struct dcerpc_binding_handle *b,
+				  union netr_Capabilities *capabilities);
 
 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
 				struct tevent_context *ev,
diff --git a/source3/rpc_client/cli_netlogon.c b/source3/rpc_client/cli_netlogon.c
index c315e69a902..19b81a5f5a9 100644
--- a/source3/rpc_client/cli_netlogon.c
+++ b/source3/rpc_client/cli_netlogon.c
@@ -446,7 +446,8 @@ again:
 		goto fail;
 	}
 
-	status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle);
+	status = netlogon_creds_cli_check(creds_ctx, rpccli->binding_handle,
+					  NULL);
 	if (!NT_STATUS_IS_OK(status)) {
 		DBG_WARNING("netlogon_creds_cli_check failed: %s\n",
 			    nt_errstr(status));
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index c7042947b24..d449a828b5a 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3370,7 +3370,8 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 	if (ndr_syntax_id_equal(&table->syntax_id,
 				&ndr_table_netlogon.syntax_id)) {
 		status = netlogon_creds_cli_check(netlogon_creds,
-						  rpccli->binding_handle);
+						  rpccli->binding_handle,
+						  NULL);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
 				  nt_errstr(status)));
-- 
2.11.0


From fe9c543eef645f9a2b0dbde9d541055e70ffc115 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 19 Sep 2017 17:30:02 -0700
Subject: [PATCH 27/28] rpcclient: Fix "capabilities" command

This used to not properly store the chained credentials back into the
netlogon_creds_cli tdb. This by the way is the bug that all the
routines for the NT4 style sam replication had that just disappeared.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/rpcclient/cmd_netlogon.c | 56 ++++++++++++----------------------------
 1 file changed, 16 insertions(+), 40 deletions(-)

diff --git a/source3/rpcclient/cmd_netlogon.c b/source3/rpcclient/cmd_netlogon.c
index 88576aeb88b..2d6a0829a57 100644
--- a/source3/rpcclient/cmd_netlogon.c
+++ b/source3/rpcclient/cmd_netlogon.c
@@ -878,62 +878,38 @@ static NTSTATUS cmd_netlogon_capabilities(struct rpc_pipe_client *cli,
 					  TALLOC_CTX *mem_ctx, int argc,
 					  const char **argv)
 {
-	NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-	NTSTATUS result;
-	struct netr_Authenticator credential;
-	struct netr_Authenticator return_authenticator;
+	struct netlogon_creds_cli_lck *lck;
 	union netr_Capabilities capabilities;
-	uint32_t level = 1;
-	struct dcerpc_binding_handle *b = cli->binding_handle;
-	struct netlogon_creds_CredentialState *creds = NULL;
+	NTSTATUS status;
 
-	if (argc > 2) {
-		fprintf(stderr, "Usage: %s <level>\n", argv[0]);
+	if (argc > 1) {
+		fprintf(stderr, "Usage: %s\n", argv[0]);
 		return NT_STATUS_OK;
 	}
 
-	if (argc == 2) {
-		level = atoi(argv[1]);
-	}
-
-	ZERO_STRUCT(return_authenticator);
-
-	if (rpcclient_netlogon_creds == NULL) {
-		return NT_STATUS_UNSUCCESSFUL;
-	}
-
-	status = netlogon_creds_cli_lock(rpcclient_netlogon_creds,
-					 mem_ctx, &creds);
+	status = netlogon_creds_cli_lck(rpcclient_netlogon_creds,
+					NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+					mem_ctx, &lck);
 	if (!NT_STATUS_IS_OK(status)) {
+		fprintf(stderr, "netlogon_creds_cli_lck failed: %s\n",
+			nt_errstr(status));
 		return status;
 	}
 
-	netlogon_creds_client_authenticator(creds, &credential);
-
-	status = dcerpc_netr_LogonGetCapabilities(b, mem_ctx,
-						  cli->desthost,
-						  lp_netbios_name(),
-						  &credential,
-						  &return_authenticator,
-						  level,
-						  &capabilities,
-						  &result);
+	status = netlogon_creds_cli_check(rpcclient_netlogon_creds,
+					  cli->binding_handle,
+					  &capabilities);
 	if (!NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(creds);
+		fprintf(stderr, "netlogon_creds_cli_check failed: %s\n",
+			nt_errstr(status));
 		return status;
 	}
 
-	if (!netlogon_creds_client_check(creds,
-					 &return_authenticator.cred)) {
-		DEBUG(0,("credentials chain check failed\n"));
-		TALLOC_FREE(creds);
-		return NT_STATUS_ACCESS_DENIED;
-	}
-	TALLOC_FREE(creds);
+	TALLOC_FREE(lck);
 
 	printf("capabilities: 0x%08x\n", capabilities.server_capabilities);
 
-	return result;
+	return NT_STATUS_OK;
 }
 
 /* List of commands exported by this module */
-- 
2.11.0


From 5a169f40fe0d445f3556ac5d62226658415749d0 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Tue, 19 Sep 2017 17:33:52 -0700
Subject: [PATCH 28/28] netlogon_creds_cli: Make netlogon_creds_cli_lock static

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 libcli/auth/netlogon_creds_cli.c | 18 +++++++++---------
 libcli/auth/netlogon_creds_cli.h | 10 ----------
 2 files changed, 9 insertions(+), 19 deletions(-)

diff --git a/libcli/auth/netlogon_creds_cli.c b/libcli/auth/netlogon_creds_cli.c
index cb3d6a9eeb4..8ebeeff19b2 100644
--- a/libcli/auth/netlogon_creds_cli.c
+++ b/libcli/auth/netlogon_creds_cli.c
@@ -720,9 +720,9 @@ struct netlogon_creds_cli_lock_state {
 
 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
 
-struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
-				struct tevent_context *ev,
-				struct netlogon_creds_cli_context *context)
+static struct tevent_req *netlogon_creds_cli_lock_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	struct netlogon_creds_cli_context *context)
 {
 	struct tevent_req *req;
 	struct netlogon_creds_cli_lock_state *state;
@@ -876,9 +876,9 @@ static NTSTATUS netlogon_creds_cli_get_internal(
 	return NT_STATUS_OK;
 }
 
-NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
-			TALLOC_CTX *mem_ctx,
-			struct netlogon_creds_CredentialState **creds)
+static NTSTATUS netlogon_creds_cli_lock_recv(
+	struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	struct netlogon_creds_CredentialState **creds)
 {
 	struct netlogon_creds_cli_lock_state *state =
 		tevent_req_data(req,
@@ -897,9 +897,9 @@ NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
 	return NT_STATUS_OK;
 }
 
-NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
-			TALLOC_CTX *mem_ctx,
-			struct netlogon_creds_CredentialState **creds)
+static NTSTATUS netlogon_creds_cli_lock(
+	struct netlogon_creds_cli_context *context,
+	TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **creds)
 {
 	TALLOC_CTX *frame = talloc_stackframe();
 	struct tevent_context *ev;
diff --git a/libcli/auth/netlogon_creds_cli.h b/libcli/auth/netlogon_creds_cli.h
index 56a2dd9bc77..e87f4fd086c 100644
--- a/libcli/auth/netlogon_creds_cli.h
+++ b/libcli/auth/netlogon_creds_cli.h
@@ -68,16 +68,6 @@ NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
 NTSTATUS netlogon_creds_cli_delete_lck(
 	struct netlogon_creds_cli_context *context);
 
-struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
-				struct tevent_context *ev,
-				struct netlogon_creds_cli_context *context);
-NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
-			TALLOC_CTX *mem_ctx,
-			struct netlogon_creds_CredentialState **creds);
-NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
-			TALLOC_CTX *mem_ctx,
-			struct netlogon_creds_CredentialState **creds);
-
 struct netlogon_creds_cli_lck;
 
 enum netlogon_creds_cli_lck_type {
-- 
2.11.0



More information about the samba-technical mailing list