From b7bd51a393988883936048a0fd9d790d0e03481f Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze@samba.org>
Date: Fri, 25 Nov 2022 09:54:17 +0100
Subject: [PATCH 15/30] CVE-2022-38023 s4:rpc_server/netlogon: split out
 dcesrv_netr_ServerAuthenticate3_check_downgrade()

We'll soon make it possible to use 'reject md5 servers:CLIENTACCOUNT$ = no',
which means we'll need the downgrade detection in more places.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
(cherry picked from commit b6339fd1dcbe903e73efeea074ab0bd04ef83561)

Conflict: NA
Reference: https://attachments.samba.org/attachment.cgi?id=17692
---
 source4/rpc_server/netlogon/dcerpc_netlogon.c | 114 ++++++++++--------
 1 file changed, 67 insertions(+), 47 deletions(-)

diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index ce01400ec88b..82e3df055e7f 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -125,6 +125,67 @@ static NTSTATUS dcesrv_netr_ServerReqChallenge(struct dcesrv_call_state *dce_cal
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS dcesrv_netr_ServerAuthenticate3_check_downgrade(
+	struct dcesrv_call_state *dce_call,
+	struct netr_ServerAuthenticate3 *r,
+	struct netlogon_server_pipe_state *pipe_state,
+	uint32_t negotiate_flags,
+	NTSTATUS orig_status)
+{
+	struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+	bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(lp_ctx);
+	bool reject_des_client = !allow_nt4_crypto;
+	bool reject_md5_client = lpcfg_reject_md5_clients(lp_ctx);
+
+	if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
+		reject_des_client = false;
+	}
+
+	if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
+		reject_des_client = false;
+		reject_md5_client = false;
+	}
+
+	if (reject_des_client || reject_md5_client) {
+		/*
+		 * Here we match Windows 2012 and return no flags.
+		 */
+		*r->out.negotiate_flags = 0;
+		return NT_STATUS_DOWNGRADE_DETECTED;
+	}
+
+	/*
+	 * This talloc_free is important to prevent re-use of the
+	 * challenge.  We have to delay it this far due to NETApp
+	 * servers per:
+	 * https://bugzilla.samba.org/show_bug.cgi?id=11291
+	 */
+	TALLOC_FREE(pipe_state);
+
+	/*
+	 * At this point we must also cleanup the TDB cache
+	 * entry, if we fail the client needs to call
+	 * netr_ServerReqChallenge again.
+	 *
+	 * Note: this handles a non existing record just fine,
+	 * the r->in.computer_name might not be the one used
+	 * in netr_ServerReqChallenge(), but we are trying to
+	 * just tidy up the normal case to prevent re-use.
+	 */
+	schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx,
+				  r->in.computer_name);
+
+	/*
+	 * According to Microsoft (see bugid #6099)
+	 * Windows 7 looks at the negotiate_flags
+	 * returned in this structure *even if the
+	 * call fails with access denied!
+	 */
+	*r->out.negotiate_flags = negotiate_flags;
+
+	return orig_status;
+}
+
 /*
  * Do the actual processing of a netr_ServerAuthenticate3 message.
  * called from dcesrv_netr_ServerAuthenticate3, which handles the logging.
@@ -152,11 +213,9 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper(
 			       "objectSid", "samAccountName", NULL};
 	uint32_t server_flags = 0;
 	uint32_t negotiate_flags = 0;
-	bool allow_nt4_crypto = lpcfg_allow_nt4_crypto(dce_call->conn->dce_ctx->lp_ctx);
-	bool reject_des_client = !allow_nt4_crypto;
-	bool reject_md5_client = lpcfg_reject_md5_clients(dce_call->conn->dce_ctx->lp_ctx);
 
 	ZERO_STRUCTP(r->out.return_credentials);
+	*r->out.negotiate_flags = 0;
 	*r->out.rid = 0;
 
 	pipe_state = dcesrv_iface_state_find_conn(dce_call,
@@ -243,52 +302,13 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate3_helper(
 
 	negotiate_flags = *r->in.negotiate_flags & server_flags;
 
-	if (negotiate_flags & NETLOGON_NEG_STRONG_KEYS) {
-		reject_des_client = false;
-	}
-
-	if (negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
-		reject_des_client = false;
-		reject_md5_client = false;
-	}
-
-	if (reject_des_client || reject_md5_client) {
-		/*
-		 * Here we match Windows 2012 and return no flags.
-		 */
-		*r->out.negotiate_flags = 0;
-		return NT_STATUS_DOWNGRADE_DETECTED;
+	nt_status = dcesrv_netr_ServerAuthenticate3_check_downgrade(
+			dce_call, r, pipe_state, negotiate_flags,
+			NT_STATUS_OK);
+	if (!NT_STATUS_IS_OK(nt_status)) {
+		return nt_status;
 	}
 
-	/*
-	 * This talloc_free is important to prevent re-use of the
-	 * challenge.  We have to delay it this far due to NETApp
-	 * servers per:
-	 * https://bugzilla.samba.org/show_bug.cgi?id=11291
-	 */
-	TALLOC_FREE(pipe_state);
-
-	/*
-	 * At this point we must also cleanup the TDB cache
-	 * entry, if we fail the client needs to call
-	 * netr_ServerReqChallenge again.
-	 *
-	 * Note: this handles a non existing record just fine,
-	 * the r->in.computer_name might not be the one used
-	 * in netr_ServerReqChallenge(), but we are trying to
-	 * just tidy up the normal case to prevent re-use.
-	 */
-	schannel_delete_challenge(dce_call->conn->dce_ctx->lp_ctx,
-				  r->in.computer_name);
-
-	/*
-	 * According to Microsoft (see bugid #6099)
-	 * Windows 7 looks at the negotiate_flags
-	 * returned in this structure *even if the
-	 * call fails with access denied!
-	 */
-	*r->out.negotiate_flags = negotiate_flags;
-
 	switch (r->in.secure_channel_type) {
 	case SEC_CHAN_WKSTA:
 	case SEC_CHAN_DNS_DOMAIN:
-- 
2.34.1
