[Patches] The way to remove gensec_update_ev()

Stefan Metzmacher metze at samba.org
Wed May 17 12:43:11 UTC 2017


Hi,

here's the next chunk on top.

Both are combined the following branch:
https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master3-gensec-ok

https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master3-gensec-tmp
contains the change for the LDAP server, which also pass a private
autobuild, but it needs some more tests to be written.

While
https://git.samba.org/?p=metze/samba/wip.git;a=shortlog;h=refs/heads/master3-gensec
contains the unfinished parts:
- source4/libcli/smb_composite/sesssetup.c
- source4/lib/http/http_auth.c
- auth/gensec/spnego.c

While auth/gensec/spnego.c is the most difficult and time consuming part.

Please review and push:-)

Thanks!
metze

> I'm currently working on the removal of gensec_update_ev(),
> which relies on nested event loops to be activated.
> 
> If we want to have proper support for trusted domains in the
> as AD DC, we need to use real async authentication because
> we still use a single process model for the rpc server.
> 
> So the first step is to make all users of gensec_update_ev()
> use gensec_update_send/recv instead.
> 
> Once we have that we need to make the low level auth stack async
> for NTLMSSP (as a server) and Kerberos (as a client).
> 
> Here's the first chunk of patches, they passed a private autobuild.
> 
> Please review and push:-)

-------------- next part --------------
From 76a4a6db252100f82d6f7449da69e45960b67401 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 14:15:41 +0200
Subject: [PATCH 01/24] s4:rpc_server: introduce call->ack_pkt and avoid pkt
 variable for the response on the stack

This will be needed when we use async authentication using gensec_update_send/recv.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 64 +++++++++++++++++++-------------------
 source4/rpc_server/dcerpc_server.h |  5 +++
 2 files changed, 37 insertions(+), 32 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 9f62c11..a9f8854 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -773,7 +773,7 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *
 */
 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 {
-	struct ncacn_packet pkt;
+	struct ncacn_packet *pkt = &call->ack_pkt;
 	struct data_blob_list_item *rep;
 	NTSTATUS status;
 	uint32_t extra_flags = 0;
@@ -984,14 +984,14 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	}
 
 	/* setup a bind_ack */
-	dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
-	pkt.auth_length = 0;
-	pkt.call_id = call->pkt.call_id;
-	pkt.ptype = DCERPC_PKT_BIND_ACK;
-	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
-	pkt.u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
-	pkt.u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
-	pkt.u.bind_ack.assoc_group_id = call->conn->assoc_group->id;
+	dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+	pkt->auth_length = 0;
+	pkt->call_id = call->pkt.call_id;
+	pkt->ptype = DCERPC_PKT_BIND_ACK;
+	pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+	pkt->u.bind_ack.max_xmit_frag = call->conn->max_xmit_frag;
+	pkt->u.bind_ack.max_recv_frag = call->conn->max_recv_frag;
+	pkt->u.bind_ack.assoc_group_id = call->conn->assoc_group->id;
 
 	endpoint = dcerpc_binding_get_string_option(
 				call->conn->endpoint->ep_description,
@@ -1010,18 +1010,18 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 		endpoint += 6;
 	}
 
-	pkt.u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s",
+	pkt->u.bind_ack.secondary_address = talloc_asprintf(call, "%s%s",
 							   ep_prefix,
 							   endpoint);
