[Patches] Add support for trusted domains to the auth stack as AD DC

Stefan Metzmacher metze at samba.org
Fri Jul 21 13:37:25 UTC 2017


Hi,

here's a patchset on top of the gensec_update_ev() removal patchset,
that changes the auth stack to support async
check_ntlm_password_send/recv processing.

I've converted the most relavant backend:
source4/auth/ntlm/auth_winbind.c

There we're using IRPC to winbind, which is now fully
async.

A private autobuild is at 2077(13952)/2171 currently
and some former versions of the patchset passes completely...

Please note that there's still more to do in order to claim
full support for trusts in the AD DC, e.g. lsa lookup names/sid
forwarding, sid filtering and other things are still to be done.

But I think this is a very good milestone.

Please review and push:-)

Thanks!
metze
-------------- next part --------------
From ce5f5f6150538e19b8d87d60a13933478073a572 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 07:39:11 +0200
Subject: [PATCH 01/16] s4:rpc_server/netlogon: check auth_level for validation
 level 6 already in dcesrv_netr_LogonSamLogon_check()

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

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index b50b7a5..6c55d8a 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -801,7 +801,8 @@ static WERROR dcesrv_netr_LogonUasLogoff(struct dcesrv_call_state *dce_call, TAL
 }
 
 
-static NTSTATUS dcesrv_netr_LogonSamLogon_check(const struct netr_LogonSamLogonEx *r)
+static NTSTATUS dcesrv_netr_LogonSamLogon_check(struct dcesrv_call_state *dce_call,
+						const struct netr_LogonSamLogonEx *r)
 {
 	switch (r->in.logon_level) {
 	case NetlogonInteractiveInformation:
@@ -857,6 +858,17 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_check(const struct netr_LogonSamLogonE
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
+	switch (r->in.validation_level) {
+	case NetlogonValidationSamInfo4: /* 6 */
+		if (dce_call->conn->auth_state.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+		break;
+
+	default:
+		break;
+	}
+
 	return NT_STATUS_OK;
 }
 
@@ -1090,10 +1102,6 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 		break;
 
 	case 6:
-		if (dce_call->conn->auth_state.auth_level < DCERPC_AUTH_LEVEL_PRIVACY) {
-			return NT_STATUS_INVALID_PARAMETER;
-		}
-
 		nt_status = auth_convert_user_info_dc_saminfo6(mem_ctx,
 							       user_info_dc,
 							       &sam6);
@@ -1124,7 +1132,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
 
 	*r->out.authoritative = 1;
 
-	nt_status = dcesrv_netr_LogonSamLogon_check(r);
+	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, r);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		return nt_status;
 	}
@@ -1169,7 +1177,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce
 
 	*r->out.authoritative = 1;
 
-	nt_status = dcesrv_netr_LogonSamLogon_check(&r2);
+	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, &r2);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		return nt_status;
 	}
-- 
1.9.1


From 23d95ebe32028f8e7eb21e39b33cad7e98d5c614 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 17 Mar 2017 19:27:38 +0100
Subject: [PATCH 02/16] s4:rpc_server/netlogon: prepare
 dcesrv_netr_LogonSamLogon_base for async processing

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 185 +++++++++++++++++++-------
 1 file changed, 138 insertions(+), 47 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 6c55d8a..fcced5e 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -872,6 +872,24 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_check(struct dcesrv_call_state *dce_ca
 	return NT_STATUS_OK;
 }
 
+struct dcesrv_netr_LogonSamLogon_base_state {
+	struct dcesrv_call_state *dce_call;
+
+	TALLOC_CTX *mem_ctx;
+
+	struct netlogon_creds_CredentialState *creds;
+
+	struct netr_LogonSamLogonEx r;
+
+	uint32_t _ignored_flags;
+
+	struct {
+		struct netr_LogonSamLogon *lsl;
+		struct netr_LogonSamLogonWithFlags *lslwf;
+		struct netr_LogonSamLogonEx *lslex;
+	} _r;
+};
+
 /*
   netr_LogonSamLogon_base
 
@@ -880,9 +898,12 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_check(struct dcesrv_call_state *dce_ca
   We can't do the traditional 'wrapping' format completely, as this
   function must only run under schannel
 */
-static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-					struct netr_LogonSamLogonEx *r, struct netlogon_creds_CredentialState *creds)
+static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamLogon_base_state *state)
 {
+	struct dcesrv_call_state *dce_call = state->dce_call;
+	TALLOC_CTX *mem_ctx = state->mem_ctx;
+	struct netr_LogonSamLogonEx *r = &state->r;
+	struct netlogon_creds_CredentialState *creds = state->creds;
 	struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
 	const char *workgroup = lpcfg_workgroup(lp_ctx);
 	struct auth4_context *auth_context = NULL;
@@ -1127,19 +1148,39 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base(struct dcesrv_call_state *dce_cal
 static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
 				     struct netr_LogonSamLogonEx *r)
 {
+	struct dcesrv_netr_LogonSamLogon_base_state *state;
 	NTSTATUS nt_status;
-	struct netlogon_creds_CredentialState *creds;
 
 	*r->out.authoritative = 1;
 
-	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, r);
+	state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonSamLogon_base_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	state->dce_call = dce_call;
+	state->mem_ctx = mem_ctx;
+
+	state->r.in.server_name      = r->in.server_name;
+	state->r.in.computer_name    = r->in.computer_name;
+	state->r.in.logon_level      = r->in.logon_level;
+	state->r.in.logon            = r->in.logon;
+	state->r.in.validation_level = r->in.validation_level;
+	state->r.in.flags            = r->in.flags;
+	state->r.out.validation      = r->out.validation;
+	state->r.out.authoritative   = r->out.authoritative;
+	state->r.out.flags           = r->out.flags;
+
+	state->_r.lslex = r;
+
+	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, &state->r);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		return nt_status;
 	}
 
 	nt_status = schannel_get_creds_state(mem_ctx,
 					     dce_call->conn->dce_ctx->lp_ctx,
-					     r->in.computer_name, &creds);
+					     r->in.computer_name, &state->creds);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		return nt_status;
 	}
@@ -1147,7 +1188,14 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
 	if (dce_call->conn->auth_state.auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
 		return NT_STATUS_ACCESS_DENIED;
 	}
