kwizart / rpms / samba

Forked from rpms/samba 4 years ago
Clone
Blob Blame History Raw
From a4603b32f7ca11c37f5a48d541ef76b08cda6415 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Mon, 9 Aug 2010 14:31:24 +0200
Subject: [PATCH] s3-winbind: Fix Bug #7568: Make sure cm_connect_lsa_tcp does not reset the secure channel.

This is an important fix as the following could and is happening:

* winbind authenticates a user via schannel secured netlogon samlogonex call,
current secure channel cred state is stored in winbind state, winbind
sucessfully decrypts session key from the info3

* winbind sets up a new schannel ncacn_ip_tcp lsa pipe (and thereby resets the
secure channel on the dc)

* subsequent samlogonex calls use the new secure channel creds on the dc to
encrypt info3 session key, while winbind tries to use old schannel creds for
decryption

Guenther
(cherry picked from commit be396411a4e1f3a174f8a44b6c062d834135e70a)
(cherry picked from commit afe0e73b7bb640428396c9f40dbbcba5c311fcd9)
---
 source3/winbindd/winbindd_cm.c |   20 +++++++++++++-------
 1 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index ee9a656..f8e49cc 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -2231,6 +2231,7 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 			    struct rpc_pipe_client **cli)
 {
 	struct winbindd_cm_conn *conn;
+	struct netlogon_creds_CredentialState *creds;
 	NTSTATUS status;
 
 	DEBUG(10,("cm_connect_lsa_tcp\n"));
@@ -2251,14 +2252,19 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
 	TALLOC_FREE(conn->lsa_pipe_tcp);
 
-	status = cli_rpc_pipe_open_schannel(conn->cli,
-					    &ndr_table_lsarpc.syntax_id,
-					    NCACN_IP_TCP,
-					    DCERPC_AUTH_LEVEL_PRIVACY,
-					    domain->name,
-					    &conn->lsa_pipe_tcp);
+	if (!cm_get_schannel_creds(domain, &creds)) {
+		goto done;
+	}
+
+	status = cli_rpc_pipe_open_schannel_with_key(conn->cli,
+						     &ndr_table_lsarpc.syntax_id,
+						     NCACN_IP_TCP,
+						     DCERPC_AUTH_LEVEL_PRIVACY,
+						     domain->name,
+						     &creds,
+						     &conn->lsa_pipe_tcp);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(10,("cli_rpc_pipe_open_schannel failed: %s\n",
+		DEBUG(10,("cli_rpc_pipe_open_schannel_with_key failed: %s\n",
 			nt_errstr(status)));
 		goto done;
 	}
-- 
1.7.2.1

From fb4d65af7405d0f78674aaea66005e048e2a0536 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 23 Aug 2010 13:05:56 -0700
Subject: [PATCH 1/2] Final part of fix for bug #7636 - winbind internal error, backtrace.

Ensure cm_get_schannel_creds() returns NTSTATUS.

Jeremy.
(cherry picked from commit 33060f67be100836d381a74bced351c6579cc58d)
---
 source3/winbindd/winbindd_cm.c |   29 ++++++++++++++++++-----------
 1 files changed, 18 insertions(+), 11 deletions(-)

diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index f8e49cc..f466a94 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -2016,30 +2016,30 @@ static void set_dc_type_and_flags( struct winbindd_domain *domain )
 /**********************************************************************
 ***********************************************************************/
 
-static bool cm_get_schannel_creds(struct winbindd_domain *domain,
+static NTSTATUS cm_get_schannel_creds(struct winbindd_domain *domain,
 				   struct netlogon_creds_CredentialState **ppdc)
 {
-	NTSTATUS result;
+	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
 	struct rpc_pipe_client *netlogon_pipe;
 
 	if (lp_client_schannel() == False) {
-		return False;
+		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;;
 	}
 
 	result = cm_connect_netlogon(domain, &netlogon_pipe);
 	if (!NT_STATUS_IS_OK(result)) {
-		return False;
+		return result;
 	}
 
 	/* Return a pointer to the struct netlogon_creds_CredentialState from the
 	   netlogon pipe. */
 
 	if (!domain->conn.netlogon_pipe->dc) {
-		return false;
+		return NT_STATUS_INTERNAL_ERROR; /* This shouldn't happen. */
 	}
 
 	*ppdc = domain->conn.netlogon_pipe->dc;
-	return True;
+	return NT_STATUS_OK;
 }
 
 NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
@@ -2136,10 +2136,13 @@ NTSTATUS cm_connect_sam(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
 
 	/* Fall back to schannel if it's a W2K pre-SP1 box. */
 
-	if (!cm_get_schannel_creds(domain, &p_creds)) {
+	result = cm_get_schannel_creds(domain, &p_creds);
+	if (!NT_STATUS_IS_OK(result)) {
 		/* If this call fails - conn->cli can now be NULL ! */
 		DEBUG(10, ("cm_connect_sam: Could not get schannel auth info "
-			   "for domain %s, trying anon\n", domain->name));
+			   "for domain %s (error %s), trying anon\n",
+			domain->name,
+			nt_errstr(result) ));
 		goto anonymous;
 	}
 	result = cli_rpc_pipe_open_schannel_with_key
@@ -2252,7 +2255,8 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 
 	TALLOC_FREE(conn->lsa_pipe_tcp);
 
-	if (!cm_get_schannel_creds(domain, &creds)) {
+	status = cm_get_schannel_creds(domain, &creds);
+	if (!NT_STATUS_IS_OK(status)) {
 		goto done;
 	}
 
@@ -2344,10 +2348,13 @@ NTSTATUS cm_connect_lsa(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx,
 
 	/* Fall back to schannel if it's a W2K pre-SP1 box. */
 
-	if (!cm_get_schannel_creds(domain, &p_creds)) {
+	result = cm_get_schannel_creds(domain, &p_creds);
+	if (!NT_STATUS_IS_OK(result)) {
 		/* If this call fails - conn->cli can now be NULL ! */
 		DEBUG(10, ("cm_connect_lsa: Could not get schannel auth info "
-			   "for domain %s, trying anon\n", domain->name));
+			   "for domain %s (error %s), trying anon\n",
+			domain->name,
+			nt_errstr(result) ));
 		goto anonymous;
 	}
 	result = cli_rpc_pipe_open_schannel_with_key
-- 
1.7.2.1


From 703ce6f46e3d58476e0a31c8b258d7d194ea0315 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
Date: Mon, 23 Aug 2010 16:02:23 +0200
Subject: [PATCH 2/2] s3-dcerpc: avoid talloc_move on schannel creds in cli_rpc_pipe_open_schannel_with_key().

Initially, the schannel creds were talloc memduped, then, during the netlogon
creds client merge (baf7274fed2f1ae7a9e3a57160bf5471566e636c) they were first
talloc_referenced and then later (53765c81f726a8c056cc4e57004592dd489975c9)
talloc_moved.

The issue with using talloc_move here is that users of that function in winbind
will only be able to have two schanneled connections, as the cached schannel
credentials pointer from the netlogon pipe will be set to NULL. Do a deep copy
of the struct instead.

Guenther
(cherry picked from commit 898c6123355a3a11ec17f0396c4cb3018c75c184)
---
 libcli/auth/credentials.c     |   46 ++++++++++++++++++++++++++++++++++++++++-
 libcli/auth/proto.h           |    2 +
 source3/rpc_client/cli_pipe.c |   10 ++++++--
 3 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/libcli/auth/credentials.c b/libcli/auth/credentials.c
index 87d1866..504f594 100644
--- a/libcli/auth/credentials.c
+++ b/libcli/auth/credentials.c
@@ -24,6 +24,7 @@
 #include "system/time.h"
 #include "../lib/crypto/crypto.h"
 #include "libcli/auth/libcli_auth.h"
+#include "../libcli/security/dom_sid.h"
 
 static void netlogon_creds_step_crypt(struct netlogon_creds_CredentialState *creds,
 				      const struct netr_Credential *in,
@@ -202,7 +203,7 @@ struct netlogon_creds_CredentialState *netlogon_creds_client_init(TALLOC_CTX *me
 								  struct netr_Credential *initial_credential,
 								  uint32_t negotiate_flags)
 {
-	struct netlogon_creds_CredentialState *creds = talloc(mem_ctx, struct netlogon_creds_CredentialState);
+	struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
 	
 	if (!creds) {
 		return NULL;
@@ -453,3 +454,46 @@ void netlogon_creds_decrypt_samlogon(struct netlogon_creds_CredentialState *cred
 	}
 }	
 
+/*
+  copy a netlogon_creds_CredentialState struct
+*/
+
+struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
+							   struct netlogon_creds_CredentialState *creds_in)
+{
+	struct netlogon_creds_CredentialState *creds = talloc_zero(mem_ctx, struct netlogon_creds_CredentialState);
+
+	if (!creds) {
+		return NULL;
+	}
+
+	creds->sequence			= creds_in->sequence;
+	creds->negotiate_flags		= creds_in->negotiate_flags;
+	creds->secure_channel_type	= creds_in->secure_channel_type;
+
+	creds->computer_name = talloc_strdup(creds, creds_in->computer_name);
+	if (!creds->computer_name) {
+		talloc_free(creds);
+		return NULL;
+	}
+	creds->account_name = talloc_strdup(creds, creds_in->account_name);
+	if (!creds->account_name) {
+		talloc_free(creds);
+		return NULL;
+	}
+
+	if (creds_in->sid) {
+		creds->sid = dom_sid_dup(creds, creds_in->sid);
+		if (!creds->sid) {
+			talloc_free(creds);
+			return NULL;
+		}
+	}
+
+	memcpy(creds->session_key, creds_in->session_key, sizeof(creds->session_key));
+	memcpy(creds->seed.data, creds_in->seed.data, sizeof(creds->seed.data));
+	memcpy(creds->client.data, creds_in->client.data, sizeof(creds->client.data));
+	memcpy(creds->server.data, creds_in->server.data, sizeof(creds->server.data));
+
+	return creds;
+}
diff --git a/libcli/auth/proto.h b/libcli/auth/proto.h
index e09cdee..c3878f5 100644
--- a/libcli/auth/proto.h
+++ b/libcli/auth/proto.h
@@ -35,6 +35,8 @@ void netlogon_creds_client_authenticator(struct netlogon_creds_CredentialState *
 				struct netr_Authenticator *next);
 bool netlogon_creds_client_check(struct netlogon_creds_CredentialState *creds,
 			const struct netr_Credential *received_credentials);
+struct netlogon_creds_CredentialState *netlogon_creds_copy(TALLOC_CTX *mem_ctx,
+							   struct netlogon_creds_CredentialState *creds_in);
 
 /*****************************************************************
 The above functions are common to the client and server interface
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index ee60c1d..06b9c5d 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -3213,7 +3213,7 @@ NTSTATUS rpccli_schannel_bind_data(TALLOC_CTX *mem_ctx, const char *domain,
 	result->a_u.schannel_auth->state = SCHANNEL_STATE_START;
 	result->a_u.schannel_auth->seq_num = 0;
 	result->a_u.schannel_auth->initiator = true;
-	result->a_u.schannel_auth->creds = creds;
+	result->a_u.schannel_auth->creds = netlogon_creds_copy(result, creds);
 
 	*presult = result;
 	return NT_STATUS_OK;
@@ -4044,9 +4044,13 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
 
 	/*
 	 * The credentials on a new netlogon pipe are the ones we are passed
-	 * in - reference them in
+	 * in - copy them over
 	 */
-	result->dc = talloc_move(result, pdc);
+	result->dc = netlogon_creds_copy(result, *pdc);
+	if (result->dc == NULL) {
+		TALLOC_FREE(result);
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
 		  "for domain %s and bound using schannel.\n",
-- 
1.7.2.1