diff options
Diffstat (limited to 'source4/rpc_server/netlogon/dcerpc_netlogon.c')
-rw-r--r-- | source4/rpc_server/netlogon/dcerpc_netlogon.c | 546 |
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#. |