-	if (pkt.u.bind_ack.secondary_address == NULL) {
+	if (pkt->u.bind_ack.secondary_address == NULL) {
 		TALLOC_FREE(call->context);
 		return NT_STATUS_NO_MEMORY;
 	}
-	pkt.u.bind_ack.num_results = call->pkt.u.bind.num_contexts;
-	pkt.u.bind_ack.ctx_list = ack_ctx_list;
-	pkt.u.bind_ack.auth_info = data_blob_null;
+	pkt->u.bind_ack.num_results = call->pkt.u.bind.num_contexts;
+	pkt->u.bind_ack.ctx_list = ack_ctx_list;
+	pkt->u.bind_ack.auth_info = data_blob_null;
 
-	status = dcesrv_auth_bind_ack(call, &pkt);
+	status = dcesrv_auth_bind_ack(call, pkt);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(call->context);
 		return dcesrv_bind_nak(call, 0);
@@ -1033,7 +1033,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	status = ncacn_push_auth(&rep->blob, call, &pkt,
+	status = ncacn_push_auth(&rep->blob, call, pkt,
 				 call->out_auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
 		TALLOC_FREE(call->context);
@@ -1337,7 +1337,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 {
 	NTSTATUS status;
 	bool auth_ok = false;
-	struct ncacn_packet pkt;
+	struct ncacn_packet *pkt = &call->ack_pkt;
 	uint32_t extra_flags = 0;
 	struct data_blob_list_item *rep = NULL;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
@@ -1430,20 +1430,20 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 		return dcesrv_fault_disconnect(call, DCERPC_FAULT_ACCESS_DENIED);
 	}
 
-	dcesrv_init_hdr(&pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
-	pkt.auth_length = 0;
-	pkt.call_id = call->pkt.call_id;
-	pkt.ptype = DCERPC_PKT_ALTER_RESP;
-	pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
-	pkt.u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
-	pkt.u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
-	pkt.u.alter_resp.assoc_group_id = call->conn->assoc_group->id;
-	pkt.u.alter_resp.secondary_address = "";
-	pkt.u.alter_resp.num_results = call->pkt.u.alter.num_contexts;
-	pkt.u.alter_resp.ctx_list = ack_ctx_list;
-	pkt.u.alter_resp.auth_info = data_blob_null;
-
-	status = dcesrv_auth_alter_ack(call, &pkt);
+	dcesrv_init_hdr(pkt, lpcfg_rpc_big_endian(call->conn->dce_ctx->lp_ctx));
+	pkt->auth_length = 0;
+	pkt->call_id = call->pkt.call_id;
+	pkt->ptype = DCERPC_PKT_ALTER_RESP;
+	pkt->pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST | extra_flags;
+	pkt->u.alter_resp.max_xmit_frag = call->conn->max_xmit_frag;
+	pkt->u.alter_resp.max_recv_frag = call->conn->max_recv_frag;
+	pkt->u.alter_resp.assoc_group_id = call->conn->assoc_group->id;
+	pkt->u.alter_resp.secondary_address = "";
+	pkt->u.alter_resp.num_results = call->pkt.u.alter.num_contexts;
+	pkt->u.alter_resp.ctx_list = ack_ctx_list;
+	pkt->u.alter_resp.auth_info = data_blob_null;
+
+	status = dcesrv_auth_alter_ack(call, pkt);
 	if (!NT_STATUS_IS_OK(status)) {
 		return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
 	}
@@ -1453,7 +1453,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	status = ncacn_push_auth(&rep->blob, call, &pkt, call->out_auth_info);
+	status = ncacn_push_auth(&rep->blob, call, pkt, call->out_auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 89377ab..9a64341 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -93,6 +93,11 @@ struct dcesrv_call_state {
 	struct ncacn_packet pkt;
 
 	/*
+	 * Used during async bind/alter_context.
+	 */
+	struct ncacn_packet ack_pkt;
+
+	/*
 	  which list this request is in, if any
 	 */
 	enum dcesrv_call_list list;
-- 
1.9.1


From 2dae7992a0be8cce86e47fbd0c01d2c541114832 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 08:11:29 +0200
Subject: [PATCH 02/24] s4:rpc_server: add wait_send/recv infrastructure

This will be used to implement async BIND/ALTER_CONTEXT/AUTH3
using gensec_update_send/recv.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 63 ++++++++++++++++++++++++++++++++++++++
 source4/rpc_server/dcerpc_server.h | 10 ++++++
 2 files changed, 73 insertions(+)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index a9f8854..0a8e7e5 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -2160,6 +2160,10 @@ static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, cons
 	srv_conn = talloc_get_type(dce_conn->transport.private_data,
 				   struct stream_connection);
 
+	dce_conn->wait_send = NULL;
+	dce_conn->wait_recv = NULL;
+	dce_conn->wait_private = NULL;
+
 	dce_conn->allow_bind = false;
 	dce_conn->allow_auth3 = false;
 	dce_conn->allow_alter = false;
@@ -2513,6 +2517,8 @@ static void dcesrv_sock_accept(struct stream_connection *srv_conn)
 	return;
 }
 
+static void dcesrv_conn_wait_done(struct tevent_req *subreq);
+
 static void dcesrv_read_fragment_done(struct tevent_req *subreq)
 {
 	struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
@@ -2548,6 +2554,63 @@ static void dcesrv_read_fragment_done(struct tevent_req *subreq)
 		return;
 	}
 
+	/*
+	 * This is used to block the connection during
+	 * pending authentication.
+	 */
+	if (dce_conn->wait_send != NULL) {
+		subreq = dce_conn->wait_send(dce_conn,
+					     dce_conn->event_ctx,
+					     dce_conn->wait_private);
+		if (!subreq) {
+			status = NT_STATUS_NO_MEMORY;
+			dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+			return;
+		}
+		tevent_req_set_callback(subreq, dcesrv_conn_wait_done, dce_conn);
+		return;
+	}
+
+	subreq = dcerpc_read_ncacn_packet_send(dce_conn,
+					       dce_conn->event_ctx,
+					       dce_conn->stream);
+	if (!subreq) {
+		status = NT_STATUS_NO_MEMORY;
+		dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+		return;
+	}
+	tevent_req_set_callback(subreq, dcesrv_read_fragment_done, dce_conn);
+}
+
+static void dcesrv_conn_wait_done(struct tevent_req *subreq)
+{
+	struct dcesrv_connection *dce_conn = tevent_req_callback_data(subreq,
+					     struct dcesrv_connection);
+	struct dcesrv_context *dce_ctx = dce_conn->dce_ctx;
+	NTSTATUS status;
+
+	if (dce_conn->terminate) {
+		/*
+		 * if the current connection is broken
+		 * we need to clean it up before any other connection
+		 */
+		dcesrv_terminate_connection(dce_conn, dce_conn->terminate);
+		dcesrv_cleanup_broken_connections(dce_ctx);
+		return;
+	}
+
+	dcesrv_cleanup_broken_connections(dce_ctx);
+
+	status = dce_conn->wait_recv(subreq);
+	dce_conn->wait_send = NULL;
+	dce_conn->wait_recv = NULL;
+	dce_conn->wait_private = NULL;
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		dcesrv_terminate_connection(dce_conn, nt_errstr(status));
+		return;
+	}
+
 	subreq = dcerpc_read_ncacn_packet_send(dce_conn,
 					       dce_conn->event_ctx,
 					       dce_conn->stream);
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 9a64341..c038075 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -288,6 +288,16 @@ struct dcesrv_connection {
 
 	/* the negotiated bind time features */
 	uint16_t bind_time_features;
+
+	/*
+	 * This is used to block the connection during
+	 * pending authentication.
+	 */
+	struct tevent_req *(*wait_send)(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					void *private_data);
+	NTSTATUS (*wait_recv)(struct tevent_req *req);
+	void *wait_private;
 };
 
 
-- 
1.9.1


From cd3bd5fbb808d7288f53a608dfab737ae90dd203 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 09:00:45 +0200
Subject: [PATCH 03/24] s4:rpc_server: split out dcesrv_auth_complete() from
 dcesrv_auth_bind_ack()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 67 +++++++++++++++++++++++++++-------------
 1 file changed, 46 insertions(+), 21 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 7b63598..3fda2aa 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -241,6 +241,51 @@ bool dcesrv_auth_bind(struct dcesrv_call_state *call)
 	return true;
 }
 
+NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
+{
+	struct dcesrv_connection *dce_conn = call->conn;
+	const char *pdu = "<unknown>";
+
+	switch (call->pkt.ptype) {
+	case DCERPC_PKT_BIND:
+		pdu = "BIND";
+		break;
+	case DCERPC_PKT_ALTER:
+		pdu = "ALTER";
+		break;
+	case DCERPC_PKT_AUTH3:
+		pdu = "AUTH3";
+		break;
+	default:
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+		return NT_STATUS_OK;
+	}
+
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(4, ("GENSEC mech rejected the incoming authentication "
+			  "at %s: %s\n", pdu, nt_errstr(status)));
+		return status;
+	}
+
+	status = gensec_session_info(dce_conn->auth_state.gensec_security,
+				     dce_conn,
+				     &dce_conn->auth_state.session_info);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(1, ("Failed to establish session_info: %s\n",
+			  nt_errstr(status)));
+		return status;
+	}
+	dce_conn->auth_state.auth_finished = true;
+	dce_conn->allow_request = true;
+
+	/* Now that we are authenticated, go back to the generic session key... */
+	dce_conn->auth_state.session_key = dcesrv_generic_session_key;
+	return NT_STATUS_OK;
+}
+
 /*
   add any auth information needed in a bind ack, and process the authentication
   information found in the bind.
@@ -279,28 +324,8 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
 			       call, call->event_ctx,
 			       call->in_auth_info.credentials,
 			       &call->out_auth_info->credentials);
-	
-	if (NT_STATUS_IS_OK(status)) {
-		status = gensec_session_info(dce_conn->auth_state.gensec_security,
-					     dce_conn,
-					     &dce_conn->auth_state.session_info);
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
-			return status;
-		}
-		dce_conn->auth_state.auth_finished = true;
-		dce_conn->allow_request = true;
 
-		/* Now that we are authenticated, go back to the generic session key... */
-		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
-		return NT_STATUS_OK;
-	} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		return NT_STATUS_OK;
-	} else {
-		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n",
-			  nt_errstr(status)));
-		return status;
-	}
+	return dcesrv_auth_complete(call, status);
 }
 
 
-- 
1.9.1


From 4dd75d3f43e8ccb6d8fee15a6e9637017cb34b56 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 09:14:21 +0200
Subject: [PATCH 04/24] s4:rpc_server: make use of dcesrv_auth_complete() in
 dcesrv_auth_alter_ack()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 22 +---------------------
 1 file changed, 1 insertion(+), 21 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 3fda2aa..3eeba2b 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -501,27 +501,7 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack
 			       call->in_auth_info.credentials,
 			       &call->out_auth_info->credentials);
 
-	if (NT_STATUS_IS_OK(status)) {
-		status = gensec_session_info(dce_conn->auth_state.gensec_security,
-					     dce_conn,
-					     &dce_conn->auth_state.session_info);
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
-			return status;
-		}
-		dce_conn->auth_state.auth_finished = true;
-		dce_conn->allow_request = true;
-
-		/* Now that we are authenticated, got back to the generic session key... */
-		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
-		return NT_STATUS_OK;
-	} else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		return NT_STATUS_OK;
-	}
-
-	DEBUG(4, ("GENSEC mech rejected the incoming authentication at auth alter_ack: %s\n",
-		  nt_errstr(status)));
-	return status;
+	return dcesrv_auth_complete(call, status);
 }
 
 /*
-- 
1.9.1


From 8ecf824614544256fafee0d7441a566c20d24ad7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 09:13:08 +0200
Subject: [PATCH 05/24] s4:rpc_server: prepare dcesrv_auth_complete() for AUTH3

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 3eeba2b..2a5271f 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -255,6 +255,10 @@ NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
 		break;
 	case DCERPC_PKT_AUTH3:
 		pdu = "AUTH3";
+		if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+			DEBUG(4, ("GENSEC not finished at at %s\n", pdu));
+			return NT_STATUS_RPC_SEC_PKG_ERROR;
+		}
 		break;
 	default:
 		return NT_STATUS_INTERNAL_ERROR;
@@ -283,6 +287,17 @@ NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
 
 	/* Now that we are authenticated, go back to the generic session key... */
 	dce_conn->auth_state.session_key = dcesrv_generic_session_key;
+
+	if (call->pkt.ptype != DCERPC_PKT_AUTH3) {
+		return NT_STATUS_OK;
+	}
+
+	if (call->out_auth_info->credentials.length != 0) {
+		DEBUG(4, ("GENSEC produced output token (len=%zu) at %s\n",
+			  call->out_auth_info->credentials.length, pdu));
+		return NT_STATUS_RPC_SEC_PKG_ERROR;
+	}
+
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From 8976ff195ab91b861c2387be060045ccec8a1a90 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 09:13:08 +0200
Subject: [PATCH 06/24] s4:rpc_server: make use of dcesrv_auth_complete() in
 dcesrv_auth_auth3()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 27 ++++-----------------------
 1 file changed, 4 insertions(+), 23 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 2a5271f..5e3df04 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -401,32 +401,13 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
 			       call, call->event_ctx,
 			       call->in_auth_info.credentials,
 			       &call->out_auth_info->credentials);
