From f7c26ead133ab9b67c6802a2303a22fd98e3c41a Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 5906464a9f3..a3853d482df 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 = "<unknown>";
- 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 1790cc254c10dfc0deb5ff84ff18a5f24bfd3f44 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 0b720a68927..b58f3d45118 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -271,9 +271,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
+
fss: sequence timeout = 1
check parent directory delete on close = yes
";
--
2.39.0
From 0e7e7ddbf5524b8aec595227a04cb09599c61a81 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@samba.org>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 740422fb6609dac3b0e2c1bb91d61b87e99c64aa Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 <abartlet@samba.org> 2004-2008
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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 = "<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;
+}
+
+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 <abartlet@samba.org> 2004-2008
+ Copyright (C) Stefan Metzmacher <metze@samba.org> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__
+#define __LIBRPC_RPC_SERVER_NETLOGON_SCHANNEL_UTIL_H__
+
+#include "replace.h"
+#include <talloc.h>
+#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 b82209b4299..f22ab2eabae 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 ddcb8487a56..6a3e044eb9d 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 = "<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#.
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 1a1f5c53c217b5336464885a70e7eef94dd0ad5f Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 b58f3d45118..75256db675c 100755
--- a/selftest/target/Samba3.pm
+++ b/selftest/target/Samba3.pm
@@ -288,6 +288,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
+
fss: sequence timeout = 1
check parent directory delete on close = yes
";
diff --git a/source3/rpc_server/netlogon/srv_netlog_nt.c b/source3/rpc_server/netlogon/srv_netlog_nt.c
index a3853d482df..8e0ea522b6d 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 = "<unknown>";
-
- 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 5e8a9c85fe9cd28727c284a7fa5465db00a16cac Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 8e0ea522b6d..ba2680668ed 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 f4682b16e9e5bdc4decf6c9d02388d540482b6a7 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 ba2680668ed..a6f56a5ca21 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 5ddca0370de470bf1c532a6883e0b9fa0dedf6c4 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@samba.org>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
(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 @@
</para>
<para>
- 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.
</para>
<para>
--
2.39.0
From 2cb3ecb5c258fd23ca2f1fd2635be90336a0d7e0 Mon Sep 17 00:00:00 2001
From: Samuel Cabrero <scabrero@suse.de>
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 <scabrero@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Autobuild-User(master): Andreas Schneider <asn@cryptomilk.org>
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 a6f56a5ca21..7d17ab79f3d 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