From d513d3d0c16d7658cf247aca6a07ac16c612de9b Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Wed, 21 Dec 2022 15:53:04 +0100 Subject: [PATCH 1/9] CVE-2022-38023 s3:rpc_server/netlogon: 'server schannel != yes' warning to dcesrv_interface_netlogon_bind Follow s4 netlogon server changes and move the checks to the RPC bind hook. Next commits will remove the s3 netr_creds_server_step_check() function. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 8141eae47aad849741beb138fae866c772e4ec4c) --- source3/rpc_server/netlogon/srv_netlog_nt.c | 39 +++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index cc92c84cc07..5db3f7ad97d 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1081,7 +1081,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; uint16_t opnum = dce_call->pkt.u.request.opnum; const char *opname = ""; - static bool warned_global_once = false; if (creds_out != NULL) { *creds_out = NULL; @@ -1143,16 +1142,6 @@ static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, return NT_STATUS_ACCESS_DENIED; } - if (!schannel_global_required && !warned_global_once) { - /* - * We want admins to notice their misconfiguration! - */ - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Please configure 'server schannel = yes', " - "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); - warned_global_once = true; - } - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { DBG_ERR("CVE-2020-1472(ZeroLogon): " "%s request (opnum[%u]) WITH schannel from " @@ -2997,5 +2986,33 @@ NTSTATUS _netr_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p, return NT_STATUS_NOT_IMPLEMENTED; } +/* + * Define the bind function that will be used by ndr_netlogon_scompat.c, + * included at the bottom of this file. + */ +#define DCESRV_INTERFACE_NETLOGON_BIND(context, iface) \ + dcesrv_interface_netlogon_bind(context, iface) + +static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context *context, + const struct dcesrv_interface *iface) +{ + struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; + int schannel = lpcfg_server_schannel(lp_ctx); + bool schannel_global_required = (schannel == true); + static bool warned_global_schannel_once = false; + + if (!schannel_global_required && !warned_global_schannel_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2020-1472(ZeroLogon): " + "Please configure 'server schannel = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=14497\n"); + warned_global_schannel_once = true; + } + + return NT_STATUS_OK; +} + /* include the generated boilerplate */ #include "librpc/gen_ndr/ndr_netlogon_scompat.c" -- 2.39.0 From f8f4902f6b48e7a06ebee10fe75ba577dfff6ba4 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 16:46:15 +0100 Subject: [PATCH 2/9] CVE-2022-38023 selftest:Samba3: avoid global 'server schannel = auto' Instead of using the generic deprecated option use the specific server require schannel:COMPUTERACCOUNT = no in order to allow legacy tests for pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 3cd18690f83d2f85e847fc703ac127b4b04189fc) --- selftest/target/Samba3.pm | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 64374ab9bcd..b985bf7a33c 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -272,9 +272,23 @@ sub setup_nt4_dc lanman auth = yes ntlm auth = yes raw NTLMv2 auth = yes - server schannel = auto rpc start on demand helpers = false + CVE_2020_1472:warn_about_unused_debug_level = 3 + server require schannel:schannel0\$ = no + server require schannel:schannel1\$ = no + server require schannel:schannel2\$ = no + server require schannel:schannel3\$ = no + server require schannel:schannel4\$ = no + server require schannel:schannel5\$ = no + server require schannel:schannel6\$ = no + server require schannel:schannel7\$ = no + server require schannel:schannel8\$ = no + server require schannel:schannel9\$ = no + server require schannel:schannel10\$ = no + server require schannel:schannel11\$ = no + server require schannel:torturetest\$ = no + vfs_default:VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS = no fss: sequence timeout = 1 -- 2.39.0 From 77d97ed15de2fd12b4df705fe16c27b0839189b1 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 5 Jan 2023 18:13:09 +0100 Subject: [PATCH 3/9] CVE-2022-38023 s4:rpc_server:wscript: Reformat following pycodestyle BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit d9e6b490db3ead7e79bb3ff0c1f9ef8ab8bdc65b) --- source4/rpc_server/wscript_build | 290 ++++++++++++++++++------------- 1 file changed, 168 insertions(+), 122 deletions(-) diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build index 8c756721232..e7bb773d719 100644 --- a/source4/rpc_server/wscript_build +++ b/source4/rpc_server/wscript_build @@ -1,174 +1,220 @@ #!/usr/bin/env python bld.SAMBA_SUBSYSTEM('DCERPC_SHARE', - source='common/share_info.c', - autoproto='common/share.h', - deps='ldb share', - enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER'), - ) + source='common/share_info.c', + autoproto='common/share.h', + deps='ldb share', + enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER'), + ) bld.SAMBA_SUBSYSTEM('DCERPC_COMMON', - source='common/server_info.c common/forward.c common/loadparm.c', - autoproto='common/proto.h', - deps='ldb DCERPC_SHARE', - enabled=bld.AD_DC_BUILD_IS_ENABLED() - ) + source=''' + common/server_info.c + common/forward.c + common/loadparm.c + ''', + autoproto='common/proto.h', + deps='ldb DCERPC_SHARE', + enabled=bld.AD_DC_BUILD_IS_ENABLED() + ) bld.SAMBA_LIBRARY('dcerpc_server', - source='dcerpc_server.c', - pc_files='dcerpc_server.pc', - deps='LIBCLI_AUTH ndr samba_server_gensec service auth', - public_deps='dcerpc dcerpc-server-core', - autoproto='dcerpc_server_proto.h', - public_headers='dcerpc_server.h', - vnum='0.0.1', - enabled=bld.AD_DC_BUILD_IS_ENABLED() - ) + source='dcerpc_server.c', + pc_files='dcerpc_server.pc', + deps='LIBCLI_AUTH ndr samba_server_gensec service auth', + public_deps='dcerpc dcerpc-server-core', + autoproto='dcerpc_server_proto.h', + public_headers='dcerpc_server.h', + vnum='0.0.1', + enabled=bld.AD_DC_BUILD_IS_ENABLED() + ) bld.SAMBA_MODULE('dcerpc_rpcecho', - source='echo/rpc_echo.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_rpcecho_init', - deps='ndr-standard events' - ) + source='echo/rpc_echo.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_rpcecho_init', + deps='ndr-standard events' + ) bld.SAMBA_MODULE('dcerpc_epmapper', - source='epmapper/rpc_epmapper.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_epmapper_init', - deps='NDR_EPMAPPER' - ) + source='epmapper/rpc_epmapper.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_epmapper_init', + deps='NDR_EPMAPPER' + ) bld.SAMBA_MODULE('dcerpc_remote', - source='remote/dcesrv_remote.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_remote_init', - deps='LIBCLI_SMB ndr-table' - ) + source='remote/dcesrv_remote.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_remote_init', + deps='LIBCLI_SMB ndr-table' + ) bld.SAMBA_MODULE('dcerpc_srvsvc', - source='srvsvc/dcesrv_srvsvc.c srvsvc/srvsvc_ntvfs.c', - autoproto='srvsvc/proto.h', - subsystem='dcerpc_server', - init_function='dcerpc_server_srvsvc_init', - deps='DCERPC_COMMON NDR_SRVSVC share ntvfs', - enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER') - ) + source='srvsvc/dcesrv_srvsvc.c srvsvc/srvsvc_ntvfs.c', + autoproto='srvsvc/proto.h', + subsystem='dcerpc_server', + init_function='dcerpc_server_srvsvc_init', + deps='DCERPC_COMMON NDR_SRVSVC share ntvfs', + enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER') + ) bld.SAMBA_MODULE('dcerpc_wkssvc', - source='wkssvc/dcesrv_wkssvc.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_wkssvc_init', - deps='DCERPC_COMMON ndr-standard' - ) + source='wkssvc/dcesrv_wkssvc.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_wkssvc_init', + deps='DCERPC_COMMON ndr-standard' + ) bld.SAMBA_MODULE('dcerpc_unixinfo', - source='unixinfo/dcesrv_unixinfo.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_unixinfo_init', - deps='DCERPC_COMMON samdb NDR_UNIXINFO LIBWBCLIENT_OLD' - ) + source='unixinfo/dcesrv_unixinfo.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_unixinfo_init', + deps='DCERPC_COMMON samdb NDR_UNIXINFO LIBWBCLIENT_OLD' + ) bld.SAMBA_MODULE('dcesrv_samr', - source='samr/dcesrv_samr.c samr/samr_password.c', - autoproto='samr/proto.h', - subsystem='dcerpc_server', - init_function='dcerpc_server_samr_init', - deps='samdb DCERPC_COMMON ndr-standard auth4_sam GNUTLS_HELPERS DCERPC_HELPER' - ) + source='samr/dcesrv_samr.c samr/samr_password.c', + autoproto='samr/proto.h', + subsystem='dcerpc_server', + init_function='dcerpc_server_samr_init', + deps=''' + samdb + DCERPC_COMMON + ndr-standard + auth4_sam + GNUTLS_HELPERS + DCERPC_HELPER + ''' + ) bld.SAMBA_MODULE('dcerpc_winreg', - source='winreg/rpc_winreg.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_winreg_init', - deps='registry ndr-standard', - internal_module=True, - enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER') - ) + source='winreg/rpc_winreg.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_winreg_init', + deps='registry ndr-standard', + internal_module=True, + enabled=bld.CONFIG_SET('WITH_NTVFS_FILESERVER') + ) bld.SAMBA_MODULE('dcerpc_netlogon', - source='netlogon/dcerpc_netlogon.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_netlogon_init', - deps='''DCERPC_COMMON RPC_NDR_IRPC COMMON_SCHANNEL ndr-standard auth4_sam samba-hostconfig DSDB_MODULE_HELPERS - util_str_escape''' - ) + source='netlogon/dcerpc_netlogon.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_netlogon_init', + deps=''' + DCERPC_COMMON + RPC_NDR_IRPC + COMMON_SCHANNEL + ndr-standard + auth4_sam + samba-hostconfig + DSDB_MODULE_HELPERS + util_str_escape + ''' + ) bld.SAMBA_MODULE('dcerpc_lsarpc', - source='lsa/dcesrv_lsa.c lsa/lsa_init.c lsa/lsa_lookup.c', - autoproto='lsa/proto.h', - subsystem='dcerpc_server', - init_function='dcerpc_server_lsa_init', - deps='samdb DCERPC_COMMON ndr-standard LIBCLI_AUTH NDR_DSSETUP com_err samba-security UTIL_LSARPC' - ) + source='lsa/dcesrv_lsa.c lsa/lsa_init.c lsa/lsa_lookup.c', + autoproto='lsa/proto.h', + subsystem='dcerpc_server', + init_function='dcerpc_server_lsa_init', + deps=''' + samdb + DCERPC_COMMON + ndr-standard + LIBCLI_AUTH + NDR_DSSETUP + com_err + samba-security + UTIL_LSARPC + ''' + ) bld.SAMBA_MODULE('dcerpc_backupkey', - source='backupkey/dcesrv_backupkey.c ', - autoproto='backupkey/proto.h', - subsystem='dcerpc_server', - init_function='dcerpc_server_backupkey_init', - deps='samdb DCERPC_COMMON NDR_BACKUPKEY RPC_NDR_BACKUPKEY gnutls GNUTLS_HELPERS', - ) + source='backupkey/dcesrv_backupkey.c ', + autoproto='backupkey/proto.h', + subsystem='dcerpc_server', + init_function='dcerpc_server_backupkey_init', + deps=''' + samdb + DCERPC_COMMON + NDR_BACKUPKEY + RPC_NDR_BACKUPKEY + gnutls + GNUTLS_HELPERS + ''', + ) bld.SAMBA_MODULE('dcerpc_drsuapi', - source='drsuapi/dcesrv_drsuapi.c drsuapi/updaterefs.c drsuapi/getncchanges.c drsuapi/addentry.c drsuapi/writespn.c drsuapi/drsutil.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_drsuapi_init', - deps='samdb DCERPC_COMMON NDR_DRSUAPI samba-security' - ) + source=''' + drsuapi/dcesrv_drsuapi.c + drsuapi/updaterefs.c + drsuapi/getncchanges.c + drsuapi/addentry.c + drsuapi/writespn.c + drsuapi/drsutil.c + ''', + subsystem='dcerpc_server', + init_function='dcerpc_server_drsuapi_init', + deps='samdb DCERPC_COMMON NDR_DRSUAPI samba-security' + ) bld.SAMBA_MODULE('dcerpc_browser', - source='browser/dcesrv_browser.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_browser_init', - deps='DCERPC_COMMON NDR_BROWSER' - ) + source='browser/dcesrv_browser.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_browser_init', + deps='DCERPC_COMMON NDR_BROWSER' + ) bld.SAMBA_MODULE('dcerpc_eventlog', - source='eventlog/dcesrv_eventlog6.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_eventlog6_init', - deps='DCERPC_COMMON' - ) + source='eventlog/dcesrv_eventlog6.c', + subsystem='dcerpc_server', + init_function='dcerpc_server_eventlog6_init', + deps='DCERPC_COMMON' + ) bld.SAMBA_MODULE('dcerpc_dnsserver', - source='dnsserver/dcerpc_dnsserver.c dnsserver/dnsutils.c dnsserver/dnsdata.c dnsserver/dnsdb.c', - subsystem='dcerpc_server', - init_function='dcerpc_server_dnsserver_init', - deps='DCERPC_COMMON dnsserver_common netif' - ) + source=''' + dnsserver/dcerpc_dnsserver.c + dnsserver/dnsutils.c + dnsserver/dnsdata.c + dnsserver/dnsdb.c + ''', + subsystem='dcerpc_server', + init_function='dcerpc_server_dnsserver_init', + deps='DCERPC_COMMON dnsserver_common netif' + ) bld.SAMBA_MODULE('service_dcerpc', - source='service_rpc.c', - autoproto='service_rpc.h', - subsystem='service', - init_function='server_service_rpc_init', - internal_module=False, - deps='dcerpc_server' - ) - -bld.SAMBA_BINARY( - 'test_rpc_dns_server_dnsutils', - source='tests/rpc_dns_server_dnsutils_test.c', - deps=''' - dnsserver_common - dcerpc_server - cmocka - talloc - ''', - for_selftest=True, - enabled=bld.AD_DC_BUILD_IS_ENABLED() -) + source='service_rpc.c', + autoproto='service_rpc.h', + subsystem='service', + init_function='server_service_rpc_init', + internal_module=False, + deps='dcerpc_server' + ) + +bld.SAMBA_BINARY('test_rpc_dns_server_dnsutils', + source='tests/rpc_dns_server_dnsutils_test.c', + deps=''' + dnsserver_common + dcerpc_server + cmocka + talloc + ''', + for_selftest=True, + enabled=bld.AD_DC_BUILD_IS_ENABLED() + ) -- 2.39.0 From 1b3332baf17f13a6956da942702cfdb1d1d1648f Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 14:03:23 +0100 Subject: [PATCH 4/9] CVE-2022-38023 s4:rpc_server/netlogon: Move schannel and credentials check functions to librpc Will be used later by s3 netlogon server. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 121e7b0e39478c5291100652ac92c263f406076b) --- librpc/rpc/server/netlogon/schannel_util.c | 576 ++++++++++++++++++ librpc/rpc/server/netlogon/schannel_util.h | 54 ++ librpc/wscript_build | 12 + source4/rpc_server/netlogon/dcerpc_netlogon.c | 546 +---------------- source4/rpc_server/wscript_build | 2 +- 5 files changed, 644 insertions(+), 546 deletions(-) create mode 100644 librpc/rpc/server/netlogon/schannel_util.c create mode 100644 librpc/rpc/server/netlogon/schannel_util.h diff --git a/librpc/rpc/server/netlogon/schannel_util.c b/librpc/rpc/server/netlogon/schannel_util.c new file mode 100644 index 00000000000..9b2a88a2628 --- /dev/null +++ b/librpc/rpc/server/netlogon/schannel_util.c @@ -0,0 +1,576 @@ +/* + Unix SMB/CIFS implementation. + + netlogon schannel utility functions + + Copyright (C) Andrew Bartlett 2004-2008 + Copyright (C) Stefan Metzmacher 2005 + Copyright (C) Matthias Dieter Wallnöfer 2009-2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "schannel_util.h" +#include "param/param.h" +#include "libcli/security/dom_sid.h" +#include "libcli/auth/schannel.h" +#include "librpc/rpc/dcesrv_core.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "lib/util/util_str_escape.h" + +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 = ""; + const char *reason = ""; + + 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; +} + +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. + */ +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; +} diff --git a/librpc/rpc/server/netlogon/schannel_util.h b/librpc/rpc/server/netlogon/schannel_util.h new file mode 100644 index 00000000000..561e2567e02 --- /dev/null +++ b/librpc/rpc/server/netlogon/schannel_util.h @@ -0,0 +1,54 @@ +/* + Unix SMB/CIFS implementation. + + netlogon schannel utility functions + + Copyright (C) Andrew Bartlett 2004-2008 + Copyright (C) Stefan Metzmacher 2005 + Copyright (C) Matthias Dieter Wallnöfer 2009-2010 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__ +#define __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__ + +#include "replace.h" +#include +#include "libcli/util/ntstatus.h" + +#define NETLOGON_SERVER_PIPE_STATE_MAGIC 0x4f555358 + +struct dcesrv_call_state; +struct netlogon_creds_CredentialState; +struct netr_Authenticator; +enum dcerpc_AuthType; +enum dcerpc_AuthLevel; + +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); + +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); + +#endif /* __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__ */ diff --git a/librpc/wscript_build b/librpc/wscript_build index cf9085c0884..7913b7c7865 100644 --- a/librpc/wscript_build +++ b/librpc/wscript_build @@ -678,6 +678,18 @@ bld.SAMBA_LIBRARY('dcerpc-pkt-auth', ''', deps='dcerpc-binding gensec') +bld.SAMBA_SUBSYSTEM('DCERPC_SERVER_NETLOGON', + source=''' + rpc/server/netlogon/schannel_util.c + ''', + deps=''' + talloc + util_str_escape + samba-hostconfig + NDR_NETLOGON + dcerpc-server-core + ''') + bld.SAMBA_LIBRARY('dcerpc-server-core', source=''' rpc/dcesrv_core.c diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c index aa24a539abf..314b469a718 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" #include "lib/param/loadparm.h" @@ -889,551 +890,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 = ""; - const char *reason = ""; - - 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#. diff --git a/source4/rpc_server/wscript_build b/source4/rpc_server/wscript_build index e7bb773d719..0e44a3c2bae 100644 --- a/source4/rpc_server/wscript_build +++ b/source4/rpc_server/wscript_build @@ -118,10 +118,10 @@ bld.SAMBA_MODULE('dcerpc_netlogon', samba-hostconfig DSDB_MODULE_HELPERS util_str_escape + DCERPC_SERVER_NETLOGON ''' ) - bld.SAMBA_MODULE('dcerpc_lsarpc', source='lsa/dcesrv_lsa.c lsa/lsa_init.c lsa/lsa_lookup.c', autoproto='lsa/proto.h', -- 2.39.0 From 9d65354f54e269753dc30129191f500ff6c467bc Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 16:30:26 +0100 Subject: [PATCH 5/9] CVE-2022-38023 s3:rpc_server/netlogon: Use dcesrv_netr_creds_server_step_check() After s3 and s4 rpc servers merge we can avoid duplicated code. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 25300d354c80995997d552581cd91dddaf4bbf48) --- librpc/rpc/server/netlogon/schannel_util.c | 6 - selftest/target/Samba3.pm | 14 ++ source3/rpc_server/netlogon/srv_netlog_nt.c | 201 +++++--------------- source3/rpc_server/wscript_build | 2 +- 4 files changed, 58 insertions(+), 165 deletions(-) diff --git a/librpc/rpc/server/netlogon/schannel_util.c b/librpc/rpc/server/netlogon/schannel_util.c index 9b2a88a2628..b14497b13ce 100644 --- a/librpc/rpc/server/netlogon/schannel_util.c +++ b/librpc/rpc/server/netlogon/schannel_util.c @@ -529,12 +529,6 @@ NTSTATUS dcesrv_netr_check_schannel(struct dcesrv_call_state *dce_call, 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. - */ NTSTATUS dcesrv_netr_creds_server_step_check(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, const char *computer_name, diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index b985bf7a33c..c6253cf4476 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -289,6 +289,20 @@ sub setup_nt4_dc server require schannel:schannel11\$ = no server require schannel:torturetest\$ = no + server schannel require seal:schannel0\$ = no + server schannel require seal:schannel1\$ = no + server schannel require seal:schannel2\$ = no + server schannel require seal:schannel3\$ = no + server schannel require seal:schannel4\$ = no + server schannel require seal:schannel5\$ = no + server schannel require seal:schannel6\$ = no + server schannel require seal:schannel7\$ = no + server schannel require seal:schannel8\$ = no + server schannel require seal:schannel9\$ = no + server schannel require seal:schannel10\$ = no + server schannel require seal:schannel11\$ = no + server schannel require seal:torturetest\$ = no + vfs_default:VFS_OPEN_HOW_RESOLVE_NO_SYMLINKS = no fss: sequence timeout = 1 diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 5db3f7ad97d..f5038a9525a 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -51,6 +51,7 @@ #include "libsmb/dsgetdcname.h" #include "lib/util/util_str_escape.h" #include "source3/lib/substitute.h" +#include "librpc/rpc/server/netlogon/schannel_util.h" extern userdom_struct current_user_info; @@ -1061,129 +1062,6 @@ NTSTATUS _netr_ServerAuthenticate2(struct pipes_struct *p, return _netr_ServerAuthenticate3(p, &a); } -/************************************************************************* - *************************************************************************/ - -static NTSTATUS netr_creds_server_step_check(struct pipes_struct *p, - TALLOC_CTX *mem_ctx, - const char *computer_name, - struct netr_Authenticator *received_authenticator, - struct netr_Authenticator *return_authenticator, - struct netlogon_creds_CredentialState **creds_out) -{ - struct dcesrv_call_state *dce_call = p->dce_call; - NTSTATUS status; - bool schannel_global_required = (lp_server_schannel() == true) ? true:false; - bool schannel_required = schannel_global_required; - const char *explicit_opt = NULL; - struct loadparm_context *lp_ctx; - struct netlogon_creds_CredentialState *creds = NULL; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; - uint16_t opnum = dce_call->pkt.u.request.opnum; - const char *opname = ""; - - if (creds_out != NULL) { - *creds_out = NULL; - } - - if (opnum < ndr_table_netlogon.num_calls) { - opname = ndr_table_netlogon.calls[opnum].name; - } - - dcesrv_call_auth_info(dce_call, &auth_type, NULL); - - lp_ctx = loadparm_init_s3(mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - status = schannel_check_creds_state(mem_ctx, lp_ctx, - computer_name, received_authenticator, - return_authenticator, &creds); - talloc_unlink(mem_ctx, lp_ctx); - - if (!NT_STATUS_IS_OK(status)) { - ZERO_STRUCTP(return_authenticator); - return status; - } - - /* - * We don't use lp_parm_bool(), as we - * need the explicit_opt pointer in order to - * adjust the debug messages. - */ - - explicit_opt = lp_parm_const_string(GLOBAL_SECTION_SNUM, - "server require schannel", - creds->account_name, - NULL); - if (explicit_opt != NULL) { - schannel_required = lp_bool(explicit_opt); - } - - if (schannel_required) { - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - *creds_out = creds; - return NT_STATUS_OK; - } - - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' is needed! \n", - log_escape(mem_ctx, creds->account_name)); - TALLOC_FREE(creds); - ZERO_STRUCTP(return_authenticator); - return NT_STATUS_ACCESS_DENIED; - } - - if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) WITH schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' not needed!?\n", - log_escape(mem_ctx, creds->account_name)); - - *creds_out = creds; - return NT_STATUS_OK; - } - - if (explicit_opt != NULL) { - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); - DBG_INFO("CVE-2020-1472(ZeroLogon): " - "Option 'server require schannel:%s = no' still needed!\n", - log_escape(mem_ctx, creds->account_name)); - } else { - DBG_ERR("CVE-2020-1472(ZeroLogon): " - "%s request (opnum[%u]) without schannel from " - "client_account[%s] client_computer_name[%s]\n", - opname, opnum, - log_escape(mem_ctx, creds->account_name), - log_escape(mem_ctx, creds->computer_name)); - DBG_ERR("CVE-2020-1472(ZeroLogon): Check if option " - "'server require schannel:%s = no' might be needed!\n", - log_escape(mem_ctx, creds->account_name)); - } - - *creds_out = creds; - return NT_STATUS_OK; -} - - /************************************************************************* *************************************************************************/ @@ -1429,11 +1307,12 @@ NTSTATUS _netr_ServerPasswordSet(struct pipes_struct *p, DEBUG(5,("_netr_ServerPasswordSet: %d\n", __LINE__)); become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { @@ -1493,11 +1372,12 @@ NTSTATUS _netr_ServerPasswordSet2(struct pipes_struct *p, bool ok; become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { @@ -1644,11 +1524,12 @@ NTSTATUS _netr_LogonSamLogoff(struct pipes_struct *p, struct netlogon_creds_CredentialState *creds; become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); return status; @@ -2061,11 +1942,12 @@ NTSTATUS _netr_LogonSamLogonWithFlags(struct pipes_struct *p, } become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - &return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + &return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2411,11 +2293,12 @@ NTSTATUS _netr_LogonGetCapabilities(struct pipes_struct *p, NTSTATUS status; become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2775,11 +2658,12 @@ NTSTATUS _netr_GetForestTrustInformation(struct pipes_struct *p, /* TODO: check server name */ become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; @@ -2878,11 +2762,12 @@ NTSTATUS _netr_ServerGetTrustInfo(struct pipes_struct *p, /* TODO: check server name */ become_root(); - status = netr_creds_server_step_check(p, p->mem_ctx, - r->in.computer_name, - r->in.credential, - r->out.return_authenticator, - &creds); + status = dcesrv_netr_creds_server_step_check(p->dce_call, + p->mem_ctx, + r->in.computer_name, + r->in.credential, + r->out.return_authenticator, + &creds); unbecome_root(); if (!NT_STATUS_IS_OK(status)) { return status; diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build index 83ceca2a45c..341df41a321 100644 --- a/source3/rpc_server/wscript_build +++ b/source3/rpc_server/wscript_build @@ -174,7 +174,7 @@ bld.SAMBA3_SUBSYSTEM('RPC_NETDFS', bld.SAMBA3_SUBSYSTEM('RPC_NETLOGON', source='''netlogon/srv_netlog_nt.c''', - deps='LIBCLI_AUTH') + deps='LIBCLI_AUTH DCERPC_SERVER_NETLOGON') bld.SAMBA3_SUBSYSTEM('RPC_NTSVCS', source='''ntsvcs/srv_ntsvcs_nt.c''', -- 2.39.0 From 4d12f57899bdabc4f229cc01febaa462b0a38cfa Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 09:29:04 +0100 Subject: [PATCH 6/9] CVE-2022-38023 s3:rpc_server/netlogon: make sure all _netr_LogonSamLogon*() calls go through dcesrv_netr_check_schannel() Some checks are also required for _netr_LogonSamLogonEx(). BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit ca07f4340ce58a7e940a1123888b7409176412f7) --- source3/rpc_server/netlogon/srv_netlog_nt.c | 45 +++++++++++++-------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index f5038a9525a..304a42d9af9 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -1632,6 +1632,11 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, struct auth_serversupplied_info *server_info = NULL; struct auth_context *auth_context = NULL; const char *fn; + enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; + enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; + uint16_t opnum = dce_call->pkt.u.request.opnum; + + dcesrv_call_auth_info(dce_call, &auth_type, &auth_level); #ifdef DEBUG_PASSWORD logon = netlogon_creds_shallow_copy_logon(p->mem_ctx, @@ -1642,15 +1647,37 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, } #endif - switch (dce_call->pkt.u.request.opnum) { + switch (opnum) { case NDR_NETR_LOGONSAMLOGON: fn = "_netr_LogonSamLogon"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONWITHFLAGS: fn = "_netr_LogonSamLogonWithFlags"; + /* + * Already called netr_check_schannel() via + * netr_creds_server_step_check() + */ break; case NDR_NETR_LOGONSAMLOGONEX: fn = "_netr_LogonSamLogonEx"; + + if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { + return NT_STATUS_ACCESS_DENIED; + } + + status = dcesrv_netr_check_schannel(p->dce_call, + creds, + auth_type, + auth_level, + opnum); + if (NT_STATUS_IS_ERR(status)) { + return status; + } + break; default: return NT_STATUS_INTERNAL_ERROR; @@ -1881,10 +1908,6 @@ static NTSTATUS _netr_LogonSamLogon_base(struct pipes_struct *p, r->out.validation->sam3); break; case 6: { - enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE; - - dcesrv_call_auth_info(dce_call, NULL, &auth_level); - /* Only allow this if the pipe is protected. */ if (auth_level < DCERPC_AUTH_LEVEL_PRIVACY) { DEBUG(0,("netr_Validation6: client %s not using privacy for netlogon\n", @@ -1997,8 +2020,6 @@ NTSTATUS _netr_LogonSamLogon(struct pipes_struct *p, NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, struct netr_LogonSamLogonEx *r) { - struct dcesrv_call_state *dce_call = p->dce_call; - enum dcerpc_AuthType auth_type = DCERPC_AUTH_TYPE_NONE; NTSTATUS status; struct netlogon_creds_CredentialState *creds = NULL; struct loadparm_context *lp_ctx; @@ -2010,16 +2031,6 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, return status; } - /* Only allow this if the pipe is protected. */ - - dcesrv_call_auth_info(dce_call, &auth_type, NULL); - - if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) { - DEBUG(0,("_netr_LogonSamLogonEx: client %s not using schannel for netlogon\n", - get_remote_machine_name() )); - return NT_STATUS_INVALID_PARAMETER; - } - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); if (lp_ctx == NULL) { DEBUG(0, ("loadparm_init_s3 failed\n")); -- 2.39.0 From 5e5d3ded1834bb99c43f6f1d5229e5da6e45a8f0 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 11:05:33 +0100 Subject: [PATCH 7/9] CVE-2022-38023 s3:rpc_server/netlogon: Check for global "server schannel require seal" By default we'll now require schannel connections with privacy/sealing/encryption. But we allow exceptions for specific computer/trust accounts. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit a0b97e262318dc56fe663da89b0ee3172b2e7848) --- source3/rpc_server/netlogon/srv_netlog_nt.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 304a42d9af9..0ab391f8328 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -2895,7 +2895,9 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context struct loadparm_context *lp_ctx = context->conn->dce_ctx->lp_ctx; int schannel = lpcfg_server_schannel(lp_ctx); bool schannel_global_required = (schannel == true); + bool global_require_seal = lpcfg_server_schannel_require_seal(lp_ctx); static bool warned_global_schannel_once = false; + static bool warned_global_seal_once = false; if (!schannel_global_required && !warned_global_schannel_once) { /* @@ -2907,6 +2909,16 @@ static NTSTATUS dcesrv_interface_netlogon_bind(struct dcesrv_connection_context warned_global_schannel_once = true; } + if (!global_require_seal && !warned_global_seal_once) { + /* + * We want admins to notice their misconfiguration! + */ + D_ERR("CVE-2022-38023 (and others): " + "Please configure 'server schannel require seal = yes' (the default), " + "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n"); + warned_global_seal_once = true; + } + return NT_STATUS_OK; } -- 2.39.0 From 27189dc1f6cc32f376409d126b7c7a47c0339f78 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Mon, 9 Jan 2023 12:17:48 +0100 Subject: [PATCH 8/9] CVE-2022-38023 docs-xml/smbdotconf: The "server schannel require seal[:COMPUTERACCOUNT]" options are also honoured by s3 netlogon server. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider (cherry picked from commit 02fba22b8c9e9b33ab430555ef45500c45eaa9d1) --- docs-xml/smbdotconf/security/serverschannelrequireseal.xml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs-xml/smbdotconf/security/serverschannelrequireseal.xml b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml index d4620d1252d..0bec67d2519 100644 --- a/docs-xml/smbdotconf/security/serverschannelrequireseal.xml +++ b/docs-xml/smbdotconf/security/serverschannelrequireseal.xml @@ -12,9 +12,8 @@ - This option controls whether the netlogon server (currently - only in 'active directory domain controller' mode), will - reject the usage of netlogon secure channel without privacy/enryption. + This option controls whether the netlogon server, will reject the usage + of netlogon secure channel without privacy/enryption. -- 2.39.0 From f63d43b5873a778e82cdcc32890e7b92679ffb29 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Thu, 22 Dec 2022 16:32:40 +0100 Subject: [PATCH 9/9] CVE-2022-38023 s3:rpc_server/netlogon: Avoid unnecessary loadparm_context allocations After s3 and s4 rpc servers merge the loadparm_context is available in the dcesrv_context structure. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15240 Signed-off-by: Samuel Cabrero Reviewed-by: Andreas Schneider Autobuild-User(master): Andreas Schneider Autobuild-Date(master): Mon Jan 9 15:17:14 UTC 2023 on sn-devel-184 (cherry picked from commit 56837f3d3169a02d0d92bd085d9c8250415ce29b) --- source3/rpc_server/netlogon/srv_netlog_nt.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c index 0ab391f8328..83318fff753 100644 --- a/source3/rpc_server/netlogon/srv_netlog_nt.c +++ b/source3/rpc_server/netlogon/srv_netlog_nt.c @@ -880,7 +880,7 @@ NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p, * so use a copy to avoid destroying the client values. */ uint32_t in_neg_flags = *r->in.negotiate_flags; const char *fn; - struct loadparm_context *lp_ctx; + struct loadparm_context *lp_ctx = p->dce_call->conn->dce_ctx->lp_ctx; struct dom_sid sid; struct samr_Password mach_pwd; struct netlogon_creds_CredentialState *creds; @@ -1009,20 +1009,11 @@ NTSTATUS _netr_ServerAuthenticate3(struct pipes_struct *p, goto out; } - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(10, ("loadparm_init_s3 failed\n")); - status = NT_STATUS_INTERNAL_ERROR; - goto out; - } - /* Store off the state so we can continue after client disconnect. */ become_root(); status = schannel_save_creds_state(p->mem_ctx, lp_ctx, creds); unbecome_root(); - talloc_unlink(p->mem_ctx, lp_ctx); - if (!NT_STATUS_IS_OK(status)) { ZERO_STRUCTP(r->out.return_credentials); goto out; @@ -2022,7 +2013,7 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, { NTSTATUS status; struct netlogon_creds_CredentialState *creds = NULL; - struct loadparm_context *lp_ctx; + struct loadparm_context *lp_ctx = p->dce_call->conn->dce_ctx->lp_ctx; *r->out.authoritative = true; @@ -2031,18 +2022,10 @@ NTSTATUS _netr_LogonSamLogonEx(struct pipes_struct *p, return status; } - lp_ctx = loadparm_init_s3(p->mem_ctx, loadparm_s3_helpers()); - if (lp_ctx == NULL) { - DEBUG(0, ("loadparm_init_s3 failed\n")); - return NT_STATUS_INTERNAL_ERROR; - } - become_root(); status = schannel_get_creds_state(p->mem_ctx, lp_ctx, r->in.computer_name, &creds); unbecome_root(); - talloc_unlink(p->mem_ctx, lp_ctx); - if (!NT_STATUS_IS_OK(status)) { return status; } -- 2.39.0