-	if (NT_STATUS_IS_OK(status)) {
-		status = gensec_session_info(dce_conn->auth_state.gensec_security,
-					     dce_conn,
-					     &dce_conn->auth_state.session_info);
-		if (!NT_STATUS_IS_OK(status)) {
-			DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
-			return false;
-		}
-		dce_conn->auth_state.auth_finished = true;
-		dce_conn->allow_request = true;
-
-		/* Now that we are authenticated, go back to the generic session key... */
-		dce_conn->auth_state.session_key = dcesrv_generic_session_key;
-
-		if (call->out_auth_info->credentials.length != 0) {
 
-			DEBUG(4, ("GENSEC produced output token (len=%u) at bind_auth3\n",
-				  (unsigned)call->out_auth_info->credentials.length));
-			return false;
-		}
-		return true;
-	} else {
-		DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
-			  nt_errstr(status)));
+	status = dcesrv_auth_complete(call, status);
+	if (!NT_STATUS_IS_OK(status)) {
 		return false;
 	}
+
+	return true;
 }
 
 /*
-- 
1.9.1


From c1fb11d985d8a69c0f8ab166ce7a04d890a33d9c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 12:16:35 +0200
Subject: [PATCH 07/24] s4:rpc_server: split out dcesrv_auth_prepare_bind_ack()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 5e3df04..ae3cebc 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -305,10 +305,9 @@ NTSTATUS dcesrv_auth_complete(struct dcesrv_call_state *call, NTSTATUS status)
   add any auth information needed in a bind ack, and process the authentication
   information found in the bind.
 */
-NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
 {
 	struct dcesrv_connection *dce_conn = call->conn;
-	NTSTATUS status;
 
 	dce_conn->allow_alter = true;
 	dce_conn->allow_auth3 = true;
@@ -335,6 +334,23 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
 	};
 	call->out_auth_info = &call->_out_auth_info;
 
+	return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+{
+	struct dcesrv_connection *dce_conn = call->conn;
+	NTSTATUS status;
+
+	status = dcesrv_auth_prepare_bind_ack(call, pkt);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (dce_conn->auth_state.auth_finished) {
+		return NT_STATUS_OK;
+	}
+
 	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
 			       call, call->event_ctx,
 			       call->in_auth_info.credentials,
-- 
1.9.1


From 087dd09b0ca8916148ebb3ba0f3ffd396aa7ae0c Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 12:16:35 +0200
Subject: [PATCH 08/24] s4:rpc_server: split out dcesrv_auth_prepare_auth3()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index ae3cebc..502173a 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -363,7 +363,7 @@ NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packe
 /*
   process the final stage of a auth request
 */
-bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
+bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call)
 {
 	struct ncacn_packet *pkt = &call->pkt;
 	struct dcesrv_connection *dce_conn = call->conn;
@@ -412,6 +412,20 @@ bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
 	};
 	call->out_auth_info = &call->_out_auth_info;
 