-	return dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, r, creds);
+
+	nt_status = dcesrv_netr_LogonSamLogon_base_call(state);
+
+	if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
+		return nt_status;
+	}
+
+	return nt_status;
 }
 
 /*
@@ -1157,44 +1205,57 @@ static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call,
 static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
 					    struct netr_LogonSamLogonWithFlags *r)
 {
+	struct dcesrv_netr_LogonSamLogon_base_state *state;
 	NTSTATUS nt_status;
-	struct netlogon_creds_CredentialState *creds;
-	struct netr_LogonSamLogonEx r2;
 
-	struct netr_Authenticator *return_authenticator;
+	*r->out.authoritative = 1;
 
-	ZERO_STRUCT(r2);
+	state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonSamLogon_base_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	state->dce_call = dce_call;
+	state->mem_ctx = mem_ctx;
 
-	r2.in.server_name	= r->in.server_name;
-	r2.in.computer_name	= r->in.computer_name;
-	r2.in.logon_level	= r->in.logon_level;
-	r2.in.logon		= r->in.logon;
-	r2.in.validation_level	= r->in.validation_level;
-	r2.in.flags		= r->in.flags;
-	r2.out.validation	= r->out.validation;
-	r2.out.authoritative	= r->out.authoritative;
-	r2.out.flags		= r->out.flags;
+	state->r.in.server_name      = r->in.server_name;
+	state->r.in.computer_name    = r->in.computer_name;
+	state->r.in.logon_level      = r->in.logon_level;
+	state->r.in.logon            = r->in.logon;
+	state->r.in.validation_level = r->in.validation_level;
+	state->r.in.flags            = r->in.flags;
+	state->r.out.validation      = r->out.validation;
+	state->r.out.authoritative   = r->out.authoritative;
+	state->r.out.flags           = r->out.flags;
 
-	*r->out.authoritative = 1;
+	state->_r.lslwf = r;
 
-	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, &r2);
+	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, &state->r);
 	if (!NT_STATUS_IS_OK(nt_status)) {
 		return nt_status;
 	}
 
-	return_authenticator = talloc(mem_ctx, struct netr_Authenticator);
-	NT_STATUS_HAVE_NO_MEMORY(return_authenticator);
+	r->out.return_authenticator = talloc_zero(mem_ctx,
+						  struct netr_Authenticator);
+	if (r->out.return_authenticator == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
 	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
 							mem_ctx,
 							r->in.computer_name,
-							r->in.credential, return_authenticator,
-							&creds);
-	NT_STATUS_NOT_OK_RETURN(nt_status);
+							r->in.credential,
+							r->out.return_authenticator,
+							&state->creds);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		return nt_status;
+	}
 
-	nt_status = dcesrv_netr_LogonSamLogon_base(dce_call, mem_ctx, &r2, creds);
+	nt_status = dcesrv_netr_LogonSamLogon_base_call(state);
 
-	r->out.return_authenticator	= return_authenticator;
+	if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
+		return nt_status;
+	}
 
 	return nt_status;
 }
@@ -1205,29 +1266,59 @@ static NTSTATUS dcesrv_netr_LogonSamLogonWithFlags(struct dcesrv_call_state *dce
 static NTSTATUS dcesrv_netr_LogonSamLogon(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
 				   struct netr_LogonSamLogon *r)
 {
-	struct netr_LogonSamLogonWithFlags r2;
-	uint32_t flags = 0;
-	NTSTATUS status;
+	struct dcesrv_netr_LogonSamLogon_base_state *state;
+	NTSTATUS nt_status;
 
-	ZERO_STRUCT(r2);
+	*r->out.authoritative = 1;
 
-	r2.in.server_name = r->in.server_name;
-	r2.in.computer_name = r->in.computer_name;
-	r2.in.credential  = r->in.credential;
-	r2.in.return_authenticator = r->in.return_authenticator;
-	r2.in.logon_level = r->in.logon_level;
-	r2.in.logon = r->in.logon;
-	r2.in.validation_level = r->in.validation_level;
-	r2.in.flags = &flags;
-	r2.out.validation = r->out.validation;
-	r2.out.authoritative = r->out.authoritative;
-	r2.out.flags = &flags;
-
-	status = dcesrv_netr_LogonSamLogonWithFlags(dce_call, mem_ctx, &r2);
+	state = talloc_zero(mem_ctx, struct dcesrv_netr_LogonSamLogon_base_state);
+	if (state == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
 
-	r->out.return_authenticator = r2.out.return_authenticator;
+	state->dce_call = dce_call;
+	state->mem_ctx = mem_ctx;
 
-	return status;
+	state->r.in.server_name      = r->in.server_name;
+	state->r.in.computer_name    = r->in.computer_name;
+	state->r.in.logon_level      = r->in.logon_level;
+	state->r.in.logon            = r->in.logon;
+	state->r.in.validation_level = r->in.validation_level;
+	state->r.in.flags            = &state->_ignored_flags;
+	state->r.out.validation      = r->out.validation;
+	state->r.out.authoritative   = r->out.authoritative;
+	state->r.out.flags           = &state->_ignored_flags;
+
+	state->_r.lsl = r;
+
+	nt_status = dcesrv_netr_LogonSamLogon_check(dce_call, &state->r);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		return nt_status;
+	}
+
+	r->out.return_authenticator = talloc_zero(mem_ctx,
+						  struct netr_Authenticator);
+	if (r->out.return_authenticator == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	nt_status = dcesrv_netr_creds_server_step_check(dce_call,
+							mem_ctx,
+							r->in.computer_name,
+							r->in.credential,
+							r->out.return_authenticator,
+							&state->creds);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		return nt_status;
+	}
+
+	nt_status = dcesrv_netr_LogonSamLogon_base_call(state);
+
+	if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) {
+		return nt_status;
+	}
+
+	return nt_status;
 }
 
 
-- 
1.9.1


From ef411633764356685a3187ae0845f07fb5e02ca0 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 08:10:02 +0200
Subject: [PATCH 03/16] s4:rpc_server/netlogon: make use of async
 kdc_check_generic_kerberos_send/recv()

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

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index fcced5e..2f08a78 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -888,8 +888,14 @@ struct dcesrv_netr_LogonSamLogon_base_state {
 		struct netr_LogonSamLogonWithFlags *lslwf;
 		struct netr_LogonSamLogonEx *lslex;
 	} _r;
+
+	struct kdc_check_generic_kerberos kr;
 };
 
+static void dcesrv_netr_LogonSamLogon_base_krb5_done(struct tevent_req *subreq);
+static void dcesrv_netr_LogonSamLogon_base_reply(
+	struct dcesrv_netr_LogonSamLogon_base_state *state);
+
 /*
   netr_LogonSamLogon_base
 
@@ -913,6 +919,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 	struct netr_SamInfo2 *sam2 = NULL;
 	struct netr_SamInfo3 *sam3 = NULL;
 	struct netr_SamInfo6 *sam6 = NULL;
+	struct tevent_req *subreq = NULL;
 
 	*r->out.authoritative = 1;
 
@@ -1051,15 +1058,9 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 		}
 
 		if (strcmp(r->in.logon->generic->package_name.string, "Kerberos") == 0) {
-			NTSTATUS status;
 			struct dcerpc_binding_handle *irpc_handle;
-			struct kdc_check_generic_kerberos check;
 			struct netr_GenericInfo2 *generic = talloc_zero(mem_ctx, struct netr_GenericInfo2);
 			NT_STATUS_HAVE_NO_MEMORY(generic);
-			*r->out.authoritative = 1;
-
-			/* TODO: Describe and deal with these flags */
-			*r->out.flags = 0;
 
 			r->out.validation->generic = generic;
 
@@ -1071,24 +1072,24 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 				return NT_STATUS_NO_LOGON_SERVERS;
 			}
 
-			check.in.generic_request =
+			state->kr.in.generic_request =
 				data_blob_const(r->in.logon->generic->data,
 						r->in.logon->generic->length);
 
 			/*
-			 * TODO: make this async and avoid
-			 * dcerpc_binding_handle_set_sync_ev()
+			 * 60 seconds should be enough
 			 */
-			dcerpc_binding_handle_set_sync_ev(irpc_handle,
-							  dce_call->event_ctx);
-			status = dcerpc_kdc_check_generic_kerberos_r(irpc_handle,
-								     mem_ctx,
-								     &check);
-			if (!NT_STATUS_IS_OK(status)) {
-				return status;
+			dcerpc_binding_handle_set_timeout(irpc_handle, 60);
+			subreq = dcerpc_kdc_check_generic_kerberos_r_send(state,
+						state->dce_call->event_ctx,
+						irpc_handle, &state->kr);
+			if (subreq == NULL) {
+				return NT_STATUS_NO_MEMORY;
 			}
-			generic->length = check.out.generic_reply.length;
-			generic->data = check.out.generic_reply.data;
+			state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
+			tevent_req_set_callback(subreq,
+					dcesrv_netr_LogonSamLogon_base_krb5_done,
+					state);
 			return NT_STATUS_OK;
 		}
 
@@ -1145,6 +1146,66 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 	return NT_STATUS_OK;
 }
 
+static void dcesrv_netr_LogonSamLogon_base_krb5_done(struct tevent_req *subreq)
+{
+	struct dcesrv_netr_LogonSamLogon_base_state *state =
+		tevent_req_callback_data(subreq,
+		struct dcesrv_netr_LogonSamLogon_base_state);
+	TALLOC_CTX *mem_ctx = state->mem_ctx;
+	struct netr_LogonSamLogonEx *r = &state->r;
+	struct netr_GenericInfo2 *generic = NULL;
+	NTSTATUS status;
+
+	status = dcerpc_kdc_check_generic_kerberos_r_recv(subreq, mem_ctx);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		r->out.result = status;
+		dcesrv_netr_LogonSamLogon_base_reply(state);
+		return;
+	}
+
+	generic = r->out.validation->generic;
+	generic->length = state->kr.out.generic_reply.length;
+	generic->data = state->kr.out.generic_reply.data;
+
+	/* TODO: Describe and deal with these flags */
+	*r->out.flags = 0;
+
+	r->out.result = NT_STATUS_OK;
+
+	dcesrv_netr_LogonSamLogon_base_reply(state);
+}
+
+static void dcesrv_netr_LogonSamLogon_base_reply(
+	struct dcesrv_netr_LogonSamLogon_base_state *state)
+{
+	struct netr_LogonSamLogonEx *r = &state->r;
+	NTSTATUS status;
+
+	if (NT_STATUS_IS_OK(r->out.result)) {
+		netlogon_creds_encrypt_samlogon_validation(state->creds,
+							   r->in.validation_level,
+							   r->out.validation);
+	}
+
+	if (state->_r.lslex != NULL) {
+		struct netr_LogonSamLogonEx *_r = state->_r.lslex;
+		_r->out.result = r->out.result;
+	} else if (state->_r.lslwf != NULL) {
+		struct netr_LogonSamLogonWithFlags *_r = state->_r.lslwf;
+		_r->out.result = r->out.result;
+	} else if (state->_r.lsl != NULL) {
+		struct netr_LogonSamLogon *_r = state->_r.lsl;
+		_r->out.result = r->out.result;
+	}
+
+	status = dcesrv_reply(state->dce_call);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_ERR("dcesrv_reply() failed - %s\n",
+			nt_errstr(status));
+	}
+}
+
 static NTSTATUS dcesrv_netr_LogonSamLogonEx(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
 				     struct netr_LogonSamLogonEx *r)
 {
-- 
1.9.1


From b62cc35f2977b50ade8b51ba6114b331dbf0b462 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 17 Mar 2017 19:36:08 +0100
Subject: [PATCH 04/16] s4:rpc_server/netlogon: make use of
 auth_check_password_send/recv()

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

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 2f08a78..7a10613 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -892,6 +892,7 @@ struct dcesrv_netr_LogonSamLogon_base_state {
 	struct kdc_check_generic_kerberos kr;
 };
 
+static void dcesrv_netr_LogonSamLogon_base_auth_done(struct tevent_req *subreq);
 static void dcesrv_netr_LogonSamLogon_base_krb5_done(struct tevent_req *subreq);
 static void dcesrv_netr_LogonSamLogon_base_reply(
 	struct dcesrv_netr_LogonSamLogon_base_state *state);
@@ -914,11 +915,7 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 	const char *workgroup = lpcfg_workgroup(lp_ctx);
 	struct auth4_context *auth_context = NULL;
 	struct auth_usersupplied_info *user_info = NULL;
-	struct auth_user_info_dc *user_info_dc = NULL;
 	NTSTATUS nt_status;
-	struct netr_SamInfo2 *sam2 = NULL;
-	struct netr_SamInfo3 *sam3 = NULL;
-	struct netr_SamInfo6 *sam6 = NULL;
 	struct tevent_req *subreq = NULL;
 
 	*r->out.authoritative = 1;
@@ -1100,16 +1097,48 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 		return NT_STATUS_INVALID_PARAMETER;
 	}
 
