1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

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>
This commit is contained in:
Stefan Metzmacher 2022-11-25 09:54:17 +01:00
parent cfd55a22cd
commit b6339fd1dc

View File

@ -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;
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;
}
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;
switch (r->in.secure_channel_type) {
case SEC_CHAN_WKSTA:
case SEC_CHAN_DNS_DOMAIN: