summaryrefslogtreecommitdiff
path: root/source4/rpc_server/netlogon/dcerpc_netlogon.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/rpc_server/netlogon/dcerpc_netlogon.c')
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c546
1 files changed, 1 insertions, 545 deletions
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 2d4e6a2d4c7..37f6d94420d 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -42,6 +42,7 @@
#include "librpc/gen_ndr/ndr_irpc.h"
#include "librpc/gen_ndr/ndr_winbind.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
+#include "librpc/rpc/server/netlogon/schannel_util.h"
#include "lib/socket/netif.h"
#include "lib/util/util_str_escape.h"
@@ -855,551 +856,6 @@ static NTSTATUS dcesrv_netr_ServerAuthenticate2(struct dcesrv_call_state *dce_ca
return dcesrv_netr_ServerAuthenticate3(dce_call, mem_ctx, &r3);
}
-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;
-
- bool seal_global_required;
- bool seal_required;
- bool seal_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;
- int schannel = lpcfg_server_schannel(lp_ctx);
- bool schannel_global_required = (schannel == true);
- bool schannel_required = schannel_global_required;
- const char *explicit_opt = NULL;
- bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx);
- bool require_seal = global_require_seal;
- const char *explicit_seal_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_seal_opt = lpcfg_get_parametric(lp_ctx,
- NULL,
- "server schannel require seal",
- creds->account_name);
- if (explicit_seal_opt != NULL) {
- require_seal = lp_bool(explicit_seal_opt);
- }
-
- /*
- * 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;
-
- s->seal_global_required = global_require_seal;
- s->seal_required = require_seal;
- s->seal_explicitly_set = explicit_seal_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);
- int CVE_2022_38023_warn_level = lpcfg_parm_int(lp_ctx, NULL,
- "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR);
- int CVE_2022_38023_error_level = lpcfg_parm_int(lp_ctx, NULL,
- "CVE_2022_38023", "error_debug_level", DBGLVL_ERR);
- TALLOC_CTX *frame = talloc_stackframe();
- unsigned int dbg_lvl = DBGLVL_DEBUG;
- const char *opname = "<unknown>";
- const char *reason = "<unknown>";
-
- if (opnum < ndr_table_netlogon.num_calls) {
- opname = ndr_table_netlogon.calls[opnum].name;
- }
-
- if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
- if (s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
- reason = "WITH SEALED";
- } else if (s->auth_level == DCERPC_AUTH_LEVEL_INTEGRITY) {
- reason = "WITH SIGNED";
- } else {
- reason = "WITH INVALID";
- dbg_lvl = DBGLVL_ERR;
- s->result = NT_STATUS_INTERNAL_ERROR;
- }
- } else {
- reason = "WITHOUT";
- }
-
- 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)/CVE-2022-38023: "
- "%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 (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL &&
- s->auth_level == DCERPC_AUTH_LEVEL_PRIVACY)
- {
- s->result = NT_STATUS_OK;
-
- if (s->schannel_explicitly_set && !s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
- } else if (!s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- }
- if (s->seal_explicitly_set && !s->seal_required) {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level);
- } else if (!s->seal_required) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- }
-
- DEBUG(dbg_lvl, (
- "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
- "%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)));
-
- 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",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
-
- if (s->seal_explicitly_set && !s->seal_required) {
- DEBUG(CVE_2022_38023_warn_level, (
- "CVE-2022-38023: "
- "Option 'server schannel require seal:%s = no' not needed for '%s'!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
-
- TALLOC_FREE(frame);
- return s->result;
- }
-
- if (s->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
- if (s->seal_required) {
- s->result = NT_STATUS_ACCESS_DENIED;
-
- if (s->seal_explicitly_set) {
- dbg_lvl = DBGLVL_NOTICE;
- } else {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
- }
- if (s->schannel_explicitly_set && !s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_warn_level);
- }
-
- DEBUG(dbg_lvl, (
- "CVE-2022-38023: "
- "%s request (opnum[%u]) %s schannel from "
- "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)));
- if (s->seal_explicitly_set) {
- D_NOTICE("CVE-2022-38023: Option "
- "'server schannel require seal:%s = yes' "
- "rejects access for client.\n",
- log_escape(frame, creds->account_name));
- } else {
- DEBUG(CVE_2020_1472_error_level, (
- "CVE-2022-38023: Check if option "
- "'server schannel require seal:%s = no' "
- "might be needed for a legacy client.\n",
- log_escape(frame, creds->account_name)));
- }
- 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",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
- TALLOC_FREE(frame);
- return s->result;
- }
-
- s->result = NT_STATUS_OK;
-
- if (s->schannel_explicitly_set && !s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_warn_level);
- } else if (!s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- }
- if (s->seal_explicitly_set && !s->seal_required) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- } else if (!s->seal_required) {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
- }
-
- 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)));
- 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",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
- if (s->seal_explicitly_set && !s->seal_required) {
- D_INFO("CVE-2022-38023: "
- "Option 'server schannel require seal:%s = no' still needed for '%s'!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name));
- } else if (!s->seal_required) {
- /*
- * admins should set
- * server schannel require seal:COMPUTER$ = no
- * in order to avoid the level 0 messages.
- * Over time they can switch the global value
- * to be strict.
- */
- DEBUG(CVE_2022_38023_error_level, (
- "CVE-2022-38023: "
- "Please use 'server schannel require seal:%s = no' "
- "for '%s' to avoid this warning!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
-
- TALLOC_FREE(frame);
- return s->result;
- }
-
- if (s->seal_required) {
- s->result = NT_STATUS_ACCESS_DENIED;
-
- if (s->seal_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
- } else {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
- }
- if (!s->schannel_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
- } else if (s->schannel_required) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
- }
-
- DEBUG(dbg_lvl, (
- "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
- "%s request (opnum[%u]) %s schannel from "
- "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)));
- if (s->seal_explicitly_set) {
- D_NOTICE("CVE-2022-38023: Option "
- "'server schannel require seal:%s = yes' "
- "rejects access for client.\n",
- log_escape(frame, creds->account_name));
- } else {
- DEBUG(CVE_2022_38023_error_level, (
- "CVE-2022-38023: Check if option "
- "'server schannel require seal:%s = no' "
- "might be needed for a legacy client.\n",
- log_escape(frame, creds->account_name)));
- }
- if (!s->schannel_explicitly_set) {
- DEBUG(CVE_2020_1472_error_level, (
- "CVE-2020-1472(ZeroLogon): Check if option "
- "'server require schannel:%s = no' "
- "might be needed for a legacy client.\n",
- log_escape(frame, creds->account_name)));
- } else if (s->schannel_required) {
- D_NOTICE("CVE-2022-38023: Option "
- "'server require schannel:%s = yes' "
- "also rejects access for client.\n",
- log_escape(frame, creds->account_name));
- }
- TALLOC_FREE(frame);
- return s->result;
- }
-
- if (s->schannel_required) {
- s->result = NT_STATUS_ACCESS_DENIED;
-
- if (s->schannel_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_NOTICE);
- } else {
- dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
- }
- if (!s->seal_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
- }
-
- DEBUG(dbg_lvl, (
- "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
- "%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)));
- if (s->schannel_explicitly_set) {
- D_NOTICE("CVE-2020-1472(ZeroLogon): Option "
- "'server require schannel:%s = yes' "
- "rejects access for client.\n",
- log_escape(frame, creds->account_name));
- } else {
- DEBUG(CVE_2020_1472_error_level, (
- "CVE-2020-1472(ZeroLogon): Check if option "
- "'server require schannel:%s = no' "
- "might be needed for a legacy client.\n",
- log_escape(frame, creds->account_name)));
- }
- if (!s->seal_explicitly_set) {
- DEBUG(CVE_2022_38023_error_level, (
- "CVE-2022-38023: Check if option "
- "'server schannel require seal:%s = no' "
- "might be needed for a legacy client.\n",
- log_escape(frame, creds->account_name)));
- }
- TALLOC_FREE(frame);
- return s->result;
- }
-
- s->result = NT_STATUS_OK;
-
- if (s->seal_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- } else {
- dbg_lvl = MIN(dbg_lvl, CVE_2022_38023_error_level);
- }
-
- if (s->schannel_explicitly_set) {
- dbg_lvl = MIN(dbg_lvl, DBGLVL_INFO);
- } else {
- dbg_lvl = MIN(dbg_lvl, CVE_2020_1472_error_level);
- }
-
- DEBUG(dbg_lvl, (
- "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
- "%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)));
-
- if (s->seal_explicitly_set) {
- D_INFO("CVE-2022-38023: Option "
- "'server schannel require seal:%s = no' "
- "still needed for '%s'!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name));
- } else {
- /*
- * admins should set
- * server schannel require seal:COMPUTER$ = no
- * in order to avoid the level 0 messages.
- * Over time they can switch the global value
- * to be strict.
- */
- DEBUG(CVE_2022_38023_error_level, (
- "CVE-2022-38023: Please use "
- "'server schannel require seal:%s = no' "
- "for '%s' to avoid this warning!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
-
- if (s->schannel_explicitly_set) {
- D_INFO("CVE-2020-1472(ZeroLogon): Option "
- "'server require schannel:%s = no' "
- "still needed for '%s'!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name));
- } else {
- /*
- * admins should set
- * server require schannel:COMPUTER$ = no
- * in order to avoid the level 0 messages.
- * Over time they can switch the global value
- * to be strict.
- */
- DEBUG(CVE_2020_1472_error_level, (
- "CVE-2020-1472(ZeroLogon): "
- "Please use 'server require schannel:%s = no' "
- "for '%s' to avoid this warning!\n",
- log_escape(frame, creds->account_name),
- log_escape(frame, creds->computer_name)));
- }
-
- 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;
-}
-
-/*
- * NOTE: The following functions are nearly identical to the ones available in
- * source3/rpc_server/srv_nelog_nt.c
- * The reason we keep 2 copies is that they use different structures to
- * represent the auth_info and the decrpc pipes.
- */
-static NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call,
- TALLOC_CTX *mem_ctx,
- const char *computer_name,
- struct netr_Authenticator *received_authenticator,
- struct netr_Authenticator *return_authenticator,
- struct netlogon_creds_CredentialState **creds_out)
-{
- NTSTATUS nt_status;
- struct netlogon_creds_CredentialState *creds = NULL;
- enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE;
- enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
-
- dcesrv_call_auth_info(dce_call, &auth_type, &auth_level);
-
- nt_status = schannel_check_creds_state(mem_ctx,
- dce_call->conn->dce_ctx->lp_ctx,
- computer_name,
- received_authenticator,
- return_authenticator,
- &creds);
- if (!NT_STATUS_IS_OK(nt_status)) {
- ZERO_STRUCTP(return_authenticator);
- return nt_status;
- }
-
- nt_status = dcesrv_netr_check_schannel(dce_call,
- creds,
- auth_type,
- auth_level,
- dce_call->pkt.u.request.opnum);
- if (!NT_STATUS_IS_OK(nt_status)) {
- TALLOC_FREE(creds);
- ZERO_STRUCTP(return_authenticator);
- return nt_status;
- }
-
- *creds_out = creds;
- return NT_STATUS_OK;
-}
-
/*
Change the machine account password for the currently connected
client. Supplies only the NT#.