-	nt_status = auth_check_password(auth_context, mem_ctx, user_info,
-					&user_info_dc, r->out.authoritative);
-	NT_STATUS_NOT_OK_RETURN(nt_status);
+	subreq = auth_check_password_send(state, state->dce_call->event_ctx,
+					  auth_context, user_info);
+	state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC;
+	tevent_req_set_callback(subreq,
+				dcesrv_netr_LogonSamLogon_base_auth_done,
+				state);
+	return NT_STATUS_OK;
+}
+
+static void dcesrv_netr_LogonSamLogon_base_auth_done(struct tevent_req *subreq)
+{
+	struct dcesrv_netr_LogonSamLogon_base_state *state =
+		tevent_req_callback_data(subreq,
+		struct dcesrv_netr_LogonSamLogon_base_state);
+	TALLOC_CTX *mem_ctx = state->mem_ctx;
+	struct netr_LogonSamLogonEx *r = &state->r;
+	struct auth_user_info_dc *user_info_dc = NULL;
+	struct netr_SamInfo2 *sam2 = NULL;
+	struct netr_SamInfo3 *sam3 = NULL;
+	struct netr_SamInfo6 *sam6 = NULL;
+	NTSTATUS nt_status;
+
+	nt_status = auth_check_password_recv(subreq, mem_ctx,
+					     &user_info_dc,
+					     r->out.authoritative);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		r->out.result = nt_status;
+		dcesrv_netr_LogonSamLogon_base_reply(state);
+		return;
+	}
 
 	switch (r->in.validation_level) {
 	case 2:
 		nt_status = auth_convert_user_info_dc_saminfo2(mem_ctx,
 							       user_info_dc,
 							       &sam2);
-		NT_STATUS_NOT_OK_RETURN(nt_status);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			r->out.result = nt_status;
+			dcesrv_netr_LogonSamLogon_base_reply(state);
+			return;
+		}
 
 		r->out.validation->sam2 = sam2;
 		break;
@@ -1118,7 +1147,11 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 		nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx,
 							       user_info_dc,
 							       &sam3);
-		NT_STATUS_NOT_OK_RETURN(nt_status);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			r->out.result = nt_status;
+			dcesrv_netr_LogonSamLogon_base_reply(state);
+			return;
+		}
 
 		r->out.validation->sam3 = sam3;
 		break;
@@ -1127,23 +1160,29 @@ static NTSTATUS dcesrv_netr_LogonSamLogon_base_call(struct dcesrv_netr_LogonSamL
 		nt_status = auth_convert_user_info_dc_saminfo6(mem_ctx,
 							       user_info_dc,
 							       &sam6);
-		NT_STATUS_NOT_OK_RETURN(nt_status);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			r->out.result = nt_status;
+			dcesrv_netr_LogonSamLogon_base_reply(state);
+			return;
+		}
 
 		r->out.validation->sam6 = sam6;
 		break;
 
 	default:
-		return NT_STATUS_INVALID_INFO_CLASS;
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			r->out.result = NT_STATUS_INVALID_INFO_CLASS;
+			dcesrv_netr_LogonSamLogon_base_reply(state);
+			return;
+		}
 	}
 
-	netlogon_creds_encrypt_samlogon_validation(creds,
-						   r->in.validation_level,
-						   r->out.validation);
-
 	/* TODO: Describe and deal with these flags */
 	*r->out.flags = 0;
 
-	return NT_STATUS_OK;
+	r->out.result = NT_STATUS_OK;
+
+	dcesrv_netr_LogonSamLogon_base_reply(state);
 }
 
 static void dcesrv_netr_LogonSamLogon_base_krb5_done(struct tevent_req *subreq)
-- 
1.9.1


From 91518d84c7ac1dfc18c769538bf7d50b3d3f6eea Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 17 Jun 2017 00:56:09 +0200
Subject: [PATCH 05/16] s4:auth_winbind: implement async authentication via
 IRPC

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/auth/ntlm/auth_winbind.c | 178 ++++++++++++++++++++++++++++++---------
 1 file changed, 137 insertions(+), 41 deletions(-)

diff --git a/source4/auth/ntlm/auth_winbind.c b/source4/auth/ntlm/auth_winbind.c
index aff8f47..018940f 100644
--- a/source4/auth/ntlm/auth_winbind.c
+++ b/source4/auth/ntlm/auth_winbind.c
@@ -22,6 +22,8 @@
 */
 
 #include "includes.h"
+#include <tevent.h>
+#include "../lib/util/tevent_ntstatus.h"
 #include "auth/auth.h"
 #include "auth/ntlm/auth_proto.h"
 #include "librpc/gen_ndr/ndr_winbind_c.h"
@@ -90,57 +92,84 @@ static NTSTATUS winbind_rodc_want_check(struct auth_method_context *ctx,
 }
 
 struct winbind_check_password_state {
+	struct auth_method_context *ctx;
+	const struct auth_usersupplied_info *user_info;
 	struct winbind_SamLogon req;
+	struct auth_user_info_dc *user_info_dc;
+	bool authoritative;
 };
 
+static void winbind_check_password_done(struct tevent_req *subreq);
+
 /*
  Authenticate a user with a challenge/response
  using IRPC to the winbind task
 */
-static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
-				       TALLOC_CTX *mem_ctx,
-				       const struct auth_usersupplied_info *user_info, 
-				       struct auth_user_info_dc **user_info_dc,
-				       bool *authoritative)
+static struct tevent_req *winbind_check_password_send(TALLOC_CTX *mem_ctx,
+				struct tevent_context *ev,
+				struct auth_method_context *ctx,
+				const struct auth_usersupplied_info *user_info)
 {
+	struct tevent_req *req = NULL;
 	struct winbind_check_password_state *state = NULL;
 	NTSTATUS status;
 	struct dcerpc_binding_handle *irpc_handle;
 	const struct auth_usersupplied_info *user_info_new;
 	struct netr_IdentityInfo *identity_info;
-	struct ldb_dn *domain_dn;
-	struct ldb_message *msg;
-	const char *account_name = user_info->mapped.account_name;
-	const char *p = NULL;
+	struct imessaging_context *msg_ctx;
+	struct tevent_req *subreq = NULL;
 
-	if (!ctx->auth_ctx->msg_ctx) {
-		DEBUG(0,("winbind_check_password: auth_context_create was called with out messaging context\n"));
-		return NT_STATUS_INTERNAL_ERROR;
+	req = tevent_req_create(mem_ctx, &state,
+				struct winbind_check_password_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ctx = ctx;
+	state->user_info = user_info;
+	state->authoritative = true;
+
+	msg_ctx = imessaging_client_init(state, ctx->auth_ctx->lp_ctx, ev);
+	if (msg_ctx == NULL) {
+		DEBUG(1, ("imessaging_init failed\n"));
+		tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
+		return tevent_req_post(req, ev);
 	}
 
-	state = talloc(mem_ctx, struct winbind_check_password_state);
-	NT_STATUS_HAVE_NO_MEMORY(state);
-
-	irpc_handle = irpc_binding_handle_by_name(state, ctx->auth_ctx->msg_ctx,
+	irpc_handle = irpc_binding_handle_by_name(state, msg_ctx,
 						  "winbind_server",
 						  &ndr_table_winbind);
 	if (irpc_handle == NULL) {
 		DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " 
 			  "no winbind_server running!\n",
 			  user_info->client.domain_name, user_info->client.account_name));
-		return NT_STATUS_NO_LOGON_SERVERS;
+		tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
+		return tevent_req_post(req, ev);
 	}
 
+	/*
+	 * 120 seconds should be enough even for trusted domains.
+	 *
+	 * Currently winbindd has a much lower limit.
+	 * And tests with Windows RODCs show that it
+	 * returns NO_LOGON_SERVERS after 90-100 seconds
+	 * if it can't reach any RWDC.
+	 */
+	dcerpc_binding_handle_set_timeout(irpc_handle, 120);
+
 	if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
 		struct netr_PasswordInfo *password_info;
 
 		status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_HASH,
 					   user_info, &user_info_new);
-		NT_STATUS_NOT_OK_RETURN(status);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
 		user_info = user_info_new;
 
 		password_info = talloc_zero(state, struct netr_PasswordInfo);
-		NT_STATUS_HAVE_NO_MEMORY(password_info);
+		if (tevent_req_nomem(password_info, req)) {
+			return tevent_req_post(req, ev);
+		}
 
 		password_info->lmpassword = *user_info->password.hash.lanman;
 		password_info->ntpassword = *user_info->password.hash.nt;
@@ -154,14 +183,20 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
 
 		status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE,
 					   user_info, &user_info_new);
