summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c193
1 files changed, 153 insertions, 40 deletions
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index d5bca620b0d..624c8d40724 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -877,23 +877,105 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);
}
-static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
- const struct netlogon_creds_CredentialState *creds,
- enum dcerpc_AuthType auth_type,
- enum dcerpc_AuthLevel auth_level,
- uint16_t opnum)
+struct dcesrv_netr_check_schannel_state {
+ struct dom_sid account_sid;
+ enum dcerpc_AuthType auth_type;
+ enum dcerpc_AuthLevel auth_level;
+
+ bool schannel_global_required;
+ bool schannel_required;
+ bool schannel_explicitly_set;
+
+ NTSTATUS result;
+};
+
+static NTSTATUS dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state *dce_call,
+ const struct netlogon_creds_CredentialState *creds,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ struct dcesrv_netr_check_schannel_state **_s)
{
struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
- TALLOC_CTX *frame = talloc_stackframe();
- NTSTATUS nt_status;
int schannel = lpcfg_server_schannel(lp_ctx);
bool schannel_global_required = (schannel == true);
bool schannel_required = schannel_global_required;
const char *explicit_opt = NULL;
+#define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1)
+ struct dcesrv_netr_check_schannel_state *s = NULL;
+ NTSTATUS status;
+
+ *_s = NULL;
+
+ s = dcesrv_iface_state_find_conn(dce_call,
+ DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC,
+ struct dcesrv_netr_check_schannel_state);
+ if (s != NULL) {
+ if (!dom_sid_equal(&s->account_sid, creds->sid)) {
+ goto new_state;
+ }
+ if (s->auth_type != auth_type) {
+ goto new_state;
+ }
+ if (s->auth_level != auth_level) {
+ goto new_state;
+ }
+
+ *_s = s;
+ return NT_STATUS_OK;
+ }
+
+new_state:
+ TALLOC_FREE(s);
+ s = talloc_zero(dce_call,
+ struct dcesrv_netr_check_schannel_state);
+ if (s == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ s->account_sid = *creds->sid;
+ s->auth_type = auth_type;
+ s->auth_level = auth_level;
+ s->result = NT_STATUS_MORE_PROCESSING_REQUIRED;
+
+ /*
+ * We don't use lpcfg_parm_bool(), as we
+ * need the explicit_opt pointer in order to
+ * adjust the debug messages.
+ */
+ explicit_opt = lpcfg_get_parametric(lp_ctx,
+ NULL,
+ "server require schannel",
+ creds->account_name);
+ if (explicit_opt != NULL) {
+ schannel_required = lp_bool(explicit_opt);
+ }
+
+ s->schannel_global_required = schannel_global_required;
+ s->schannel_required = schannel_required;
+ s->schannel_explicitly_set = explicit_opt != NULL;
+
+ status = dcesrv_iface_state_store_conn(dce_call,
+ DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC,
+ s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ *_s = s;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcesrv_netr_check_schannel_once(struct dcesrv_call_state *dce_call,
+ struct dcesrv_netr_check_schannel_state *s,
+ const struct netlogon_creds_CredentialState *creds,
+ uint16_t opnum)
+{
+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
int CVE_2020_1472_warn_level = lpcfg_parm_int(lp_ctx, NULL,
"CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR);
int CVE_2020_1472_error_level = lpcfg_parm_int(lp_ctx, NULL,
"CVE_2020_1472", "error_debug_level", DBGLVL_ERR);
+ TALLOC_CTX *frame = talloc_stackframe();
unsigned int dbg_lvl = DBGLVL_DEBUG;
const char *opname = "<unknown>";
const char *reason = "<unknown>";
@@ -902,37 +984,43 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
opname = ndr_table_netlogon.calls[opnum].name;
}
- if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
- if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
+ if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ if (s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
reason = "WITH SEALED";
- } else if (auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
+ } else if (s->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
reason = "WITH SIGNED";
} else {
- smb_panic("Schannel without SIGN/SEAL");
+ reason = "WITH INVALID";
+ dbg_lvl = DBGLVL_ERR;
+ s->result = NT_STATUS_INTERNAL_ERROR;
}
} else {
reason = "WITHOUT";
}
- /*
- * We don't use lpcfg_parm_bool(), as we
- * need the explicit_opt pointer in order to
- * adjust the debug messages.
- */
- explicit_opt = lpcfg_get_parametric(lp_ctx,
- NULL,
- "server require schannel",
- creds->account_name);
- if (explicit_opt != NULL) {
- schannel_required = lp_bool(explicit_opt);
+ if (!NT_STATUS_EQUAL(s->result, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ if (!NT_STATUS_IS_OK(s->result)) {
+ dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
+ }
+
+ DEBUG(dbg_lvl, (
+ "CVE-2020-1472(ZeroLogon): "
+ "%s request (opnum[%u]) %s schannel from "
+ "client_account[%s] client_computer_name[%s] %s\n",
+ opname, opnum, reason,
+ log_escape(frame, creds->account_name),
+ log_escape(frame, creds->computer_name),
+ nt_errstr(s->result)));
+ TALLOC_FREE(frame);
+ return s->result;
}
- if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
- nt_status = NT_STATUS_OK;
+ if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
+ s->result = NT_STATUS_OK;
- if (explicit_opt != NULL && !schannel_required) {
+ if (s->schannel_explicitly_set && !s->schannel_required) {
dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
- } else if (!schannel_required) {
+ } else if (!s->schannel_required) {
dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
}
@@ -943,9 +1031,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
opname, opnum, reason,
log_escape(frame, creds->account_name),
log_escape(frame, creds->computer_name),
- nt_errstr(nt_status)));
-
- if (explicit_opt != NULL && !schannel_required) {
+ nt_errstr(s->result)));
+ if (s->schannel_explicitly_set && !s->schannel_required) {
DEBUG(CVE_2020_1472_warn_level, (
"CVE-2020-1472(ZeroLogon): "
"Option 'server require schannel:%s = no' not needed for '%s'!\n",
@@ -954,13 +1041,13 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
}
TALLOC_FREE(frame);
- return nt_status;
+ return s->result;
}
- if (schannel_required) {
- nt_status = NT_STATUS_ACCESS_DENIED;
+ if (s->schannel_required) {
+ s->result = NT_STATUS_ACCESS_DENIED;
- if (explicit_opt != NULL) {
+ if (s->schannel_explicitly_set) {
dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
} else {
dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
@@ -973,8 +1060,8 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
opname, opnum, reason,
log_escape(frame, creds->account_name),
log_escape(frame, creds->computer_name),
- nt_errstr(nt_status)));
- if (explicit_opt != NULL) {
+ nt_errstr(s->result)));
+ if (s->schannel_explicitly_set) {
D_NOTICE("CVE-2020-1472(ZeroLogon): Option "
"'server require schannel:%s = yes' "
"rejects access for client.\n",
@@ -987,12 +1074,12 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
log_escape(frame, creds->account_name)));
}
TALLOC_FREE(frame);
- return nt_status;
+ return s->result;
}
- nt_status = NT_STATUS_OK;
+ s->result = NT_STATUS_OK;
- if (explicit_opt != NULL) {
+ if (s->schannel_explicitly_set) {
dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
} else {
dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
@@ -1005,9 +1092,9 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
opname, opnum, reason,
log_escape(frame, creds->account_name),
log_escape(frame, creds->computer_name),
- nt_errstr(nt_status)));
+ nt_errstr(s->result)));
- if (explicit_opt != NULL) {
+ if (s->schannel_explicitly_set) {
D_INFO("CVE-2020-1472(ZeroLogon): Option "
"'server require schannel:%s = no' "
"still needed for '%s'!\n",
@@ -1030,6 +1117,32 @@ static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
}
TALLOC_FREE(frame);
+ return s->result;
+}
+
+static NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call,
+ const struct netlogon_creds_CredentialState *creds,
+ enum dcerpc_AuthType auth_type,
+ enum dcerpc_AuthLevel auth_level,
+ uint16_t opnum)
+{
+ struct dcesrv_netr_check_schannel_state *s = NULL;
+ NTSTATUS status;
+
+ status = dcesrv_netr_check_schannel_get_state(dce_call,
+ creds,
+ auth_type,
+ auth_level,
+ &s);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = dcesrv_netr_check_schannel_once(dce_call, s, creds, opnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
return NT_STATUS_OK;
}