2 Unix SMB/CIFS implementation.
4 netlogon schannel utility functions
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2008
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
8 Copyright (C) Matthias Dieter Wallnöfer 2009-2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "auth/auth.h"
26 #include "schannel_util.h"
27 #include "param/param.h"
28 #include "libcli/security/dom_sid.h"
29 #include "libcli/auth/schannel.h"
30 #include "librpc/rpc/dcesrv_core.h"
31 #include "librpc/gen_ndr/ndr_netlogon.h"
32 #include "lib/util/util_str_escape.h"
34 struct dcesrv_netr_check_schannel_state
{
35 struct dom_sid account_sid
;
36 enum dcerpc_AuthType auth_type
;
37 enum dcerpc_AuthLevel auth_level
;
39 bool kerberos_required
;
41 bool schannel_global_required
;
42 bool schannel_required
;
43 bool schannel_explicitly_set
;
45 bool seal_global_required
;
47 bool seal_explicitly_set
;
52 static NTSTATUS
dcesrv_netr_check_schannel_get_state(struct dcesrv_call_state
*dce_call
,
53 const struct netlogon_creds_CredentialState
*creds
,
54 enum dcerpc_AuthType auth_type
,
55 enum dcerpc_AuthLevel auth_level
,
56 struct dcesrv_netr_check_schannel_state
**_s
)
58 struct loadparm_context
*lp_ctx
= dce_call
->conn
->dce_ctx
->lp_ctx
;
59 int schannel
= lpcfg_server_schannel(lp_ctx
);
60 bool schannel_global_required
= (schannel
== true);
61 bool schannel_required
= schannel_global_required
;
62 const char *explicit_opt
= NULL
;
63 bool global_require_seal
= lpcfg_server_schannel_require_seal(lp_ctx
);
64 bool require_seal
= global_require_seal
;
65 const char *explicit_seal_opt
= NULL
;
66 #define DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC (NETLOGON_SERVER_PIPE_STATE_MAGIC+1)
67 struct dcesrv_netr_check_schannel_state
*s
= NULL
;
72 if (creds
->authenticate_kerberos
) {
73 struct auth_session_info
*session_info
=
74 dcesrv_call_session_info(dce_call
);
75 const struct dom_sid
*auth_sid
=
76 &session_info
->security_token
->sids
[0];
78 if (auth_type
!= DCERPC_AUTH_TYPE_KRB5
) {
79 return NT_STATUS_ACCESS_DENIED
;
82 if (auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
83 return NT_STATUS_ACCESS_DENIED
;
86 if (!dom_sid_equal(auth_sid
, &creds
->client_sid
)) {
87 return NT_STATUS_ACCESS_DENIED
;
91 s
= dcesrv_iface_state_find_conn(dce_call
,
92 DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC
,
93 struct dcesrv_netr_check_schannel_state
);
95 if (!dom_sid_equal(&s
->account_sid
, &creds
->client_sid
)) {
98 if (s
->auth_type
!= auth_type
) {
101 if (s
->auth_level
!= auth_level
) {
111 s
= talloc_zero(dce_call
,
112 struct dcesrv_netr_check_schannel_state
);
114 return NT_STATUS_NO_MEMORY
;
117 s
->account_sid
= creds
->client_sid
;
118 s
->auth_type
= auth_type
;
119 s
->auth_level
= auth_level
;
120 s
->result
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
123 * We don't use lpcfg_parm_bool(), as we
124 * need the explicit_opt pointer in order to
125 * adjust the debug messages.
127 explicit_seal_opt
= lpcfg_get_parametric(lp_ctx
,
129 "server schannel require seal",
130 creds
->account_name
);
131 if (explicit_seal_opt
!= NULL
) {
132 require_seal
= lp_bool(explicit_seal_opt
);
136 * We don't use lpcfg_parm_bool(), as we
137 * need the explicit_opt pointer in order to
138 * adjust the debug messages.
140 explicit_opt
= lpcfg_get_parametric(lp_ctx
,
142 "server require schannel",
143 creds
->account_name
);
144 if (explicit_opt
!= NULL
) {
145 schannel_required
= lp_bool(explicit_opt
);
148 s
->schannel_global_required
= schannel_global_required
;
149 s
->schannel_required
= schannel_required
;
150 s
->schannel_explicitly_set
= explicit_opt
!= NULL
;
152 s
->seal_global_required
= global_require_seal
;
153 s
->seal_required
= require_seal
;
154 s
->seal_explicitly_set
= explicit_seal_opt
!= NULL
;
156 if (creds
->authenticate_kerberos
) {
157 s
->kerberos_required
= true;
158 s
->seal_required
= true;
161 status
= dcesrv_iface_state_store_conn(dce_call
,
162 DCESRV_NETR_CHECK_SCHANNEL_STATE_MAGIC
,
164 if (!NT_STATUS_IS_OK(status
)) {
172 static NTSTATUS
dcesrv_netr_check_schannel_once(struct dcesrv_call_state
*dce_call
,
173 struct dcesrv_netr_check_schannel_state
*s
,
174 const struct netlogon_creds_CredentialState
*creds
,
177 struct loadparm_context
*lp_ctx
= dce_call
->conn
->dce_ctx
->lp_ctx
;
178 int CVE_2020_1472_warn_level
= lpcfg_parm_int(lp_ctx
, NULL
,
179 "CVE_2020_1472", "warn_about_unused_debug_level", DBGLVL_ERR
);
180 int CVE_2020_1472_error_level
= lpcfg_parm_int(lp_ctx
, NULL
,
181 "CVE_2020_1472", "error_debug_level", DBGLVL_ERR
);
182 int CVE_2022_38023_warn_level
= lpcfg_parm_int(lp_ctx
, NULL
,
183 "CVE_2022_38023", "warn_about_unused_debug_level", DBGLVL_ERR
);
184 int CVE_2022_38023_error_level
= lpcfg_parm_int(lp_ctx
, NULL
,
185 "CVE_2022_38023", "error_debug_level", DBGLVL_ERR
);
186 TALLOC_CTX
*frame
= talloc_stackframe();
187 unsigned int dbg_lvl
= DBGLVL_DEBUG
;
188 const char *opname
= "<unknown>";
189 const char *reason
= "<unknown>";
191 if (opnum
< ndr_table_netlogon
.num_calls
) {
192 opname
= ndr_table_netlogon
.calls
[opnum
].name
;
195 if (s
->auth_type
== DCERPC_AUTH_TYPE_KRB5
) {
196 if (s
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
197 reason
= "KRB5 WITH SEALED";
198 } else if (s
->auth_level
== DCERPC_AUTH_LEVEL_INTEGRITY
) {
199 reason
= "KRB5 ONLY WITH SIGNED";
200 dbg_lvl
= DBGLVL_ERR
;
201 s
->result
= NT_STATUS_ACCESS_DENIED
;
203 reason
= "KRB5 WITH INVALID";
204 dbg_lvl
= DBGLVL_ERR
;
205 s
->result
= NT_STATUS_ACCESS_DENIED
;
207 } else if (s
->kerberos_required
) {
208 s
->result
= NT_STATUS_ACCESS_DENIED
;
209 reason
= "WITHOUT KRB5";
210 } else if (s
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
211 if (s
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
) {
212 reason
= "WITH SEALED";
213 } else if (s
->auth_level
== DCERPC_AUTH_LEVEL_INTEGRITY
) {
214 reason
= "WITH SIGNED";
216 reason
= "WITH INVALID";
217 dbg_lvl
= DBGLVL_ERR
;
218 s
->result
= NT_STATUS_INTERNAL_ERROR
;
224 if (!NT_STATUS_EQUAL(s
->result
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
225 if (!NT_STATUS_IS_OK(s
->result
)) {
226 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
230 "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
231 "%s request (opnum[%u]) %s schannel from "
232 "client_account[%s] client_computer_name[%s] %s\n",
233 opname
, opnum
, reason
,
234 log_escape(frame
, creds
->account_name
),
235 log_escape(frame
, creds
->computer_name
),
236 nt_errstr(s
->result
)));
241 if (s
->auth_type
== DCERPC_AUTH_TYPE_KRB5
&&
242 s
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
)
244 s
->result
= NT_STATUS_OK
;
249 if (s
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
&&
250 s
->auth_level
== DCERPC_AUTH_LEVEL_PRIVACY
)
252 s
->result
= NT_STATUS_OK
;
254 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
255 dbg_lvl
= MIN(dbg_lvl
, CVE_2020_1472_warn_level
);
256 } else if (!s
->schannel_required
) {
257 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
259 if (s
->seal_explicitly_set
&& !s
->seal_required
) {
260 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_warn_level
);
261 } else if (!s
->seal_required
) {
262 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
266 "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
267 "%s request (opnum[%u]) %s schannel from "
268 "client_account[%s] client_computer_name[%s] %s\n",
269 opname
, opnum
, reason
,
270 log_escape(frame
, creds
->account_name
),
271 log_escape(frame
, creds
->computer_name
),
272 nt_errstr(s
->result
)));
274 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
275 DEBUG(CVE_2020_1472_warn_level
, (
276 "CVE-2020-1472(ZeroLogon): "
277 "Option 'server require schannel:%s = no' not needed for '%s'!\n",
278 log_escape(frame
, creds
->account_name
),
279 log_escape(frame
, creds
->computer_name
)));
282 if (s
->seal_explicitly_set
&& !s
->seal_required
) {
283 DEBUG(CVE_2022_38023_warn_level
, (
285 "Option 'server schannel require seal:%s = no' not needed for '%s'!\n",
286 log_escape(frame
, creds
->account_name
),
287 log_escape(frame
, creds
->computer_name
)));
294 if (s
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
295 if (s
->seal_required
) {
296 s
->result
= NT_STATUS_ACCESS_DENIED
;
298 if (s
->seal_explicitly_set
) {
299 dbg_lvl
= DBGLVL_NOTICE
;
301 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_error_level
);
303 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
304 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_warn_level
);
309 "%s request (opnum[%u]) %s schannel from "
310 "from client_account[%s] client_computer_name[%s] %s\n",
311 opname
, opnum
, reason
,
312 log_escape(frame
, creds
->account_name
),
313 log_escape(frame
, creds
->computer_name
),
314 nt_errstr(s
->result
)));
315 if (s
->seal_explicitly_set
) {
316 D_NOTICE("CVE-2022-38023: Option "
317 "'server schannel require seal:%s = yes' "
318 "rejects access for client.\n",
319 log_escape(frame
, creds
->account_name
));
321 DEBUG(CVE_2020_1472_error_level
, (
322 "CVE-2022-38023: Check if option "
323 "'server schannel require seal:%s = no' "
324 "might be needed for a legacy client.\n",
325 log_escape(frame
, creds
->account_name
)));
327 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
328 DEBUG(CVE_2020_1472_warn_level
, (
329 "CVE-2020-1472(ZeroLogon): Option "
330 "'server require schannel:%s = no' "
331 "not needed for '%s'!\n",
332 log_escape(frame
, creds
->account_name
),
333 log_escape(frame
, creds
->computer_name
)));
339 s
->result
= NT_STATUS_OK
;
341 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
342 dbg_lvl
= MIN(dbg_lvl
, CVE_2020_1472_warn_level
);
343 } else if (!s
->schannel_required
) {
344 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
346 if (s
->seal_explicitly_set
&& !s
->seal_required
) {
347 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
348 } else if (!s
->seal_required
) {
349 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_error_level
);
353 "CVE-2020-1472(ZeroLogon): "
354 "%s request (opnum[%u]) %s schannel from "
355 "client_account[%s] client_computer_name[%s] %s\n",
356 opname
, opnum
, reason
,
357 log_escape(frame
, creds
->account_name
),
358 log_escape(frame
, creds
->computer_name
),
359 nt_errstr(s
->result
)));
360 if (s
->schannel_explicitly_set
&& !s
->schannel_required
) {
361 DEBUG(CVE_2020_1472_warn_level
, (
362 "CVE-2020-1472(ZeroLogon): "
363 "Option 'server require schannel:%s = no' not needed for '%s'!\n",
364 log_escape(frame
, creds
->account_name
),
365 log_escape(frame
, creds
->computer_name
)));
367 if (s
->seal_explicitly_set
&& !s
->seal_required
) {
368 D_INFO("CVE-2022-38023: "
369 "Option 'server schannel require seal:%s = no' still needed for '%s'!\n",
370 log_escape(frame
, creds
->account_name
),
371 log_escape(frame
, creds
->computer_name
));
372 } else if (!s
->seal_required
) {
375 * server schannel require seal:COMPUTER$ = no
376 * in order to avoid the level 0 messages.
377 * Over time they can switch the global value
380 DEBUG(CVE_2022_38023_error_level
, (
382 "Please use 'server schannel require seal:%s = no' "
383 "for '%s' to avoid this warning!\n",
384 log_escape(frame
, creds
->account_name
),
385 log_escape(frame
, creds
->computer_name
)));
392 if (s
->seal_required
) {
393 s
->result
= NT_STATUS_ACCESS_DENIED
;
395 if (s
->seal_explicitly_set
) {
396 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_NOTICE
);
398 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_error_level
);
400 if (!s
->schannel_explicitly_set
) {
401 dbg_lvl
= MIN(dbg_lvl
, CVE_2020_1472_error_level
);
402 } else if (s
->schannel_required
) {
403 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_NOTICE
);
407 "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
408 "%s request (opnum[%u]) %s schannel from "
409 "from client_account[%s] client_computer_name[%s] %s\n",
410 opname
, opnum
, reason
,
411 log_escape(frame
, creds
->account_name
),
412 log_escape(frame
, creds
->computer_name
),
413 nt_errstr(s
->result
)));
414 if (s
->seal_explicitly_set
) {
415 D_NOTICE("CVE-2022-38023: Option "
416 "'server schannel require seal:%s = yes' "
417 "rejects access for client.\n",
418 log_escape(frame
, creds
->account_name
));
420 DEBUG(CVE_2022_38023_error_level
, (
421 "CVE-2022-38023: Check if option "
422 "'server schannel require seal:%s = no' "
423 "might be needed for a legacy client.\n",
424 log_escape(frame
, creds
->account_name
)));
426 if (!s
->schannel_explicitly_set
) {
427 DEBUG(CVE_2020_1472_error_level
, (
428 "CVE-2020-1472(ZeroLogon): Check if option "
429 "'server require schannel:%s = no' "
430 "might be needed for a legacy client.\n",
431 log_escape(frame
, creds
->account_name
)));
432 } else if (s
->schannel_required
) {
433 D_NOTICE("CVE-2022-38023: Option "
434 "'server require schannel:%s = yes' "
435 "also rejects access for client.\n",
436 log_escape(frame
, creds
->account_name
));
442 if (s
->schannel_required
) {
443 s
->result
= NT_STATUS_ACCESS_DENIED
;
445 if (s
->schannel_explicitly_set
) {
446 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_NOTICE
);
448 dbg_lvl
= MIN(dbg_lvl
, CVE_2020_1472_error_level
);
450 if (!s
->seal_explicitly_set
) {
451 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_error_level
);
455 "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
456 "%s request (opnum[%u]) %s schannel from "
457 "client_account[%s] client_computer_name[%s] %s\n",
458 opname
, opnum
, reason
,
459 log_escape(frame
, creds
->account_name
),
460 log_escape(frame
, creds
->computer_name
),
461 nt_errstr(s
->result
)));
462 if (s
->schannel_explicitly_set
) {
463 D_NOTICE("CVE-2020-1472(ZeroLogon): Option "
464 "'server require schannel:%s = yes' "
465 "rejects access for client.\n",
466 log_escape(frame
, creds
->account_name
));
468 DEBUG(CVE_2020_1472_error_level
, (
469 "CVE-2020-1472(ZeroLogon): Check if option "
470 "'server require schannel:%s = no' "
471 "might be needed for a legacy client.\n",
472 log_escape(frame
, creds
->account_name
)));
474 if (!s
->seal_explicitly_set
) {
475 DEBUG(CVE_2022_38023_error_level
, (
476 "CVE-2022-38023: Check if option "
477 "'server schannel require seal:%s = no' "
478 "might be needed for a legacy client.\n",
479 log_escape(frame
, creds
->account_name
)));
485 s
->result
= NT_STATUS_OK
;
487 if (s
->seal_explicitly_set
) {
488 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
490 dbg_lvl
= MIN(dbg_lvl
, CVE_2022_38023_error_level
);
493 if (s
->schannel_explicitly_set
) {
494 dbg_lvl
= MIN(dbg_lvl
, DBGLVL_INFO
);
496 dbg_lvl
= MIN(dbg_lvl
, CVE_2020_1472_error_level
);
500 "CVE-2020-1472(ZeroLogon)/CVE-2022-38023: "
501 "%s request (opnum[%u]) %s schannel from "
502 "client_account[%s] client_computer_name[%s] %s\n",
503 opname
, opnum
, reason
,
504 log_escape(frame
, creds
->account_name
),
505 log_escape(frame
, creds
->computer_name
),
506 nt_errstr(s
->result
)));
508 if (s
->seal_explicitly_set
) {
509 D_INFO("CVE-2022-38023: Option "
510 "'server schannel require seal:%s = no' "
511 "still needed for '%s'!\n",
512 log_escape(frame
, creds
->account_name
),
513 log_escape(frame
, creds
->computer_name
));
517 * server schannel require seal:COMPUTER$ = no
518 * in order to avoid the level 0 messages.
519 * Over time they can switch the global value
522 DEBUG(CVE_2022_38023_error_level
, (
523 "CVE-2022-38023: Please use "
524 "'server schannel require seal:%s = no' "
525 "for '%s' to avoid this warning!\n",
526 log_escape(frame
, creds
->account_name
),
527 log_escape(frame
, creds
->computer_name
)));
530 if (s
->schannel_explicitly_set
) {
531 D_INFO("CVE-2020-1472(ZeroLogon): Option "
532 "'server require schannel:%s = no' "
533 "still needed for '%s'!\n",
534 log_escape(frame
, creds
->account_name
),
535 log_escape(frame
, creds
->computer_name
));
539 * server require schannel:COMPUTER$ = no
540 * in order to avoid the level 0 messages.
541 * Over time they can switch the global value
544 DEBUG(CVE_2020_1472_error_level
, (
545 "CVE-2020-1472(ZeroLogon): "
546 "Please use 'server require schannel:%s = no' "
547 "for '%s' to avoid this warning!\n",
548 log_escape(frame
, creds
->account_name
),
549 log_escape(frame
, creds
->computer_name
)));
556 NTSTATUS
dcesrv_netr_check_schannel(struct dcesrv_call_state
*dce_call
,
557 const struct netlogon_creds_CredentialState
*creds
,
558 enum dcerpc_AuthType auth_type
,
559 enum dcerpc_AuthLevel auth_level
,
562 struct dcesrv_netr_check_schannel_state
*s
= NULL
;
565 status
= dcesrv_netr_check_schannel_get_state(dce_call
,
570 if (!NT_STATUS_IS_OK(status
)) {
574 status
= dcesrv_netr_check_schannel_once(dce_call
, s
, creds
, opnum
);
575 if (!NT_STATUS_IS_OK(status
)) {
582 struct dcesrv_netr_step_access_state
{
583 struct dcesrv_call_state
*dce_call
;
584 enum dcerpc_AuthType auth_type
;
585 enum dcerpc_AuthLevel auth_level
;
590 static NTSTATUS
dcesrv_netr_step_access_cb(
591 struct netlogon_creds_CredentialState
*creds
,
592 NTSTATUS step_status
,
594 void *access_check_private
)
596 struct dcesrv_netr_step_access_state
*s
=
597 (struct dcesrv_netr_step_access_state
*)access_check_private
;
598 struct dcesrv_call_state
*dce_call
=
599 talloc_get_type_abort(s
->dce_call
,
600 struct dcesrv_call_state
);
602 if (NT_STATUS_EQUAL(step_status
, NT_STATUS_ACCESS_DENIED
)) {
603 s
->status
= step_status
;
608 if (!NT_STATUS_IS_OK(step_status
)) {
613 s
->status
= dcesrv_netr_check_schannel(dce_call
,
619 if (!NT_STATUS_IS_OK(s
->status
)) {
628 NTSTATUS
dcesrv_netr_creds_server_step_check(struct dcesrv_call_state
*dce_call
,
630 const char *computer_name
,
631 struct netr_Authenticator
*received_authenticator
,
632 struct netr_Authenticator
*return_authenticator
,
633 struct netlogon_creds_CredentialState
**creds_out
)
636 struct netlogon_creds_CredentialState
*creds
= NULL
;
637 struct dcesrv_netr_step_access_state state
= {
638 .dce_call
= dce_call
,
639 .auth_type
= DCERPC_AUTH_TYPE_NONE
,
640 .auth_level
= DCERPC_AUTH_LEVEL_NONE
,
641 .opnum
= dce_call
->pkt
.u
.request
.opnum
,
642 .status
= NT_STATUS_INTERNAL_ERROR
,
645 dcesrv_call_auth_info(dce_call
, &state
.auth_type
, &state
.auth_level
);
647 nt_status
= schannel_check_creds_state(mem_ctx
,
648 dce_call
->conn
->dce_ctx
->lp_ctx
,
650 received_authenticator
,
651 return_authenticator
,
654 dcesrv_netr_step_access_cb
,
657 if (!NT_STATUS_IS_OK(nt_status
)) {
658 ZERO_STRUCTP(return_authenticator
);
662 nt_status
= state
.status
;
663 if (!NT_STATUS_IS_OK(nt_status
)) {
665 ZERO_STRUCTP(return_authenticator
);