-		NT_STATUS_NOT_OK_RETURN(status);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
 		user_info = user_info_new;
 
 		network_info = talloc_zero(state, struct netr_NetworkInfo);
-		NT_STATUS_HAVE_NO_MEMORY(network_info);
+		if (tevent_req_nomem(network_info, req)) {
+			return tevent_req_post(req, ev);
+		}
 
 		status = auth_get_challenge(ctx->auth_ctx, chal);
-		NT_STATUS_NOT_OK_RETURN(status);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
 
 		memcpy(network_info->challenge, chal, sizeof(network_info->challenge));
 
@@ -185,16 +220,50 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
 
 	state->req.in.validation_level = 3;
 
-	/* Note: this makes use of nested event loops... */
-	dcerpc_binding_handle_set_sync_ev(irpc_handle, ctx->auth_ctx->event_ctx);
-	status = dcerpc_winbind_SamLogon_r(irpc_handle, state, &state->req);
-	NT_STATUS_NOT_OK_RETURN(status);
+	subreq = dcerpc_winbind_SamLogon_r_send(state, ev, irpc_handle,
+						&state->req);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				winbind_check_password_done,
+				req);
+
+	return req;
+}
+
+static void winbind_check_password_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct winbind_check_password_state *state =
+		tevent_req_data(req,
+		struct winbind_check_password_state);
+	struct auth_method_context *ctx = state->ctx;
+	const struct auth_usersupplied_info *user_info = state->user_info;
+	const char *account_name = user_info->mapped.account_name;
+	struct ldb_dn *domain_dn = NULL;
+	struct ldb_message *msg = NULL;
+	const char *p = NULL;
+	NTSTATUS status;
 
-	if (!NT_STATUS_IS_OK(state->req.out.result)) {
+	status = dcerpc_winbind_SamLogon_r_recv(subreq, state);
+	if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+		status = NT_STATUS_NO_LOGON_SERVERS;
+	}
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	status = state->req.out.result;
+	if (!NT_STATUS_IS_OK(status)) {
 		if (!state->req.out.authoritative) {
-			*authoritative = false;
+			state->authoritative = false;
 		}
-		return state->req.out.result;
+		tevent_req_nterror(req, status);
+		return;
 	}
 
 	/*
@@ -207,7 +276,7 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
 		const char *nt4_domain = NULL;
 		const char *nt4_account = NULL;
 
-		status = crack_name_to_nt4_name(mem_ctx,
+		status = crack_name_to_nt4_name(state,
 						ctx->auth_ctx->sam_ctx,
 						DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
 						account_name,
@@ -221,7 +290,7 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
 
 	domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
 	if (domain_dn != NULL) {
-		status = authsam_search_account(mem_ctx, ctx->auth_ctx->sam_ctx,
+		status = authsam_search_account(state, ctx->auth_ctx->sam_ctx,
 						account_name, domain_dn, &msg);
 		if (NT_STATUS_IS_OK(status)) {
 			authsam_logon_success_accounting(
@@ -232,14 +301,39 @@ static NTSTATUS winbind_check_password(struct auth_method_context *ctx,
 		}
 	}
 
-	status = make_user_info_dc_netlogon_validation(mem_ctx,
+	status = make_user_info_dc_netlogon_validation(state,
 						      user_info->client.account_name,
 						      state->req.in.validation_level,
 						      &state->req.out.validation,
-						       true, /* This user was authenticated */
-						      user_info_dc);
-	NT_STATUS_NOT_OK_RETURN(status);
+						      true, /* This user was authenticated */
+						      &state->user_info_dc);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
 
+	tevent_req_done(req);
+}
+
+static NTSTATUS winbind_check_password_recv(struct tevent_req *req,
+					    TALLOC_CTX *mem_ctx,
+					    struct auth_user_info_dc **user_info_dc,
+					    bool *pauthoritative)
+{
+	struct winbind_check_password_state *state =
+		tevent_req_data(req,
+		struct winbind_check_password_state);
+	NTSTATUS status = NT_STATUS_OK;
+
+	*pauthoritative = state->authoritative;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
+		return status;
+	}
+
+	*user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
+
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
@@ -340,15 +434,17 @@ static NTSTATUS winbind_check_password_wbclient(struct auth_method_context *ctx,
 }
 
 static const struct auth_operations winbind_ops = {
-	.name		= "winbind",
-	.want_check	= winbind_want_check,
-	.check_password	= winbind_check_password
+	.name			= "winbind",
+	.want_check		= winbind_want_check,
+	.check_password_send	= winbind_check_password_send,
+	.check_password_recv	= winbind_check_password_recv
 };
 
 static const struct auth_operations winbind_rodc_ops = {
-	.name		= "winbind_rodc",
-	.want_check	= winbind_rodc_want_check,
-	.check_password	= winbind_check_password
+	.name			= "winbind_rodc",
+	.want_check		= winbind_rodc_want_check,
+	.check_password_send	= winbind_check_password_send,
+	.check_password_recv	= winbind_check_password_recv
 };
 
 static const struct auth_operations winbind_wbclient_ops = {
-- 
1.9.1


From 15c75fcb3c362ef6759d17c890014a7a49b71a57 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 15 Jun 2017 00:34:26 +0200
Subject: [PATCH 06/16] auth/ntlmssp: prepare update_send/recv for real async
 processing

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 auth/ntlmssp/ntlmssp.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/auth/ntlmssp/ntlmssp.c b/auth/ntlmssp/ntlmssp.c
index f79f0e2..e5a243e 100644
--- a/auth/ntlmssp/ntlmssp.c
+++ b/auth/ntlmssp/ntlmssp.c
@@ -44,6 +44,13 @@ static const struct ntlmssp_callbacks {
 	NTSTATUS (*sync_fn)(struct gensec_security *gensec_security,
 			    TALLOC_CTX *out_mem_ctx,
 			    DATA_BLOB in, DATA_BLOB *out);
+	struct tevent_req *(*send_fn)(TALLOC_CTX *mem_ctx,
+				      struct tevent_context *ev,
+				      struct gensec_security *gensec_security,
+				      const DATA_BLOB in);
+	NTSTATUS (*recv_fn)(struct tevent_req *req,
+			    TALLOC_CTX *out_mem_ctx,
+			    DATA_BLOB *out);
 } ntlmssp_callbacks[] = {
 	{
 		.role		= NTLMSSP_CLIENT,
@@ -146,10 +153,13 @@ static NTSTATUS gensec_ntlmssp_update_find(struct gensec_security *gensec_securi
 }
 
 struct gensec_ntlmssp_update_state {
+	const struct ntlmssp_callbacks *cb;
 	NTSTATUS status;
 	DATA_BLOB out;
 };
 
+static void gensec_ntlmssp_update_done(struct tevent_req *subreq);
+
 static struct tevent_req *gensec_ntlmssp_update_send(TALLOC_CTX *mem_ctx,
 						     struct tevent_context *ev,
 						     struct gensec_security *gensec_security,
@@ -176,6 +186,23 @@ static struct tevent_req *gensec_ntlmssp_update_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	if (ntlmssp_callbacks[i].send_fn != NULL) {
+		struct tevent_req *subreq = NULL;
+
+		state->cb = &ntlmssp_callbacks[i];
+
+		subreq = state->cb->send_fn(state, ev,
+					    gensec_security,
+					    in);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq,
+					gensec_ntlmssp_update_done,
+					req);
+		return req;
+	}
+
 	status = ntlmssp_callbacks[i].sync_fn(gensec_security,
 					      state,
 					      in, &state->out);
@@ -192,6 +219,27 @@ static struct tevent_req *gensec_ntlmssp_update_send(TALLOC_CTX *mem_ctx,
 	return tevent_req_post(req, ev);
 }
 
+static void gensec_ntlmssp_update_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct gensec_ntlmssp_update_state *state =
+		tevent_req_data(req,
+		struct gensec_ntlmssp_update_state);
+	NTSTATUS status;
+
+	status = state->cb->recv_fn(subreq, state, &state->out);
+	TALLOC_FREE(subreq);
+	if (GENSEC_UPDATE_IS_NTERROR(status)) {
+		tevent_req_nterror(req, status);
+		return;
+	}
+
+	state->status = status;
+	tevent_req_done(req);
+}
+
 static NTSTATUS gensec_ntlmssp_update_recv(struct tevent_req *req,
 					   TALLOC_CTX *out_mem_ctx,
 					   DATA_BLOB *out)
-- 
1.9.1


From 0d93ab0954d72a0ac97b833fed0111f3c9120ec1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 16 Jun 2017 16:16:15 +0200
Subject: [PATCH 07/16] auth/ntlmssp: introduce ntlmssp_server_auth_send/recv

We still use the sync ntlmssp_server_check_password().

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 auth/ntlmssp/ntlmssp.c         |   3 +-
 auth/ntlmssp/ntlmssp_private.h |  20 +++----
 auth/ntlmssp/ntlmssp_server.c  | 124 +++++++++++++++++++++++------------------
 3 files changed, 81 insertions(+), 66 deletions(-)

diff --git a/auth/ntlmssp/ntlmssp.c b/auth/ntlmssp/ntlmssp.c
index e5a243e..36e7052 100644
--- a/auth/ntlmssp/ntlmssp.c
+++ b/auth/ntlmssp/ntlmssp.c
@@ -71,7 +71,8 @@ static const struct ntlmssp_callbacks {
 	},{
 		.role		= NTLMSSP_SERVER,
 		.command	= NTLMSSP_AUTH,
-		.sync_fn	= gensec_ntlmssp_server_auth,
+		.send_fn	= ntlmssp_server_auth_send,
+		.recv_fn	= ntlmssp_server_auth_recv,
 	}
 };
 
diff --git a/auth/ntlmssp/ntlmssp_private.h b/auth/ntlmssp/ntlmssp_private.h
index eed48ed..95ec637 100644
--- a/auth/ntlmssp/ntlmssp_private.h
+++ b/auth/ntlmssp/ntlmssp_private.h
@@ -117,18 +117,14 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
 					 TALLOC_CTX *out_mem_ctx,
 					 const DATA_BLOB request, DATA_BLOB *reply);
 