+	return true;
+}
+
+bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
+{
+	struct dcesrv_connection *dce_conn = call->conn;
+	NTSTATUS status;
+	bool ok;
+
+	ok = dcesrv_auth_prepare_auth3(call);
+	if (!ok) {
+		return false;
+	}
+
 	/* Pass the extra data we got from the client down to gensec for processing */
 	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
 			       call, call->event_ctx,
-- 
1.9.1


From 6a9891118b689f81c3d21e5de937d456ace7e243 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 12:16:35 +0200
Subject: [PATCH 09/24] s4:rpc_server: split out
 dcesrv_auth_prepare_alter_ack()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 502173a..108d268 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -500,10 +500,9 @@ bool dcesrv_auth_alter(struct dcesrv_call_state *call)
   add any auth information needed in a alter ack, and process the authentication
   information found in the alter.
 */
-NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
 {
 	struct dcesrv_connection *dce_conn = call->conn;
-	NTSTATUS status;
 
 	/* on a pure interface change there is no auth_info structure
 	   setup */
@@ -522,6 +521,23 @@ NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_pack
 	};
 	call->out_auth_info = &call->_out_auth_info;
 
+	return NT_STATUS_OK;
+}
+
+NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
+{
+	struct dcesrv_connection *dce_conn = call->conn;
+	NTSTATUS status;
+
+	status = dcesrv_auth_prepare_alter_ack(call, pkt);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (dce_conn->auth_state.auth_finished) {
+		return NT_STATUS_OK;
+	}
+
 	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
 			       call, call->event_ctx,
 			       call->in_auth_info.credentials,
-- 
1.9.1


From 5bc31a79a2eb62fc56816c24bdf7193769d7a027 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 17:36:17 +0200
Subject: [PATCH 10/24] s4:rpc_server: remove useless
 TALLOC_FREE(call->context) from dcesrv_bind()

This is not needed if we're terminating the connection anyway.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 0a8e7e5..34de071 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -965,8 +965,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	if (!dcesrv_auth_bind(call)) {
 		struct dcesrv_auth *auth = &call->conn->auth_state;
 
-		TALLOC_FREE(call->context);
-
 		if (auth->auth_level == DCERPC_AUTH_LEVEL_NONE) {
 			/*
 			 * With DCERPC_AUTH_LEVEL_NONE, we get the
@@ -1014,7 +1012,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 							   ep_prefix,
 							   endpoint);
 	if (pkt->u.bind_ack.secondary_address == NULL) {
-		TALLOC_FREE(call->context);
 		return NT_STATUS_NO_MEMORY;
 	}
 	pkt->u.bind_ack.num_results = call->pkt.u.bind.num_contexts;
@@ -1023,20 +1020,17 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 
 	status = dcesrv_auth_bind_ack(call, pkt);
 	if (!NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(call->context);
 		return dcesrv_bind_nak(call, 0);
 	}
 
 	rep = talloc_zero(call, struct data_blob_list_item);
 	if (!rep) {
-		TALLOC_FREE(call->context);
 		return NT_STATUS_NO_MEMORY;
 	}
 
 	status = ncacn_push_auth(&rep->blob, call, pkt,
 				 call->out_auth_info);
 	if (!NT_STATUS_IS_OK(status)) {
-		TALLOC_FREE(call->context);
 		return status;
 	}
 
-- 
1.9.1


From 63babe07a3ef9c3cadadd2294b1af3396073eb9f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 17:19:31 +0200
Subject: [PATCH 11/24] s4:rpc_server: split out dcesrv_auth_reply() from
 dcesrv_bind()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 34de071..f89a3fa 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -768,13 +768,14 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call);
+
 /*
   handle a bind request
 */
 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 {
 	struct ncacn_packet *pkt = &call->ack_pkt;
-	struct data_blob_list_item *rep;
 	NTSTATUS status;
 	uint32_t extra_flags = 0;
 	uint16_t max_req = 0;
@@ -1023,6 +1024,15 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 		return dcesrv_bind_nak(call, 0);
 	}
 
+	return dcesrv_auth_reply(call);
+}
+
+static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call)
+{
+	struct ncacn_packet *pkt = &call->ack_pkt;
+	struct data_blob_list_item *rep = NULL;
+	NTSTATUS status;
+
 	rep = talloc_zero(call, struct data_blob_list_item);
 	if (!rep) {
 		return NT_STATUS_NO_MEMORY;
-- 
1.9.1


From c2bd66ccbc1e2c55cebe8304dc8e91c5ccb32a8f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 17:37:05 +0200
Subject: [PATCH 12/24] s4:rpc_server: make use of dcesrv_auth_reply() in
 dcesrv_alter()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 24 +-----------------------
 1 file changed, 1 insertion(+), 23 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index f89a3fa..c2b531f 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1343,7 +1343,6 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 	bool auth_ok = false;
 	struct ncacn_packet *pkt = &call->ack_pkt;
 	uint32_t extra_flags = 0;
-	struct data_blob_list_item *rep = NULL;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
 	size_t i;
 
@@ -1452,28 +1451,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 		return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
 	}
 
-	rep = talloc_zero(call, struct data_blob_list_item);
-	if (!rep) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	status = ncacn_push_auth(&rep->blob, call, pkt, call->out_auth_info);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	dcerpc_set_frag_length(&rep->blob, rep->blob.length);
-
-	DLIST_ADD_END(call->replies, rep);
-	dcesrv_call_set_list(call, DCESRV_LIST_CALL_LIST);
-
-	if (call->conn->call_list && call->conn->call_list->replies) {
-		if (call->conn->transport.report_output_data) {
-			call->conn->transport.report_output_data(call->conn);
-		}
-	}
-
-	return NT_STATUS_OK;
+	return dcesrv_auth_reply(call);
 }
 
 /*
-- 
1.9.1


From eca76a8949c53436e1d9a8ceb8d3faac9e965f01 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 14:02:07 +0200
Subject: [PATCH 13/24] s4:rpc_server: make use of
 dcesrv_auth_prepare_bind_ack() in dcesrv_bind()

It means we also need to call gensec_update_ev() and dcesrv_auth_complete()
directly in dcesrv_bind(). Doing that will make it easier to make dcesrv_bind()
async in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index c2b531f..2f322ce 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -782,6 +782,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	uint16_t max_rep = 0;
 	const char *ep_prefix = "";
 	const char *endpoint = NULL;
+	struct dcesrv_auth *auth = &call->conn->auth_state;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
 	struct dcerpc_ack_ctx *ack_features = NULL;
 	size_t i;
@@ -964,7 +965,6 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	 * is being requested.
 	 */
 	if (!dcesrv_auth_bind(call)) {
-		struct dcesrv_auth *auth = &call->conn->auth_state;
 
 		if (auth->auth_level == DCERPC_AUTH_LEVEL_NONE) {
 			/*
@@ -1019,7 +1019,21 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	pkt->u.bind_ack.ctx_list = ack_ctx_list;
 	pkt->u.bind_ack.auth_info = data_blob_null;
 
-	status = dcesrv_auth_bind_ack(call, pkt);
+	status = dcesrv_auth_prepare_bind_ack(call, pkt);
+	if (!NT_STATUS_IS_OK(status)) {
+		return dcesrv_bind_nak(call, 0);
+	}
+
+	if (auth->auth_finished) {
+		return dcesrv_auth_reply(call);
+	}
+
+	status = gensec_update_ev(auth->gensec_security,
+				  call, call->event_ctx,
+				  call->in_auth_info.credentials,
+				  &call->out_auth_info->credentials);
+
+	status = dcesrv_auth_complete(call, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		return dcesrv_bind_nak(call, 0);
 	}
-- 
1.9.1


From f6894d56fa833cddaabb9744b0d36c94cc0245d1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 14:02:07 +0200
Subject: [PATCH 14/24] s4:rpc_server: make use of
 dcesrv_auth_prepare_alter_ack() in dcesrv_alter()

It means we also need to call gensec_update_ev() and dcesrv_auth_complete()
directly in dcesrv_alter(). Doing that will make it easier to make dcesrv_alter()
async in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 2f322ce..c650c63 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1357,6 +1357,7 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 	bool auth_ok = false;
 	struct ncacn_packet *pkt = &call->ack_pkt;
 	uint32_t extra_flags = 0;
+	struct dcesrv_auth *auth = &call->conn->auth_state;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
 	size_t i;
 
@@ -1460,7 +1461,21 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 	pkt->u.alter_resp.ctx_list = ack_ctx_list;
 	pkt->u.alter_resp.auth_info = data_blob_null;
 
-	status = dcesrv_auth_alter_ack(call, pkt);
+	status = dcesrv_auth_prepare_alter_ack(call, pkt);
+	if (!NT_STATUS_IS_OK(status)) {
+		return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
+	}
+
+	if (auth->auth_finished) {
+		return dcesrv_auth_reply(call);
+	}
+
+	status = gensec_update_ev(auth->gensec_security,
+				  call, call->event_ctx,
+				  call->in_auth_info.credentials,
+				  &call->out_auth_info->credentials);
+
+	status = dcesrv_auth_complete(call, status);
 	if (!NT_STATUS_IS_OK(status)) {
 		return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
 	}
-- 
1.9.1


From 4e545ce7b4ecd9421dee8e3d1510b030a0dcbcd8 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 14:02:07 +0200
Subject: [PATCH 15/24] s4:rpc_server: make use of dcesrv_auth_prepare_auth3()
 in dcesrv_auth3()

It means we also need to call gensec_update_ev() and dcesrv_auth_complete()
directly in dcesrv_auth3(). Doing that will make it easier to make dcesrv_auth3()
async in the next commits.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 40 ++++++++++++++++++++++++++++++++++----
 1 file changed, 36 insertions(+), 4 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index c650c63..40b942a 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1078,6 +1078,7 @@ static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call)
 */
 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 {
+	struct dcesrv_auth *auth = &call->conn->auth_state;
 	NTSTATUS status;
 
 	if (!call->conn->allow_auth3) {
@@ -1105,17 +1106,48 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 	}
 
 	/* handle the auth3 in the auth code */
-	if (!dcesrv_auth_auth3(call)) {
+	if (!dcesrv_auth_prepare_auth3(call)) {
+		/*
+		 * we don't send a reply to a auth3 request,
+		 * except by a fault.
+		 *
+		 * In anycase we mark the connection as
+		 * invalid.
+		 */
 		call->conn->auth_state.auth_invalid = true;
 		if (call->fault_code != 0) {
 			return dcesrv_fault_disconnect(call, call->fault_code);
 		}
+		TALLOC_FREE(call);
+		return NT_STATUS_OK;
 	}
 
-	talloc_free(call);
+	status = gensec_update_ev(auth->gensec_security,
+				  call, call->event_ctx,
+				  call->in_auth_info.credentials,
+				  &call->out_auth_info->credentials);
 
-	/* we don't send a reply to a auth3 request, except by a
-	   fault */
+	status = dcesrv_auth_complete(call, status);
+	if (!NT_STATUS_IS_OK(status)) {
+		/*
+		 * we don't send a reply to a auth3 request,
+		 * except by a fault.
+		 *
+		 * In anycase we mark the connection as
+		 * invalid.
+		 */
+		call->conn->auth_state.auth_invalid = true;
+		if (call->fault_code != 0) {
+			return dcesrv_fault_disconnect(call, call->fault_code);
+		}
+		TALLOC_FREE(call);
+		return NT_STATUS_OK;
+	}
+
+	/*
+	 * we don't send a reply to a auth3 request.
+	 */
+	TALLOC_FREE(call);
 	return NT_STATUS_OK;
 }
 
-- 
1.9.1


From 9d03195213b3994a23ffc1206f8e48843845a866 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 14:03:54 +0200
Subject: [PATCH 16/24] s4:rpc_server: remove unused
 dcesrv_auth_{bind_ack,auth3,alter_ack}()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcesrv_auth.c | 70 ----------------------------------------
 1 file changed, 70 deletions(-)

diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 108d268..d48d03e 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -337,29 +337,6 @@ NTSTATUS dcesrv_auth_prepare_bind_ack(struct dcesrv_call_state *call, struct nca
 	return NT_STATUS_OK;
 }
 
-NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
-{
-	struct dcesrv_connection *dce_conn = call->conn;
-	NTSTATUS status;
-
-	status = dcesrv_auth_prepare_bind_ack(call, pkt);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	if (dce_conn->auth_state.auth_finished) {
-		return NT_STATUS_OK;
-	}
-
-	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
-			       call, call->event_ctx,
-			       call->in_auth_info.credentials,
-			       &call->out_auth_info->credentials);
-
-	return dcesrv_auth_complete(call, status);
-}
-
-
 /*
   process the final stage of a auth request
 */
@@ -415,31 +392,6 @@ bool dcesrv_auth_prepare_auth3(struct dcesrv_call_state *call)
 	return true;
 }
 
-bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
-{
-	struct dcesrv_connection *dce_conn = call->conn;
-	NTSTATUS status;
-	bool ok;
-
-	ok = dcesrv_auth_prepare_auth3(call);
-	if (!ok) {
-		return false;
-	}
-
-	/* Pass the extra data we got from the client down to gensec for processing */
-	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
-			       call, call->event_ctx,
-			       call->in_auth_info.credentials,
-			       &call->out_auth_info->credentials);
-
-	status = dcesrv_auth_complete(call, status);
-	if (!NT_STATUS_IS_OK(status)) {
-		return false;
-	}
-
-	return true;
-}
-
 /*
   parse any auth information from a dcerpc alter request
   return false if we can't handle the auth request for some 
@@ -524,28 +476,6 @@ NTSTATUS dcesrv_auth_prepare_alter_ack(struct dcesrv_call_state *call, struct nc
 	return NT_STATUS_OK;
 }
 
-NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
-{
-	struct dcesrv_connection *dce_conn = call->conn;
-	NTSTATUS status;
-
-	status = dcesrv_auth_prepare_alter_ack(call, pkt);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
-	}
-
-	if (dce_conn->auth_state.auth_finished) {
-		return NT_STATUS_OK;
-	}
-
-	status = gensec_update_ev(dce_conn->auth_state.gensec_security,
-			       call, call->event_ctx,
-			       call->in_auth_info.credentials,
-			       &call->out_auth_info->credentials);
-
-	return dcesrv_auth_complete(call, status);
-}
-
 /*
   check credentials on a packet
 */
