mirror of
https://github.com/samba-team/samba.git
synced 2025-01-22 22:04:08 +03:00
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)
This commit is contained in:
parent
538dcc38fa
commit
0d27e4b459
576
librpc/rpc/server/netlogon/schannel_util.c
Normal file
576
librpc/rpc/server/netlogon/schannel_util.c
Normal file
@ -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;
|
||||
}
|
54
librpc/rpc/server/netlogon/schannel_util.h
Normal file
54
librpc/rpc/server/netlogon/schannel_util.h
Normal file
@ -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__ */
|
@ -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
|
||||
|
@ -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#.
|
||||
|
@ -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',
|
||||
|
Loading…
x
Reference in New Issue
Block a user