-/**
- * Next state function for the Authenticate packet (GENSEC wrapper)
- *
- * @param gensec_security GENSEC state
- * @param out_mem_ctx Memory context for *out
- * @param in The request, as a DATA_BLOB.  reply.data must be NULL
- * @param out The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK if authentication sucessful
- */
-NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
-				    TALLOC_CTX *out_mem_ctx,
-				    const DATA_BLOB in, DATA_BLOB *out);
+struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct gensec_security *gensec_security,
+					    const DATA_BLOB in);
+NTSTATUS ntlmssp_server_auth_recv(struct tevent_req *req,
+				  TALLOC_CTX *out_mem_ctx,
+				  DATA_BLOB *out);
+
 
 /**
  * Start NTLMSSP on the server side
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index e17074e..b7d74e6 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -21,6 +21,8 @@
 */
 
 #include "includes.h"
+#include <tevent.h>
+#include "lib/util/tevent_ntstatus.h"
 #include "lib/util/time_basic.h"
 #include "auth/ntlmssp/ntlmssp.h"
 #include "auth/ntlmssp/ntlmssp_private.h"
@@ -304,6 +306,66 @@ struct ntlmssp_server_auth_state {
 	uint8_t session_nonce[16];
 };
 
+static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
+				       struct gensec_ntlmssp_context *gensec_ntlmssp,
+				       struct ntlmssp_server_auth_state *state,
+				       const DATA_BLOB request);
+static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_security,
+					      struct gensec_ntlmssp_context *gensec_ntlmssp,
+					      const struct auth_usersupplied_info *user_info,
+					      TALLOC_CTX *mem_ctx,
+					      DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key);
+static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
+					struct gensec_ntlmssp_context *gensec_ntlmssp,
+					struct ntlmssp_server_auth_state *state,
+					DATA_BLOB request);
+
+struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
+					    struct tevent_context *ev,
+					    struct gensec_security *gensec_security,
+					    const DATA_BLOB in)
+{
+	struct gensec_ntlmssp_context *gensec_ntlmssp =
+		talloc_get_type_abort(gensec_security->private_data,
+				      struct gensec_ntlmssp_context);
+	struct tevent_req *req = NULL;
+	struct ntlmssp_server_auth_state *state = NULL;
+	NTSTATUS status;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct ntlmssp_server_auth_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	status = ntlmssp_server_preauth(gensec_security,
+					gensec_ntlmssp,
+					state, in);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = ntlmssp_server_check_password(gensec_security,
+					       gensec_ntlmssp,
+					       state->user_info,
+					       state,
+					       &state->user_session_key,
+					       &state->lm_session_key);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = ntlmssp_server_postauth(gensec_security,
+					 gensec_ntlmssp,
+					 state, in);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	tevent_req_done(req);
+	return tevent_req_post(req, ev);
+}
+
 /**
  * Next state function for the Authenticate packet
  *
@@ -989,63 +1051,19 @@ static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
 	return nt_status;
 }
 
-
-/**
- * Next state function for the NTLMSSP Authenticate packet
- *
- * @param gensec_security GENSEC state
- * @param out_mem_ctx Memory context for *out
- * @param in The request, as a DATA_BLOB.  reply.data must be NULL
- * @param out The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK if authentication sucessful
- */
-
-NTSTATUS gensec_ntlmssp_server_auth(struct gensec_security *gensec_security,
-				    TALLOC_CTX *out_mem_ctx,
-				    const DATA_BLOB in, DATA_BLOB *out)
+NTSTATUS ntlmssp_server_auth_recv(struct tevent_req *req,
+				  TALLOC_CTX *out_mem_ctx,
+				  DATA_BLOB *out)
 {
-	struct gensec_ntlmssp_context *gensec_ntlmssp =
-		talloc_get_type_abort(gensec_security->private_data,
-				      struct gensec_ntlmssp_context);
-	struct ntlmssp_server_auth_state *state;
-	NTSTATUS nt_status;
+	NTSTATUS status;
 
-	/* zero the outbound NTLMSSP packet */
 	*out = data_blob_null;
 
-	state = talloc_zero(gensec_ntlmssp, struct ntlmssp_server_auth_state);
-	if (state == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
-
-	nt_status = ntlmssp_server_preauth(gensec_security, gensec_ntlmssp, state, in);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		TALLOC_FREE(state);
-		return nt_status;
-	}
-
-	/*
-	 * Note we don't check here for NTLMv2 auth settings. If NTLMv2 auth
-	 * is required (by "ntlm auth = no" and "lm auth = no" being set in the
-	 * smb.conf file) and no NTLMv2 response was sent then the password check
-	 * will fail here. JRA.
-	 */
-
-	/* Finally, actually ask if the password is OK */
-	nt_status = ntlmssp_server_check_password(gensec_security, gensec_ntlmssp,
-						  state->user_info, state,
-						  &state->user_session_key,
-						  &state->lm_session_key);
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		TALLOC_FREE(state);
-		return nt_status;
+	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
+		return status;
 	}
 
-	/* When we get more async in the auth code behind
-	   ntlmssp_state->check_password, the ntlmssp_server_postpath
-	   can be done in a callback */
-
-	nt_status = ntlmssp_server_postauth(gensec_security, gensec_ntlmssp, state, in);
-	TALLOC_FREE(state);
-	return nt_status;
+	tevent_req_received(req);
+	return NT_STATUS_OK;
 }
-- 
1.9.1


From 2210520b1f84183623333569ef1ead4b5b906474 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 16 Jun 2017 17:14:35 +0200
Subject: [PATCH 08/16] auth/ntlmssp: merge ntlmssp_server_check_password()
 into ntlmssp_server_auth_send()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 auth/ntlmssp/ntlmssp_server.c | 70 ++++++++++++++-----------------------------
 1 file changed, 22 insertions(+), 48 deletions(-)

diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index b7d74e6..4990f77 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -310,11 +310,6 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
 				       struct gensec_ntlmssp_context *gensec_ntlmssp,
 				       struct ntlmssp_server_auth_state *state,
 				       const DATA_BLOB request);
-static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_security,
-					      struct gensec_ntlmssp_context *gensec_ntlmssp,
-					      const struct auth_usersupplied_info *user_info,
-					      TALLOC_CTX *mem_ctx,
-					      DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key);
 static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
 					struct gensec_ntlmssp_context *gensec_ntlmssp,
 					struct ntlmssp_server_auth_state *state,
@@ -328,8 +323,10 @@ struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
 	struct gensec_ntlmssp_context *gensec_ntlmssp =
 		talloc_get_type_abort(gensec_security->private_data,
 				      struct gensec_ntlmssp_context);
+	struct auth4_context *auth_context = gensec_security->auth_context;
 	struct tevent_req *req = NULL;
 	struct ntlmssp_server_auth_state *state = NULL;
+	uint8_t authoritative = 0;
 	NTSTATUS status;
 
 	req = tevent_req_create(mem_ctx, &state,
@@ -345,15 +342,29 @@ struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	status = ntlmssp_server_check_password(gensec_security,
-					       gensec_ntlmssp,
-					       state->user_info,
-					       state,
-					       &state->user_session_key,
-					       &state->lm_session_key);
+	if (auth_context->check_ntlm_password == NULL) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return tevent_req_post(req, ev);
+	}
+
+	status = auth_context->check_ntlm_password(auth_context,
+						   gensec_ntlmssp,
+						   state->user_info,
+						   &authoritative,
+						   &gensec_ntlmssp->server_returned_info,
+						   &state->user_session_key,
+						   &state->lm_session_key);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_INFO("Checking NTLMSSP password for %s\\%s failed: %s\n",
+			 state->user_info->client.domain_name,
+			 state->user_info->client.account_name,
+			 nt_errstr(status));
+	}
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
 	}