-- 
1.9.1


From 98ddc599709f4f2f50dac0460159f4cde6e2c692 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 15:20:56 +0200
Subject: [PATCH 17/24] s4:rpc_server: implement async BIND using
 gensec_update_send/recv

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 125 +++++++++++++++++++++++++++++++++++--
 1 file changed, 119 insertions(+), 6 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 40b942a..225f5e7 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -41,6 +41,7 @@
 #include "librpc/rpc/rpc_common.h"
 #include "lib/util/samba_modules.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "../lib/util/tevent_ntstatus.h"
 
 static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call,
 				const struct dcerpc_bind *b,
@@ -768,13 +769,102 @@ _PUBLIC_ NTSTATUS dcesrv_interface_bind_allow_connect(struct dcesrv_call_state *
 	return NT_STATUS_OK;
 }
 
+struct dcesrv_conn_auth_wait_context {
+	struct tevent_req *req;
+	bool done;
+	NTSTATUS status;
+};
+
+struct dcesrv_conn_auth_wait_state {
+	uint8_t dummy;
+};
+
+static struct tevent_req *dcesrv_conn_auth_wait_send(TALLOC_CTX *mem_ctx,
+						     struct tevent_context *ev,
+						     void *private_data)
+{
+	struct dcesrv_conn_auth_wait_context *auth_wait =
+		talloc_get_type_abort(private_data,
+		struct dcesrv_conn_auth_wait_context);
+	struct tevent_req *req = NULL;
+	struct dcesrv_conn_auth_wait_state *state = NULL;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct dcesrv_conn_auth_wait_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	auth_wait->req = req;
+
+	tevent_req_defer_callback(req, ev);
+
+	if (!auth_wait->done) {
+		return req;
+	}
+
+	if (tevent_req_nterror(req, auth_wait->status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_done(req);
+	return tevent_req_post(req, ev);
+}
+
+static NTSTATUS dcesrv_conn_auth_wait_recv(struct tevent_req *req)
+{
+	return tevent_req_simple_recv_ntstatus(req);
+}
+
+static NTSTATUS dcesrv_conn_auth_wait_setup(struct dcesrv_connection *conn)
+{
+	struct dcesrv_conn_auth_wait_context *auth_wait = NULL;
+
+	if (conn->wait_send != NULL) {
+		return NT_STATUS_INTERNAL_ERROR;
+	}
+
+	auth_wait = talloc_zero(conn, struct dcesrv_conn_auth_wait_context);
+	if (auth_wait == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	conn->wait_private = auth_wait;
+	conn->wait_send = dcesrv_conn_auth_wait_send;
+	conn->wait_recv = dcesrv_conn_auth_wait_recv;
+	return NT_STATUS_OK;
+}
+
+static void dcesrv_conn_auth_wait_finished(struct dcesrv_connection *conn,
+					   NTSTATUS status)
+{
+	struct dcesrv_conn_auth_wait_context *auth_wait =
+		talloc_get_type_abort(conn->wait_private,
+		struct dcesrv_conn_auth_wait_context);
+
+	auth_wait->done = true;
+	auth_wait->status = status;
+
+	if (auth_wait->req == NULL) {
+		return;
+	}
+
+	if (tevent_req_nterror(auth_wait->req, status)) {
+		return;
+	}
+
+	tevent_req_done(auth_wait->req);
+}
+
 static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call);
 
+static void dcesrv_bind_done(struct tevent_req *subreq);
+
 /*
   handle a bind request
 */
 static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 {
+	struct dcesrv_connection *conn = call->conn;
 	struct ncacn_packet *pkt = &call->ack_pkt;
 	NTSTATUS status;
 	uint32_t extra_flags = 0;
@@ -785,6 +875,7 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 	struct dcesrv_auth *auth = &call->conn->auth_state;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
 	struct dcerpc_ack_ctx *ack_features = NULL;
+	struct tevent_req *subreq = NULL;
 	size_t i;
 
 	status = dcerpc_verify_ncacn_packet_header(&call->pkt,
@@ -1028,17 +1119,39 @@ static NTSTATUS dcesrv_bind(struct dcesrv_call_state *call)
 		return dcesrv_auth_reply(call);
 	}
 
-	status = gensec_update_ev(auth->gensec_security,
-				  call, call->event_ctx,
-				  call->in_auth_info.credentials,
-				  &call->out_auth_info->credentials);
+	subreq = gensec_update_send(call, call->event_ctx,
+				    auth->gensec_security,
+				    call->in_auth_info.credentials);
+	if (subreq == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq, dcesrv_bind_done, call);
+
+	return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_bind_done(struct tevent_req *subreq)
+{
+	struct dcesrv_call_state *call =
+		tevent_req_callback_data(subreq,
+		struct dcesrv_call_state);
+	struct dcesrv_connection *conn = call->conn;
+	NTSTATUS status;
+
+	status = gensec_update_recv(subreq, call,
+				    &call->out_auth_info->credentials);
+	TALLOC_FREE(subreq);
 
 	status = dcesrv_auth_complete(call, status);
 	if (!NT_STATUS_IS_OK(status)) {
-		return dcesrv_bind_nak(call, 0);
+		status = dcesrv_bind_nak(call, 0);
+		dcesrv_conn_auth_wait_finished(conn, status);
+		return;
 	}
 
-	return dcesrv_auth_reply(call);
+	status = dcesrv_auth_reply(call);
+	dcesrv_conn_auth_wait_finished(conn, status);
+	return;
 }
 
 static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call)
-- 
1.9.1


From 5a7fd71bafa6b880186fb8dc06e57d9d17eeaae7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 15:20:56 +0200
Subject: [PATCH 18/24] s4:rpc_server: implement async ALTER_CONTEXT using
 gensec_update_send/recv

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 38 ++++++++++++++++++++++++++++++++------
 1 file changed, 32 insertions(+), 6 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 225f5e7..5deeb7c 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1493,17 +1493,21 @@ static NTSTATUS dcesrv_negotiate_contexts(struct dcesrv_call_state *call,
 	return NT_STATUS_OK;
 }
 
+static void dcesrv_alter_done(struct tevent_req *subreq);
+
 /*
   handle a alter context request
 */
 static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 {
+	struct dcesrv_connection *conn = call->conn;
 	NTSTATUS status;
 	bool auth_ok = false;
 	struct ncacn_packet *pkt = &call->ack_pkt;
 	uint32_t extra_flags = 0;
 	struct dcesrv_auth *auth = &call->conn->auth_state;
 	struct dcerpc_ack_ctx *ack_ctx_list = NULL;
+	struct tevent_req *subreq = NULL;
 	size_t i;
 
 	if (!call->conn->allow_alter) {
@@ -1615,17 +1619,39 @@ static NTSTATUS dcesrv_alter(struct dcesrv_call_state *call)
 		return dcesrv_auth_reply(call);
 	}
 
-	status = gensec_update_ev(auth->gensec_security,
-				  call, call->event_ctx,
-				  call->in_auth_info.credentials,
-				  &call->out_auth_info->credentials);
+	subreq = gensec_update_send(call, call->event_ctx,
+				    auth->gensec_security,
+				    call->in_auth_info.credentials);
+	if (subreq == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq, dcesrv_alter_done, call);
+
+	return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_alter_done(struct tevent_req *subreq)
+{
+	struct dcesrv_call_state *call =
+		tevent_req_callback_data(subreq,
+		struct dcesrv_call_state);
+	struct dcesrv_connection *conn = call->conn;
+	NTSTATUS status;
+
+	status = gensec_update_recv(subreq, call,
+				    &call->out_auth_info->credentials);
+	TALLOC_FREE(subreq);
 
 	status = dcesrv_auth_complete(call, status);
 	if (!NT_STATUS_IS_OK(status)) {
-		return dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
+		status = dcesrv_fault_disconnect(call, DCERPC_FAULT_SEC_PKG_ERROR);
+		dcesrv_conn_auth_wait_finished(conn, status);
+		return;
 	}
 
-	return dcesrv_auth_reply(call);
+	status = dcesrv_auth_reply(call);
+	dcesrv_conn_auth_wait_finished(conn, status);
+	return;
 }
 
 /*
-- 
1.9.1


From 76a42f71c961b76d869785660ba191fe1007061b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 15:20:56 +0200
Subject: [PATCH 19/24] s4:rpc_server: implement async AUTH3 using
 gensec_update_send/recv

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/dcerpc_server.c | 40 +++++++++++++++++++++++++++++++-------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 5deeb7c..de919e2 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -1186,12 +1186,16 @@ static NTSTATUS dcesrv_auth_reply(struct dcesrv_call_state *call)
 }
 
 
+static void dcesrv_auth3_done(struct tevent_req *subreq);
+
 /*
   handle a auth3 request
 */
 static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 {
+	struct dcesrv_connection *conn = call->conn;
 	struct dcesrv_auth *auth = &call->conn->auth_state;
+	struct tevent_req *subreq = NULL;
 	NTSTATUS status;
 
 	if (!call->conn->allow_auth3) {
@@ -1235,10 +1239,28 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 		return NT_STATUS_OK;
 	}
 
-	status = gensec_update_ev(auth->gensec_security,
-				  call, call->event_ctx,
-				  call->in_auth_info.credentials,
-				  &call->out_auth_info->credentials);
+	subreq = gensec_update_send(call, call->event_ctx,
+				    auth->gensec_security,
+				    call->in_auth_info.credentials);
+	if (subreq == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+	tevent_req_set_callback(subreq, dcesrv_auth3_done, call);
+
+	return dcesrv_conn_auth_wait_setup(conn);
+}
+
+static void dcesrv_auth3_done(struct tevent_req *subreq)
+{
+	struct dcesrv_call_state *call =
+		tevent_req_callback_data(subreq,
+		struct dcesrv_call_state);
+	struct dcesrv_connection *conn = call->conn;
+	NTSTATUS status;
+
+	status = gensec_update_recv(subreq, call,
+				    &call->out_auth_info->credentials);
+	TALLOC_FREE(subreq);
 
 	status = dcesrv_auth_complete(call, status);
 	if (!NT_STATUS_IS_OK(status)) {
@@ -1251,17 +1273,21 @@ static NTSTATUS dcesrv_auth3(struct dcesrv_call_state *call)
 		 */
 		call->conn->auth_state.auth_invalid = true;
 		if (call->fault_code != 0) {
-			return dcesrv_fault_disconnect(call, call->fault_code);
+			status = dcesrv_fault_disconnect(call, call->fault_code);
+			dcesrv_conn_auth_wait_finished(conn, status);
+			return;
 		}
 		TALLOC_FREE(call);
-		return NT_STATUS_OK;
+		dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK);
+		return;
 	}
 
 	/*
 	 * we don't send a reply to a auth3 request.
 	 */
 	TALLOC_FREE(call);
-	return NT_STATUS_OK;
+	dcesrv_conn_auth_wait_finished(conn, NT_STATUS_OK);
+	return;
 }
 
 
-- 
1.9.1


From a5ab80ac4596c48c3af70f08e70124c03ae355aa Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 22:36:20 +0200
Subject: [PATCH 20/24] s4:librpc: use gensec_update_send() in
 dcerpc_bind_auth_send()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/librpc/rpc/dcerpc_auth.c | 53 ++++++++++++++++++++++++++--------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index e790a9f..ee13a6b 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -136,6 +136,8 @@ _PUBLIC_ NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
 
 struct bind_auth_state {
 	struct dcerpc_pipe *pipe;
+	struct ndr_syntax_id syntax;
+	struct ndr_syntax_id transfer_syntax;
 	struct dcerpc_auth out_auth_info;
 	struct dcerpc_auth in_auth_info;
 	bool more_processing;	/* Is there anything more to do after the
@@ -289,6 +291,8 @@ static void bind_auth_recv_bindreply(struct tevent_req *subreq)
 }
 
 
+static void dcerpc_bind_auth_gensec_done(struct tevent_req *subreq);
+
 /**
    Bind to a DCE/RPC pipe, send async request
    @param mem_ctx TALLOC_CTX for the allocation of the composite_context
@@ -313,7 +317,6 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 	struct bind_auth_state *state;
 	struct dcecli_security *sec;
 	struct tevent_req *subreq;
-	struct ndr_syntax_id syntax, transfer_syntax;
 	const char *target_principal = NULL;
 
 	/* composite context allocation and setup */
@@ -327,8 +330,8 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 	state->pipe = p;
 
 	c->status = dcerpc_init_syntaxes(p, table,
-					 &syntax,
-					 &transfer_syntax);
+					 &state->syntax,
+					 &state->transfer_syntax);
 	if (!composite_is_ok(c)) return c;
 
 	sec = &p->conn->security_state;
@@ -420,22 +423,34 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 	 * it doesn't like that either
 	 */
 
-	state->pipe->inhibit_timeout_processing = true;
-	state->pipe->timed_out = false;
-	c->status = gensec_update_ev(sec->generic_state, state,
-				  p->conn->event_ctx,
-				  data_blob_null,
-				  &state->out_auth_info.credentials);
-	if (state->pipe->timed_out) {
-		composite_error(c, NT_STATUS_IO_TIMEOUT);
-		return c;
-	}
-	state->pipe->inhibit_timeout_processing = false;
+	subreq = gensec_update_send(state,
+				    p->conn->event_ctx,
+				    sec->generic_state,
+				    data_blob_null);
+	if (composite_nomem(subreq, c)) return c;
+	tevent_req_set_callback(subreq, dcerpc_bind_auth_gensec_done, c);
 
+	return c;
+}
+
+static void dcerpc_bind_auth_gensec_done(struct tevent_req *subreq)
+{
+	struct composite_context *c =
+		tevent_req_callback_data(subreq,
+		struct composite_context);
+	struct bind_auth_state *state =
+		talloc_get_type_abort(c->private_data,
+		struct bind_auth_state);
+	struct dcerpc_pipe *p = state->pipe;
+	struct dcecli_security *sec = &p->conn->security_state;
+
+	c->status = gensec_update_recv(subreq, state,
+				       &state->out_auth_info.credentials);
+	TALLOC_FREE(subreq);
 	if (!NT_STATUS_IS_OK(c->status) &&
 	    !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		composite_error(c, c->status);
-		return c;
+		return;
 	}
 
 	state->more_processing = NT_STATUS_EQUAL(c->status,
@@ -443,7 +458,7 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 
 	if (state->out_auth_info.credentials.length == 0) {
 		composite_done(c);
-		return c;
+		return;
 	}
 
 	if (gensec_have_feature(sec->generic_state, GENSEC_FEATURE_SIGN_PKT_HEADER)) {
@@ -462,11 +477,11 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 	/* The first request always is a dcerpc_bind. The subsequent ones
 	 * depend on gensec results */
 	subreq = dcerpc_bind_send(state, p->conn->event_ctx, p,
-				  &syntax, &transfer_syntax);
-	if (composite_nomem(subreq, c)) return c;
+				  &state->syntax, &state->transfer_syntax);
+	if (composite_nomem(subreq, c)) return;
 	tevent_req_set_callback(subreq, bind_auth_recv_bindreply, c);
 
-	return c;
+	return;
 }
 
 
-- 
1.9.1


From 8cdce31c06d9b66e5178f60a9b63f8dcd7237564 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 22:46:39 +0200
Subject: [PATCH 21/24] s4:librpc: make use of gensec_update_send() in
 bind_auth_next_step()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/librpc/rpc/dcerpc_auth.c | 35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index ee13a6b..a2d1418 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -144,6 +144,7 @@ struct bind_auth_state {
 				 * first bind itself received? */
 };
 
+static void bind_auth_next_gensec_done(struct tevent_req *subreq);
 static void bind_auth_recv_alter(struct tevent_req *subreq);
 
 static void bind_auth_next_step(struct composite_context *c)
@@ -151,7 +152,6 @@ static void bind_auth_next_step(struct composite_context *c)
 	struct bind_auth_state *state;
 	struct dcecli_security *sec;
 	struct tevent_req *subreq;
-	bool more_processing = false;
 
 	state = talloc_get_type(c->private_data, struct bind_auth_state);
 	sec = &state->pipe->conn->security_state;
@@ -187,18 +187,29 @@ static void bind_auth_next_step(struct composite_context *c)
 	 * it doesn't like that either
 	 */
 
-	state->pipe->inhibit_timeout_processing = true;
-	state->pipe->timed_out = false;
+	subreq = gensec_update_send(state,
+				    state->pipe->conn->event_ctx,
+				    sec->generic_state,
+				    state->in_auth_info.credentials);
+	if (composite_nomem(subreq, c)) return;
+	tevent_req_set_callback(subreq, bind_auth_next_gensec_done, c);
+}
 
-	c->status = gensec_update_ev(sec->generic_state, state,
-				  state->pipe->conn->event_ctx,
-				  state->in_auth_info.credentials,
-				  &state->out_auth_info.credentials);
-	if (state->pipe->timed_out) {
-		composite_error(c, NT_STATUS_IO_TIMEOUT);
-		return;
-	}
-	state->pipe->inhibit_timeout_processing = false;
+static void bind_auth_next_gensec_done(struct tevent_req *subreq)
+{
+	struct composite_context *c =
+		tevent_req_callback_data(subreq,
+		struct composite_context);
+	struct bind_auth_state *state =
+		talloc_get_type_abort(c->private_data,
+		struct bind_auth_state);
+	struct dcerpc_pipe *p = state->pipe;
+	struct dcecli_security *sec = &p->conn->security_state;
+	bool more_processing = false;
+
+	c->status = gensec_update_recv(subreq, state,
+				       &state->out_auth_info.credentials);
+	TALLOC_FREE(subreq);
 
 	if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		more_processing = true;
-- 
1.9.1


From f9dbfce95beabcc54a24b69c59e384a9d54eb8db Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 22:49:09 +0200
Subject: [PATCH 22/24] s4:librpc: simplify dcerpc_connect_timeout_handler()
 logic

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/librpc/rpc/dcerpc.h         |  8 --------
 source4/librpc/rpc/dcerpc_connect.c | 10 +---------
 2 files changed, 1 insertion(+), 17 deletions(-)

diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 3223948..eaa3c62 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -136,14 +136,6 @@ struct dcerpc_pipe {
 	/** timeout for individual rpc requests, in seconds */
 	uint32_t request_timeout;
 
-	/*
-	 * Set for the timeout in dcerpc_pipe_connect_b_send(), to
-	 * allow the timeout not to destory the stack during a nested
-	 * event loop caused by gensec_update()
-	 */
-	bool inhibit_timeout_processing;
-	bool timed_out;
-
 	bool verified_pcontext;
 };
 
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 8ed1257..723e657 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -1004,12 +1004,7 @@ static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tev
 {
 	struct composite_context *c = talloc_get_type_abort(private_data,
 						      struct composite_context);
-	struct pipe_connect_state *s = talloc_get_type_abort(c->private_data, struct pipe_connect_state);
-	if (!s->pipe->inhibit_timeout_processing) {
-		composite_error(c, NT_STATUS_IO_TIMEOUT);
-	} else {
-		s->pipe->timed_out = true;
-	}
+	composite_error(c, NT_STATUS_IO_TIMEOUT);
 }
 
 /*
@@ -1053,9 +1048,6 @@ _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent
 	s->credentials  = credentials;
 	s->lp_ctx 	= lp_ctx;
 
-	s->pipe->timed_out = false;
-	s->pipe->inhibit_timeout_processing = false;
-
 	tevent_add_timer(c->event_ctx, c,
 			 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
 			 dcerpc_connect_timeout_handler, c);
-- 
1.9.1


From 789053e634601ec485f9117577e1571e319cb40e Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 23:37:22 +0200
Subject: [PATCH 23/24] s4:libcli/smb2: make smb2_session_setup_spnego_*
 completely async

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/smb2/session.c | 253 ++++++++++++++++++++++++++----------------
 1 file changed, 160 insertions(+), 93 deletions(-)

diff --git a/source4/libcli/smb2/session.c b/source4/libcli/smb2/session.c
index c96693b..e3e54cb 100644
--- a/source4/libcli/smb2/session.c
+++ b/source4/libcli/smb2/session.c
@@ -115,11 +115,17 @@ struct smb2_session_setup_spnego_state {
 	bool session_bind;
 	bool reauth;
 	NTSTATUS gensec_status;
+	NTSTATUS remote_status;
 	DATA_BLOB in_secblob;
 	DATA_BLOB out_secblob;
+	struct iovec *recv_iov;
 };
 
-static void smb2_session_setup_spnego_done(struct tevent_req *subreq);
+static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req);
+static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq);
+static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req);
+static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq);
+static void smb2_session_setup_spnego_both_ready(struct tevent_req *req);
 
 /*
   a composite function that does a full SPNEGO session setup
@@ -131,18 +137,15 @@ struct tevent_req *smb2_session_setup_spnego_send(
 				struct cli_credentials *credentials,
 				uint64_t previous_session_id)
 {
+	struct smb2_transport *transport = session->transport;
 	struct tevent_req *req;
 	struct smb2_session_setup_spnego_state *state;
 	uint64_t current_session_id;
 	const char *chosen_oid;
-	struct tevent_req *subreq;
 	NTSTATUS status;
 	const DATA_BLOB *server_gss_blob;
-	DATA_BLOB negprot_secblob = data_blob_null;
-	uint32_t timeout_msec;
-	uint8_t in_flags = 0;
-
-	timeout_msec = session->transport->options.request_timeout * 1000;
+	struct timeval endtime;
+	bool ok;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smb2_session_setup_spnego_state);
@@ -153,6 +156,16 @@ struct tevent_req *smb2_session_setup_spnego_send(
 	state->session = session;
 	state->credentials = credentials;
 	state->previous_session_id = previous_session_id;
+	state->gensec_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+	state->remote_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+
+	endtime = timeval_current_ofs(transport->options.request_timeout, 0);
+
+	ok = tevent_req_set_endtime(req, ev, endtime);
+	if (!ok) {
+		tevent_req_oom(req);
+		return tevent_req_post(req, ev);
+	}
 
 	current_session_id = smb2cli_session_current_id(state->session->smbXcli);
 	if (state->session->needs_bind) {
@@ -162,7 +175,7 @@ struct tevent_req *smb2_session_setup_spnego_send(
 	}
 	server_gss_blob = smbXcli_conn_server_gss_blob(session->transport->conn);
 	if (server_gss_blob) {
-		negprot_secblob = *server_gss_blob;
+		state->out_secblob = *server_gss_blob;
 	}
 
 	status = gensec_set_credentials(session->gensec, credentials);
@@ -181,7 +194,7 @@ struct tevent_req *smb2_session_setup_spnego_send(
 		return tevent_req_post(req, ev);
 	}
 
-	if (negprot_secblob.length > 0) {
+	if (state->out_secblob.length > 0) {
 		chosen_oid = GENSEC_OID_SPNEGO;
 	} else {
 		chosen_oid = GENSEC_OID_NTLMSSP;
@@ -192,15 +205,83 @@ struct tevent_req *smb2_session_setup_spnego_send(
 		return tevent_req_post(req, ev);
 	}
 
-	status = gensec_update_ev(session->gensec, state,
-			       state->ev,
-			       negprot_secblob,
-			       &state->in_secblob);
-	if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		tevent_req_nterror(req, status);
+	smb2_session_setup_spnego_gensec_next(req);
+	if (!tevent_req_is_in_progress(req)) {
 		return tevent_req_post(req, ev);
 	}
+
+	return req;
+}
+
+static void smb2_session_setup_spnego_gensec_next(struct tevent_req *req)
+{
+	struct smb2_session_setup_spnego_state *state =
+		tevent_req_data(req,
+		struct smb2_session_setup_spnego_state);
+	struct smb2_session *session = state->session;
+	struct tevent_req *subreq = NULL;
+
+	if (NT_STATUS_IS_OK(state->gensec_status)) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+
+	subreq = gensec_update_send(state, state->ev,
+				    session->gensec,
+				    state->out_secblob);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq,
+				smb2_session_setup_spnego_gensec_done,
+				req);
+}
+
+static void smb2_session_setup_spnego_gensec_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct smb2_session_setup_spnego_state *state =
+		tevent_req_data(req,
+		struct smb2_session_setup_spnego_state);
+	NTSTATUS status;
+
+	status = gensec_update_recv(subreq, state,
+				    &state->in_secblob);
 	state->gensec_status = status;
+	state->out_secblob = data_blob_null;
+	if (!NT_STATUS_IS_OK(status) &&
+	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+
+	if (NT_STATUS_IS_OK(state->remote_status) &&
+	    NT_STATUS_IS_OK(state->gensec_status)) {
+		smb2_session_setup_spnego_both_ready(req);
+		return;
+	}
+
+	smb2_session_setup_spnego_smb2_next(req);
+}
+
+static void smb2_session_setup_spnego_smb2_next(struct tevent_req *req)
+{
+	struct smb2_session_setup_spnego_state *state =
+		tevent_req_data(req,
+		struct smb2_session_setup_spnego_state);
+	struct smb2_session *session = state->session;
+	uint32_t timeout_msec;
+	uint8_t in_flags = 0;
+	struct tevent_req *subreq = NULL;
+
+	if (NT_STATUS_IS_OK(state->remote_status)) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
+
+	timeout_msec = session->transport->options.request_timeout * 1000;
 
 	if (state->session_bind) {
 		in_flags |= SMB2_SESSION_FLAG_BINDING;
@@ -216,17 +297,17 @@ struct tevent_req *smb2_session_setup_spnego_send(
 					    state->previous_session_id,
 					    &state->in_secblob);
 	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
+		return;
 	}
-	tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
-
-	return req;
+	tevent_req_set_callback(subreq,
+				smb2_session_setup_spnego_smb2_done,
+				req);
 }
 
 /*
   handle continuations of the spnego session setup
 */
-static void smb2_session_setup_spnego_done(struct tevent_req *subreq)
+static void smb2_session_setup_spnego_smb2_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req =
 		tevent_req_callback_data(subreq,
@@ -234,104 +315,90 @@ static void smb2_session_setup_spnego_done(struct tevent_req *subreq)
 	struct smb2_session_setup_spnego_state *state =
 		tevent_req_data(req,
 		struct smb2_session_setup_spnego_state);
-	struct smb2_session *session = state->session;
-	NTSTATUS peer_status;
 	NTSTATUS status;
-	struct iovec *recv_iov;
-	uint32_t timeout_msec;
-	uint8_t in_flags = 0;
-
-	timeout_msec = session->transport->options.request_timeout * 1000;
 
 	status = smb2cli_session_setup_recv(subreq, state,
-					    &recv_iov,
+					    &state->recv_iov,
 					    &state->out_secblob);
+	state->remote_status = status;
+	state->in_secblob = data_blob_null;
 	if (!NT_STATUS_IS_OK(status) &&
 	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		tevent_req_nterror(req, status);
 		return;
 	}
-	peer_status = status;
 
-	if (NT_STATUS_EQUAL(state->gensec_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		status = gensec_update_ev(session->gensec, state,
-				       state->ev,
-				       state->out_secblob,
-				       &state->in_secblob);
-		state->gensec_status = status;
-	}
-
-	if (!NT_STATUS_IS_OK(status) &&
-	    !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
-		tevent_req_nterror(req, status);
+	if (NT_STATUS_IS_OK(state->remote_status) &&
+	    NT_STATUS_IS_OK(state->gensec_status)) {
+		smb2_session_setup_spnego_both_ready(req);
 		return;
 	}
 
-	if (NT_STATUS_IS_OK(peer_status) && NT_STATUS_IS_OK(state->gensec_status)) {
-		DATA_BLOB session_key;
+	smb2_session_setup_spnego_gensec_next(req);
+}
 
-		if (state->reauth) {
-			tevent_req_done(req);
-			return;
-		}
+static void smb2_session_setup_spnego_both_ready(struct tevent_req *req)
+{
+	struct smb2_session_setup_spnego_state *state =
+		tevent_req_data(req,
+		struct smb2_session_setup_spnego_state);
+	struct smb2_session *session = state->session;
+	NTSTATUS status;
+	DATA_BLOB session_key;
 
-		if (cli_credentials_is_anonymous(state->credentials)) {
-			/*
-			 * Windows server does not set the
-			 * SMB2_SESSION_FLAG_IS_GUEST nor
-			 * SMB2_SESSION_FLAG_IS_NULL flag.
-			 *
-			 * This fix makes sure we do not try
-			 * to verify a signature on the final
-			 * session setup response.
-			 */
-			tevent_req_done(req);
-			return;
-		}
+	if (state->out_secblob.length != 0) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
 
-		status = gensec_session_key(session->gensec, state,
-					    &session_key);
-		if (tevent_req_nterror(req, status)) {
-			return;
-		}
+	if (state->in_secblob.length != 0) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+		return;
+	}
 
-		if (state->session_bind) {
-			status = smb2cli_session_set_channel_key(session->smbXcli,
-								 session_key,
-								 recv_iov);
-			if (tevent_req_nterror(req, status)) {
-				return;
-			}
-			session->needs_bind = false;
-		} else {
-			status = smb2cli_session_set_session_key(session->smbXcli,
-								 session_key,
-								 recv_iov);
-			if (tevent_req_nterror(req, status)) {
-				return;
-			}
-		}
+	if (state->reauth) {
 		tevent_req_done(req);
 		return;
 	}
 
-	if (state->session_bind) {
-		in_flags |= SMB2_SESSION_FLAG_BINDING;
+	if (cli_credentials_is_anonymous(state->credentials)) {
+		/*
+		 * Windows server does not set the
+		 * SMB2_SESSION_FLAG_IS_GUEST nor
+		 * SMB2_SESSION_FLAG_IS_NULL flag.
+		 *
+		 * This fix makes sure we do not try
+		 * to verify a signature on the final
+		 * session setup response.
+		 */
+		tevent_req_done(req);
+		return;
 	}
 
-	subreq = smb2cli_session_setup_send(state, state->ev,
-					    session->transport->conn,
-					    timeout_msec,
-					    session->smbXcli,
-					    in_flags,
-					    0, /* in_capabilities */
-					    0, /* in_channel */
-					    state->previous_session_id,
-					    &state->in_secblob);
-	if (tevent_req_nomem(subreq, req)) {
+	status = gensec_session_key(session->gensec, state,
+				    &session_key);
+	if (tevent_req_nterror(req, status)) {
 		return;
 	}
-	tevent_req_set_callback(subreq, smb2_session_setup_spnego_done, req);
+
+	if (state->session_bind) {
+		status = smb2cli_session_set_channel_key(session->smbXcli,
+							 session_key,
+							 state->recv_iov);
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
+		session->needs_bind = false;
+	} else {
+		status = smb2cli_session_set_session_key(session->smbXcli,
+							 session_key,
+							 state->recv_iov);
+		if (tevent_req_nterror(req, status)) {
+			return;
+		}
+	}
+	tevent_req_done(req);
+	return;
 }
 
 /*
-- 
1.9.1


From 400853988e6303b7e59acbbcbf6ae0f73ced02ba Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 15 May 2017 23:53:38 +0200
Subject: [PATCH 24/24] s4:libcli/ldap: just use gensec_update() in
 ldap_bind_sasl()

We're in a blocking/sync call, we should avoid using nested event loops for
this. As far as I can see ldap_bind_sasl() is only called from command
line tools, which are ok to block.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/libcli/ldap/ldap_bind.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/source4/libcli/ldap/ldap_bind.c b/source4/libcli/ldap/ldap_bind.c
index b8799dc..66fe9f5 100644
--- a/source4/libcli/ldap/ldap_bind.c
+++ b/source4/libcli/ldap/ldap_bind.c
@@ -379,8 +379,7 @@ try_logon_again:
 		struct ldap_request *req;
 		int result = LDAP_OTHER;
 	
-		status = gensec_update_ev(conn->gensec, tmp_ctx,
-				       conn->event.event_ctx,
+		status = gensec_update(conn->gensec, tmp_ctx,
 				       input,
 				       &output);
 		/* The status value here, from GENSEC is vital to the security
-- 
1.9.1

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20170517/6669c7ac/signature-0001.sig>


More information about the samba-technical mailing list