+	talloc_steal(state, state->user_session_key.data);
+	talloc_steal(state, state->lm_session_key.data);
 
 	status = ntlmssp_server_postauth(gensec_security,
 					 gensec_ntlmssp,
@@ -784,43 +795,6 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
 }
 
 /**
- * Check the password on an NTLMSSP login.
- *
- * Return the session keys used on the connection.
- */
-
-static NTSTATUS ntlmssp_server_check_password(struct gensec_security *gensec_security,
-					      struct gensec_ntlmssp_context *gensec_ntlmssp,
-					      const struct auth_usersupplied_info *user_info,
-					      TALLOC_CTX *mem_ctx,
-					      DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
-{
-	struct auth4_context *auth_context = gensec_security->auth_context;
-	NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
-
-	if (auth_context->check_ntlm_password) {
-		uint8_t authoritative = 0;
-
-		nt_status = auth_context->check_ntlm_password(auth_context,
-							      gensec_ntlmssp,
-							      user_info,
-							      &authoritative,
-							      &gensec_ntlmssp->server_returned_info,
-							      user_session_key, lm_session_key);
-	}
-
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		DEBUG(5, (__location__ ": Checking NTLMSSP password for %s\\%s failed: %s\n", user_info->client.domain_name, user_info->client.account_name, nt_errstr(nt_status)));
-	}
-	NT_STATUS_NOT_OK_RETURN(nt_status);
-
-	talloc_steal(mem_ctx, user_session_key->data);
-	talloc_steal(mem_ctx, lm_session_key->data);
-
-	return nt_status;
-}
-
-/**
  * Next state function for the Authenticate packet
  * (after authentication - figures out the session keys etc)
  *
-- 
1.9.1


From 7b62fe22e9c1537d24428363fa69ad37987549d4 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 16 Jun 2017 17:18:17 +0200
Subject: [PATCH 09/16] auth/common: add support for
 auth4_ctx->check_ntlm_password_send/recv()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 auth/common_auth.h            | 10 +++++++
 auth/ntlmssp/ntlmssp_server.c | 65 +++++++++++++++++++++++++++++++++++++++++++
 source3/auth/auth_generic.c   | 49 +++++++++++++++++++++++++++-----
 3 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/auth/common_auth.h b/auth/common_auth.h
index 5079717..3de227e 100644
--- a/auth/common_auth.h
+++ b/auth/common_auth.h
@@ -131,6 +131,16 @@ struct auth4_context {
 					uint8_t *pauthoritative,
 					void **server_returned_info,
 					DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
+	struct tevent_req *(*check_ntlm_password_send)(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct auth4_context *auth_ctx,
+					const struct auth_usersupplied_info *user_info);
+	NTSTATUS (*check_ntlm_password_recv)(struct tevent_req *req,
+					TALLOC_CTX *mem_ctx,
+					uint8_t *pauthoritative,
+					void **server_returned_info,
+					DATA_BLOB *nt_session_key,
+					DATA_BLOB *lm_session_key);
 
 	NTSTATUS (*get_ntlm_challenge)(struct auth4_context *auth_ctx, uint8_t chal[8]);
 
diff --git a/auth/ntlmssp/ntlmssp_server.c b/auth/ntlmssp/ntlmssp_server.c
index 4990f77..417352b 100644
--- a/auth/ntlmssp/ntlmssp_server.c
+++ b/auth/ntlmssp/ntlmssp_server.c
@@ -296,6 +296,9 @@ NTSTATUS gensec_ntlmssp_server_negotiate(struct gensec_security *gensec_security
 }
 
 struct ntlmssp_server_auth_state {
+	struct gensec_security *gensec_security;
+	struct gensec_ntlmssp_context *gensec_ntlmssp;
+	DATA_BLOB in;
 	struct auth_usersupplied_info *user_info;
 	DATA_BLOB user_session_key;
 	DATA_BLOB lm_session_key;
@@ -310,6 +313,7 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
 				       struct gensec_ntlmssp_context *gensec_ntlmssp,
 				       struct ntlmssp_server_auth_state *state,
 				       const DATA_BLOB request);
+static void ntlmssp_server_auth_done(struct tevent_req *subreq);
 static NTSTATUS ntlmssp_server_postauth(struct gensec_security *gensec_security,
 					struct gensec_ntlmssp_context *gensec_ntlmssp,
 					struct ntlmssp_server_auth_state *state,
@@ -334,6 +338,9 @@ struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
+	state->gensec_security = gensec_security;
+	state->gensec_ntlmssp = gensec_ntlmssp;
+	state->in = in;
 
 	status = ntlmssp_server_preauth(gensec_security,
 					gensec_ntlmssp,
@@ -342,6 +349,21 @@ struct tevent_req *ntlmssp_server_auth_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	if (auth_context->check_ntlm_password_send != NULL) {
+		struct tevent_req *subreq = NULL;
+
+		subreq = auth_context->check_ntlm_password_send(state, ev,
+						auth_context,
+						state->user_info);
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq,
+					ntlmssp_server_auth_done,
+					req);
+		return req;
+	}
+
 	if (auth_context->check_ntlm_password == NULL) {
 		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
 		return tevent_req_post(req, ev);
@@ -794,6 +816,49 @@ static NTSTATUS ntlmssp_server_preauth(struct gensec_security *gensec_security,
 	return NT_STATUS_OK;
 }
 
+static void ntlmssp_server_auth_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct ntlmssp_server_auth_state *state =
+		tevent_req_data(req,
+		struct ntlmssp_server_auth_state);
+	struct gensec_security *gensec_security = state->gensec_security;
+	struct gensec_ntlmssp_context *gensec_ntlmssp = state->gensec_ntlmssp;
+	struct auth4_context *auth_context = gensec_security->auth_context;
+	uint8_t authoritative = 0;
+	NTSTATUS status;
+
+	status = auth_context->check_ntlm_password_recv(subreq,
+						gensec_ntlmssp,
+						&authoritative,
+						&gensec_ntlmssp->server_returned_info,
+						&state->user_session_key,
+						&state->lm_session_key);
+	TALLOC_FREE(subreq);
+	if (!NT_STATUS_IS_OK(status)) {
+		DBG_INFO("Checking NTLMSSP password for %s\\%s failed: %s\n",
+			 state->user_info->client.domain_name,
+			 state->user_info->client.account_name,
+			 nt_errstr(status));
+	}
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+	talloc_steal(state, state->user_session_key.data);
+	talloc_steal(state, state->lm_session_key.data);
+
+	status = ntlmssp_server_postauth(state->gensec_security,
+					 state->gensec_ntlmssp,
+					 state, state->in);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
 /**
  * Next state function for the Authenticate packet
  * (after authentication - figures out the session keys etc)
diff --git a/source3/auth/auth_generic.c b/source3/auth/auth_generic.c
index 6dedeed..167d4e0 100644
--- a/source3/auth/auth_generic.c
+++ b/source3/auth/auth_generic.c
@@ -22,6 +22,8 @@
 */
 
 #include "includes.h"
+#include <tevent.h>
+#include "../lib/util/tevent_ntstatus.h"
 #include "auth.h"
 #include "../lib/tsocket/tsocket.h"
 #include "auth/gensec/gensec.h"
@@ -413,14 +415,47 @@ NTSTATUS auth_check_password_session_info(struct auth4_context *auth_context,
 	void *server_info;
 	uint8_t authoritative = 0;
 
-	nt_status = auth_context->check_ntlm_password(auth_context,
-						      talloc_tos(),
-						      user_info,
-						      &authoritative,
-						      &server_info, NULL, NULL);
+	if (auth_context->check_ntlm_password_send != NULL) {
+		struct tevent_context *ev = NULL;
+		struct tevent_req *subreq = NULL;
+		bool ok;
 
-	if (!NT_STATUS_IS_OK(nt_status)) {
-		return nt_status;
+		ev = samba_tevent_context_init(talloc_tos());
+		if (ev == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		subreq = auth_context->check_ntlm_password_send(ev, ev,
+								auth_context,
+								user_info);
+		if (subreq == NULL) {
+			TALLOC_FREE(ev);
+			return NT_STATUS_NO_MEMORY;
+		}
+		ok = tevent_req_poll_ntstatus(subreq, ev, &nt_status);
+		if (!ok) {
+			TALLOC_FREE(ev);
+			return nt_status;
+		}
+		nt_status = auth_context->check_ntlm_password_recv(subreq,
+								   talloc_tos(),
+								   &authoritative,
+								   &server_info,
+								   NULL, NULL);
+		TALLOC_FREE(ev);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			return nt_status;
+		}
+	} else {
+		nt_status = auth_context->check_ntlm_password(auth_context,
+							      talloc_tos(),
+							      user_info,
+							      &authoritative,
+							      &server_info,
+							      NULL, NULL);
+		if (!NT_STATUS_IS_OK(nt_status)) {
+			return nt_status;
+		}
 	}
 
 	nt_status = auth_context->generate_session_info(auth_context,
-- 
1.9.1


From 37ea2fc81481336b0471de48076963d1bb9608fe Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 16 Jun 2017 23:07:04 +0200
Subject: [PATCH 10/16] s4:auth/ntlm: provide
 auth_check_password_wrapper_send/recv to auth4_context

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/auth/ntlm/auth.c | 83 +++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 72 insertions(+), 11 deletions(-)

diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 0e76348..9aa94bf 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -502,22 +502,81 @@ _PUBLIC_ NTSTATUS auth_check_password_recv(struct tevent_req *req,
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
-					    TALLOC_CTX *mem_ctx,
-					    const struct auth_usersupplied_info *user_info,
-					    uint8_t *pauthoritative,
-					    void **server_returned_info,
-					    DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
-{
+struct auth_check_password_wrapper_state {
+	uint8_t authoritative;
 	struct auth_user_info_dc *user_info_dc;
+};
+
+static void auth_check_password_wrapper_done(struct tevent_req *subreq);
+
+static struct tevent_req *auth_check_password_wrapper_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct auth4_context *auth_ctx,
+					const struct auth_usersupplied_info *user_info)
+{
+	struct tevent_req *req = NULL;
+	struct auth_check_password_wrapper *state = NULL;
+	struct tevent_req *subreq = NULL;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct auth_check_password_wrapper_state);
+	if (req == NULL) {
+		return NULL;
+	}
+
+	subreq = auth_check_password_send(state, ev, auth_ctx, user_info);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				auth_check_password_wrapper_done,
+				req);
+
+	return req;
+}
+
+static void auth_check_password_wrapper_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req =
+		tevent_req_callback_data(subreq,
+		struct tevent_req);
+	struct auth_check_password_wrapper_state *state =
+		tevent_req_data(req,
+		struct auth_check_password_wrapper_state);
 	NTSTATUS status;
 
-	status = auth_check_password(auth_ctx, mem_ctx, user_info,
-				     &user_info_dc, pauthoritative);
-	if (!NT_STATUS_IS_OK(status)) {
+	status = auth_check_password_recv(subreq, state,
+					  &state->user_info_dc,
+					  &state->authoritative);
+	TALLOC_FREE(subreq);
+	if (tevent_req_nterror(req, status)) {
+		return;
+	}
+
+	tevent_req_done(req);
+}
+
+static NTSTATUS auth_check_password_wrapper_recv(struct tevent_req *req,
+					TALLOC_CTX *mem_ctx,
+					uint8_t *pauthoritative,
+					void **server_returned_info,
+					DATA_BLOB *user_session_key,
+					DATA_BLOB *lm_session_key)
+{
+	struct auth_check_password_wrapper_state *state =
+		tevent_req_data(req,
+		struct auth_check_password_wrapper_state);
+	struct auth_user_info_dc *user_info_dc = state->user_info_dc;
+	NTSTATUS status = NT_STATUS_OK;
+
+	*pauthoritative = state->authoritative;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		tevent_req_received(req);
 		return status;
 	}
 
+	talloc_steal(mem_ctx, user_info_dc);
 	*server_returned_info = user_info_dc;
 
 	if (user_session_key) {
@@ -536,6 +595,7 @@ static NTSTATUS auth_check_password_wrapper(struct auth4_context *auth_ctx,
 		user_info_dc->lm_session_key = data_blob_null;
 	}
 
+	tevent_req_received(req);
 	return NT_STATUS_OK;
 }
 
@@ -673,7 +733,8 @@ _PUBLIC_ NTSTATUS auth_context_create_methods(TALLOC_CTX *mem_ctx, const char *
 		DLIST_ADD_END(ctx->methods, method);
 	}
 
-	ctx->check_ntlm_password = auth_check_password_wrapper;
+	ctx->check_ntlm_password_send = auth_check_password_wrapper_send;
+	ctx->check_ntlm_password_recv = auth_check_password_wrapper_recv;
 	ctx->get_ntlm_challenge = auth_get_challenge;
 	ctx->set_ntlm_challenge = auth_context_set_challenge;
 	ctx->generate_session_info = auth_generate_session_info_wrapper;
-- 
1.9.1


From 3b8e0cd390ec946361b3992cb1c7f13389cabab7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Wed, 22 Mar 2017 11:16:47 +0100
Subject: [PATCH 11/16] s4:auth: use "sam winbind" for the netlogon server

This adds authentication support for trusted domains to the
netlogon server.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/auth/ntlm/auth.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 9aa94bf..3424e503 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -840,14 +840,11 @@ _PUBLIC_ NTSTATUS auth_context_create_for_netlogon(TALLOC_CTX *mem_ctx,
 		DBG_NOTICE("using deprecated 'auth methods' values.\n");
 	} else {
 		/*
-		 * We can remove "winbind_rodc sam_failtrusts",
-		 * when we made the netlogon retries to
-		 * to contact winbind via irpc.
+		 * Here we only allow 'sam winbind' instead of
+		 * the 'anonymous sam winbind sam_ignoredomain'
+		 * we typically use for authentication from clients.
 		 */
-		_auth_methods = str_list_make(mem_ctx,
-				"sam "
-				"winbind_rodc sam_failtrusts",
-				NULL);
+		_auth_methods = str_list_make(mem_ctx, "sam winbind", NULL);
 		if (_auth_methods == NULL) {
 			return NT_STATUS_NO_MEMORY;
 		}
-- 
1.9.1


From b81a189078bebb5c5dd39f43d69754837b0af980 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Sat, 17 Jun 2017 01:06:46 +0200
Subject: [PATCH 12/16] s4:auth/ntlmssp: add support for using "winbind" as DC

This adds support for trusted domains to the auth stack on AD DCs.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 selftest/knownfail        |  8 +++-----
 source4/auth/ntlm/auth.c  | 17 +----------------
 source4/selftest/tests.py |  4 ++--
 3 files changed, 6 insertions(+), 23 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 1cba331..6f330ae 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -324,13 +324,11 @@
 #
 ^samba.tests.auth_log_pass_change.samba.tests.auth_log_pass_change.AuthLogPassChangeTests.test_rap_change_password\(ad_dc_ntvfs:local\)
 #
-# The following should pass once we have trust support
-^samba4.blackbox.trust_ntlm.Test07.*client.*with.ADDOMAIN\\Administrator%locDCpass1\(fl2008r2dc:local\)
-^samba4.blackbox.trust_ntlm.Test08.*client.*with.ADDOM.SAMBA.EXAMPLE.COM\\Administrator%locDCpass1\(fl2008r2dc:local\)
+# winbindd doesn't handle routing for domain="" and
+# account="Administrator at ADDOMAIN" yet.
+#
 ^samba4.blackbox.trust_ntlm.Test09.*client.*with.Administrator at ADDOMAIN%locDCpass1\(fl2008r2dc:local\)
 ^samba4.blackbox.trust_ntlm.Test10.*client.*with.Administrator at ADDOM.SAMBA.EXAMPLE.COM%locDCpass1\(fl2008r2dc:local\)
-^samba4.blackbox.trust_ntlm.Test07.*client.*with.ADDOMAIN\\Administrator%locDCpass1\(fl2003dc:local\)
-^samba4.blackbox.trust_ntlm.Test08.*client.*with.ADDOM.SAMBA.EXAMPLE.COM\\Administrator%locDCpass1\(fl2003dc:local\)
 ^samba4.blackbox.trust_ntlm.Test09.*client.*with.Administrator at ADDOMAIN%locDCpass1\(fl2003dc:local\)
 ^samba4.blackbox.trust_ntlm.Test10.*client.*with.Administrator at ADDOM.SAMBA.EXAMPLE.COM%locDCpass1\(fl2003dc:local\)
 # We currently don't send referrals for LDAP modify of non-replicated attrs
diff --git a/source4/auth/ntlm/auth.c b/source4/auth/ntlm/auth.c
index 3424e503..56c1bcf 100644
--- a/source4/auth/ntlm/auth.c
+++ b/source4/auth/ntlm/auth.c
@@ -768,25 +768,10 @@ const char **auth_methods_from_lp(TALLOC_CTX *mem_ctx, struct loadparm_context *
 		auth_methods = str_list_make(mem_ctx, "anonymous sam_ignoredomain", NULL);
 		break;
 	case ROLE_DOMAIN_MEMBER:
-		auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
-		break;
 	case ROLE_DOMAIN_BDC:
 	case ROLE_DOMAIN_PDC:
 	case ROLE_ACTIVE_DIRECTORY_DC:
-		/*
-		 * TODO: we should replace "winbind_rodc sam_failtrusts" with "winbind"
-		 * if everything (gensec/auth4) is fully async without nested
-		 * event loops!
-		 *
-		 * But for now we'll fail authentications for trusted
-		 * domain consistently with NT_STATUS_NO_TRUST_LSA_SECRET,
-		 * instead of silently mapping to local users.
-		 */
-		auth_methods = str_list_make(mem_ctx,
-					     "anonymous sam "
-					     "winbind_rodc sam_failtrusts "
-					     "sam_ignoredomain",
-					     NULL);
+		auth_methods = str_list_make(mem_ctx, "anonymous sam winbind sam_ignoredomain", NULL);
 		break;
 	}
 	return discard_const_p(const char *, auth_methods);
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
index 15037a2..75f7cbb 100755
--- a/source4/selftest/tests.py
+++ b/source4/selftest/tests.py
@@ -409,8 +409,8 @@ else:
     plantestsuite("samba4.blackbox.export.keytab(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_export_keytab_mit.sh"), '$SERVER', '$USERNAME', '$REALM', '$DOMAIN', "$PREFIX", smbclient4])
     plantestsuite("samba4.blackbox.kpasswd(ad_dc_ntvfs:local)", "ad_dc_ntvfs:local", [os.path.join(bbdir, "test_kpasswd_mit.sh"), '$SERVER', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', "$PREFIX/ad_dc_ntvfs"])
 
-plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
-plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_NO_TRUST_LSA_SECRET'])
+plantestsuite("samba4.blackbox.trust_ntlm", "fl2008r2dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'forest', 'auto', 'NT_STATUS_LOGON_FAILURE'])
+plantestsuite("samba4.blackbox.trust_ntlm", "fl2003dc:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$REALM', '$DOMAIN', '$TRUST_USERNAME', '$TRUST_PASSWORD', '$TRUST_REALM', '$TRUST_DOMAIN', 'external', 'auto', 'NT_STATUS_LOGON_FAILURE'])
 plantestsuite("samba4.blackbox.trust_ntlm", "ad_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$REALM', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
 plantestsuite("samba4.blackbox.trust_ntlm", "nt4_member:local", [os.path.join(bbdir, "test_trust_ntlm.sh"), '$SERVER_IP', '$USERNAME', '$PASSWORD', '$SERVER', '$SERVER', '$DC_USERNAME', '$DC_PASSWORD', '$DOMAIN', '$DOMAIN', 'member', 'auto', 'NT_STATUS_LOGON_FAILURE'])
 
-- 
1.9.1


From 443424715f158072326722edf7f0cc691d31535a Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 12:29:31 +0200
Subject: [PATCH 13/16] winbindd: allow all possible logon levels in
 wb_irpc_SamLogon()

We should just try to find the correct domain to forward the
request, all logic of not implementing serveral logon levels
belongs to the _winbind_SamLogon() implementation.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_irpc.c | 37 ++++++++++++++++++++++++++++++++++---
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
index c6c786c..ccff769 100644
--- a/source3/winbindd/winbindd_irpc.c
+++ b/source3/winbindd/winbindd_irpc.c
@@ -133,11 +133,42 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
 				 struct winbind_SamLogon *req)
 {
 	struct winbindd_domain *domain;
-	const char *target_domain_name;
-	if (req->in.logon.network == NULL) {
+	struct netr_IdentityInfo *identity_info;
+	const char *target_domain_name = NULL;
+
+	switch (req->in.logon_level) {
+	case NetlogonInteractiveInformation:
+	case NetlogonServiceInformation:
+	case NetlogonInteractiveTransitiveInformation:
+	case NetlogonServiceTransitiveInformation:
+		if (req->in.logon.password == NULL) {
+			return NT_STATUS_REQUEST_NOT_ACCEPTED;
+		}
+		identity_info = &req->in.logon.password->identity_info;
+		break;
+
+	case NetlogonNetworkInformation:
+	case NetlogonNetworkTransitiveInformation:
+		if (req->in.logon.network == NULL) {
+			return NT_STATUS_REQUEST_NOT_ACCEPTED;
+		}
+
+		identity_info = &req->in.logon.network->identity_info;
+		break;
+
+	case NetlogonGenericInformation:
+		if (req->in.logon.generic == NULL) {
+			return NT_STATUS_REQUEST_NOT_ACCEPTED;
+		}
+
+		identity_info = &req->in.logon.generic->identity_info;
+		break;
+
+	default:
 		return NT_STATUS_REQUEST_NOT_ACCEPTED;
 	}
-	target_domain_name = req->in.logon.network->identity_info.domain_name.string;
+
+	target_domain_name = identity_info->domain_name.string;
 
 	domain = find_auth_domain(0, target_domain_name);
 	if (domain == NULL) {
-- 
1.9.1


From 6b7bd81be6e241f1b811613eff005a3f8ebe2fa3 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 12:29:31 +0200
Subject: [PATCH 14/16] winbindd: debug if we don't know how to route a
 wb_irpc_SamLogon() request

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_irpc.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
index ccff769..3607643 100644
--- a/source3/winbindd/winbindd_irpc.c
+++ b/source3/winbindd/winbindd_irpc.c
@@ -135,6 +135,7 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
 	struct winbindd_domain *domain;
 	struct netr_IdentityInfo *identity_info;
 	const char *target_domain_name = NULL;
+	const char *account_name = NULL;
 
 	switch (req->in.logon_level) {
 	case NetlogonInteractiveInformation:
@@ -169,9 +170,19 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
 	}
 
 	target_domain_name = identity_info->domain_name.string;
+	if (target_domain_name == NULL) {
+		target_domain_name = "";
+	}
+
+	account_name = identity_info->account_name.string;
+	if (account_name == NULL) {
+		account_name = "";
+	}
 
 	domain = find_auth_domain(0, target_domain_name);
 	if (domain == NULL) {
+		DBG_INFO("target_domain[%s] for account[%s] not known\n",
+			target_domain_name, account_name);
 		req->out.result = NT_STATUS_NO_SUCH_USER;
 		req->out.authoritative = 0;
 		return NT_STATUS_OK;
-- 
1.9.1


From 85666aec37dfcf32ce12e896beb0f26b0269e4dd Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 12:29:31 +0200
Subject: [PATCH 15/16] winbindd: as DC we should try to get the target_domain
 from @SOMETHING part of the username in wb_irpc_SamLogon()

We still need a full routing table including all upn suffixes,
but this is a start to support NTLM authentication using user at REALM
against structed domains.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 selftest/knownfail               | 8 --------
 source3/winbindd/winbindd_irpc.c | 9 +++++++++
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/selftest/knownfail b/selftest/knownfail
index 6f330ae..700f3e1 100644
--- a/selftest/knownfail
+++ b/selftest/knownfail
@@ -323,14 +323,6 @@
 # rap password tests don't function in the ad_dc_ntvfs:local environment
 #
 ^samba.tests.auth_log_pass_change.samba.tests.auth_log_pass_change.AuthLogPassChangeTests.test_rap_change_password\(ad_dc_ntvfs:local\)
-#
-# winbindd doesn't handle routing for domain="" and
-# account="Administrator at ADDOMAIN" yet.
-#
-^samba4.blackbox.trust_ntlm.Test09.*client.*with.Administrator at ADDOMAIN%locDCpass1\(fl2008r2dc:local\)
-^samba4.blackbox.trust_ntlm.Test10.*client.*with.Administrator at ADDOM.SAMBA.EXAMPLE.COM%locDCpass1\(fl2008r2dc:local\)
-^samba4.blackbox.trust_ntlm.Test09.*client.*with.Administrator at ADDOMAIN%locDCpass1\(fl2003dc:local\)
-^samba4.blackbox.trust_ntlm.Test10.*client.*with.Administrator at ADDOM.SAMBA.EXAMPLE.COM%locDCpass1\(fl2003dc:local\)
 # We currently don't send referrals for LDAP modify of non-replicated attrs
 ^samba4.ldap.rodc.python\(rodc\).__main__.RodcTests.test_modify_nonreplicated.*
 ^samba4.ldap.rodc_rwdc.python.*.__main__.RodcRwdcTests.test_change_password_reveal_on_demand_kerberos
diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
index 3607643..87b890b 100644
--- a/source3/winbindd/winbindd_irpc.c
+++ b/source3/winbindd/winbindd_irpc.c
@@ -179,6 +179,15 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
 		account_name = "";
 	}
 
+	if (IS_DC && target_domain_name[0] == '\0') {
+		const char *p = NULL;
+
+		p = strchr_m(account_name, '@');
+		if (p != NULL) {
+			target_domain_name = p + 1;
+		}
+	}
+
 	domain = find_auth_domain(0, target_domain_name);
 	if (domain == NULL) {
 		DBG_INFO("target_domain[%s] for account[%s] not known\n",
-- 
1.9.1


From 637bf0dda2c123869ac2a3393b9513e9a2c48db7 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Fri, 21 Jul 2017 12:29:31 +0200
Subject: [PATCH 16/16] winbindd: give an IRPC error if wb_irpc_SamLogon() is
 called without useful routing information

The caller should have checked this already!

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/winbindd/winbindd_irpc.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c
index 87b890b..fface90 100644
--- a/source3/winbindd/winbindd_irpc.c
+++ b/source3/winbindd/winbindd_irpc.c
@@ -188,6 +188,12 @@ static NTSTATUS wb_irpc_SamLogon(struct irpc_message *msg,
 		}
 	}
 
+	if (IS_DC && target_domain_name[0] == '\0') {
+		DBG_ERR("target_domain[%s] account[%s]\n",
+			target_domain_name, account_name);
+		return NT_STATUS_REQUEST_NOT_ACCEPTED;
+	}
+
 	domain = find_auth_domain(0, target_domain_name);
 	if (domain == NULL) {
 		DBG_INFO("target_domain[%s] for account[%s] not known\n",
-- 
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/20170721/749959f9/signature.sig>


More information about the samba-technical mailing list