2 Unix SMB/CIFS implementation.
4 module to store/fetch session keys for the schannel client
6 Copyright (C) Stefan Metzmacher 2013
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "system/filesys.h"
25 #include "lib/util/tevent_ntstatus.h"
26 #include "lib/dbwrap/dbwrap.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "lib/util/util_tdb.h"
29 #include "libcli/security/security.h"
30 #include "../lib/param/param.h"
31 #include "../libcli/auth/schannel.h"
32 #include "../librpc/gen_ndr/ndr_schannel.h"
33 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
34 #include "../librpc/gen_ndr/ndr_netlogon.h"
35 #include "../librpc/gen_ndr/server_id.h"
36 #include "netlogon_creds_cli.h"
37 #include "source3/include/messages.h"
38 #include "source3/include/g_lock.h"
39 #include "libds/common/roles.h"
40 #include "lib/crypto/md4.h"
41 #include "auth/credentials/credentials.h"
42 #include "lib/param/loadparm.h"
44 struct netlogon_creds_cli_locked_state
;
46 struct netlogon_creds_cli_context
{
50 uint32_t proposed_flags
;
51 uint32_t required_flags
;
52 enum netr_SchannelType type
;
53 enum dcerpc_AuthLevel auth_level
;
58 const char *netbios_domain
;
59 const char *dns_domain
;
60 uint32_t cached_flags
;
69 struct db_context
*ctx
;
70 struct g_lock_ctx
*g_ctx
;
71 struct netlogon_creds_cli_locked_state
*locked_state
;
72 enum netlogon_creds_cli_lck_type lock
;
76 struct netlogon_creds_cli_locked_state
{
77 struct netlogon_creds_cli_context
*context
;
79 struct netlogon_creds_CredentialState
*creds
;
82 static int netlogon_creds_cli_locked_state_destructor(
83 struct netlogon_creds_cli_locked_state
*state
)
85 struct netlogon_creds_cli_context
*context
= state
->context
;
87 if (context
== NULL
) {
91 if (context
->db
.locked_state
== state
) {
92 context
->db
.locked_state
= NULL
;
95 if (state
->is_glocked
) {
96 g_lock_unlock(context
->db
.g_ctx
,
97 string_term_tdb_data(context
->db
.key_name
));
103 static NTSTATUS
netlogon_creds_cli_context_common(
104 const char *client_computer
,
105 const char *client_account
,
106 enum netr_SchannelType type
,
107 enum dcerpc_AuthLevel auth_level
,
108 uint32_t proposed_flags
,
109 uint32_t required_flags
,
110 const char *server_computer
,
111 const char *server_netbios_domain
,
112 const char *server_dns_domain
,
114 struct netlogon_creds_cli_context
**_context
)
116 struct netlogon_creds_cli_context
*context
= NULL
;
117 char *_key_name
= NULL
;
118 size_t server_netbios_name_len
;
123 context
= talloc_zero(mem_ctx
, struct netlogon_creds_cli_context
);
124 if (context
== NULL
) {
125 return NT_STATUS_NO_MEMORY
;
128 context
->client
.computer
= talloc_strdup(context
, client_computer
);
129 if (context
->client
.computer
== NULL
) {
130 TALLOC_FREE(context
);
131 return NT_STATUS_NO_MEMORY
;
134 context
->client
.account
= talloc_strdup(context
, client_account
);
135 if (context
->client
.account
== NULL
) {
136 TALLOC_FREE(context
);
137 return NT_STATUS_NO_MEMORY
;
140 context
->client
.proposed_flags
= proposed_flags
;
141 context
->client
.required_flags
= required_flags
;
142 context
->client
.type
= type
;
143 context
->client
.auth_level
= auth_level
;
145 context
->server
.computer
= talloc_strdup(context
, server_computer
);
146 if (context
->server
.computer
== NULL
) {
147 TALLOC_FREE(context
);
148 return NT_STATUS_NO_MEMORY
;
151 context
->server
.netbios_domain
= talloc_strdup(context
, server_netbios_domain
);
152 if (context
->server
.netbios_domain
== NULL
) {
153 TALLOC_FREE(context
);
154 return NT_STATUS_NO_MEMORY
;
157 context
->server
.dns_domain
= talloc_strdup(context
, server_dns_domain
);
158 if (context
->server
.dns_domain
== NULL
) {
159 TALLOC_FREE(context
);
160 return NT_STATUS_NO_MEMORY
;
165 * Force the callers to provide a unique
166 * value for server_computer and use this directly.
168 * For now we have to deal with
169 * "HOSTNAME" vs. "hostname.example.com".
172 p
= strchr(server_computer
, '.');
174 server_netbios_name_len
= p
-server_computer
;
176 server_netbios_name_len
= strlen(server_computer
);
179 _key_name
= talloc_asprintf(context
, "CLI[%s/%s]/SRV[%.*s/%s]",
182 (int)server_netbios_name_len
,
184 server_netbios_domain
);
185 if (_key_name
== NULL
) {
186 TALLOC_FREE(context
);
187 return NT_STATUS_NO_MEMORY
;
190 context
->db
.key_name
= talloc_strdup_upper(context
, _key_name
);
191 TALLOC_FREE(_key_name
);
192 if (context
->db
.key_name
== NULL
) {
193 TALLOC_FREE(context
);
194 return NT_STATUS_NO_MEMORY
;
197 context
->db
.key_data
= string_term_tdb_data(context
->db
.key_name
);
203 static struct db_context
*netlogon_creds_cli_global_db
;
205 NTSTATUS
netlogon_creds_cli_set_global_db(struct loadparm_context
*lp_ctx
,
206 struct db_context
**db
)
208 netlogon_creds_cli_warn_options(lp_ctx
);
210 if (netlogon_creds_cli_global_db
!= NULL
) {
211 return NT_STATUS_INVALID_PARAMETER_MIX
;
214 netlogon_creds_cli_global_db
= talloc_move(NULL
, db
);
218 NTSTATUS
netlogon_creds_cli_open_global_db(struct loadparm_context
*lp_ctx
)
221 struct db_context
*global_db
;
222 int hash_size
, tdb_flags
;
224 netlogon_creds_cli_warn_options(lp_ctx
);
226 if (netlogon_creds_cli_global_db
!= NULL
) {
230 fname
= lpcfg_private_db_path(NULL
, lp_ctx
, "netlogon_creds_cli");
232 return NT_STATUS_NO_MEMORY
;
235 hash_size
= lpcfg_tdb_hash_size(lp_ctx
, fname
);
236 tdb_flags
= lpcfg_tdb_flags(
238 TDB_CLEAR_IF_FIRST
|TDB_INCOMPATIBLE_HASH
);
240 global_db
= dbwrap_local_open(
249 if (global_db
== NULL
) {
250 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
251 fname
, strerror(errno
)));
253 return NT_STATUS_NO_MEMORY
;
257 netlogon_creds_cli_global_db
= global_db
;
261 void netlogon_creds_cli_close_global_db(void)
263 TALLOC_FREE(netlogon_creds_cli_global_db
);
266 void netlogon_creds_cli_warn_options(struct loadparm_context
*lp_ctx
)
268 bool global_reject_md5_servers
= lpcfg_reject_md5_servers(lp_ctx
);
269 bool global_require_strong_key
= lpcfg_require_strong_key(lp_ctx
);
270 int global_client_schannel
= lpcfg_client_schannel(lp_ctx
);
271 bool global_seal_secure_channel
= lpcfg_winbind_sealed_pipes(lp_ctx
);
272 int global_kerberos_enctypes
= lpcfg_kerberos_encryption_types(lp_ctx
);
273 static bool warned_global_reject_md5_servers
= false;
274 static bool warned_global_require_strong_key
= false;
275 static bool warned_global_client_schannel
= false;
276 static bool warned_global_seal_secure_channel
= false;
277 static bool warned_global_kerberos_encryption_types
= false;
278 static int warned_global_pid
= 0;
279 int current_pid
= tevent_cached_getpid();
281 if (warned_global_pid
!= current_pid
) {
282 warned_global_reject_md5_servers
= false;
283 warned_global_require_strong_key
= false;
284 warned_global_client_schannel
= false;
285 warned_global_seal_secure_channel
= false;
286 warned_global_kerberos_encryption_types
= false;
287 warned_global_pid
= current_pid
;
290 if (!global_reject_md5_servers
&& !warned_global_reject_md5_servers
) {
292 * We want admins to notice their misconfiguration!
294 DBG_ERR("CVE-2022-38023 (and others): "
295 "Please configure 'reject md5 servers = yes' (the default), "
296 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
297 warned_global_reject_md5_servers
= true;
300 if (!global_require_strong_key
&& !warned_global_require_strong_key
) {
302 * We want admins to notice their misconfiguration!
304 DBG_ERR("CVE-2022-38023 (and others): "
305 "Please configure 'require strong key = yes' (the default), "
306 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
307 warned_global_require_strong_key
= true;
310 if (global_client_schannel
!= true && !warned_global_client_schannel
) {
312 * We want admins to notice their misconfiguration!
314 DBG_ERR("CVE-2022-38023 (and others): "
315 "Please configure 'client schannel = yes' (the default), "
316 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
317 warned_global_client_schannel
= true;
320 if (!global_seal_secure_channel
&& !warned_global_seal_secure_channel
) {
322 * We want admins to notice their misconfiguration!
324 DBG_ERR("CVE-2022-38023 (and others): "
325 "Please configure 'winbind sealed pipes = yes' (the default), "
326 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
327 warned_global_seal_secure_channel
= true;
330 if (global_kerberos_enctypes
== KERBEROS_ETYPES_LEGACY
&&
331 !warned_global_kerberos_encryption_types
)
334 * We want admins to notice their misconfiguration!
336 DBG_ERR("CVE-2022-37966: "
337 "Please void 'kerberos encryption types = legacy', "
338 "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
339 warned_global_kerberos_encryption_types
= true;
343 NTSTATUS
netlogon_creds_cli_context_global(struct loadparm_context
*lp_ctx
,
344 struct messaging_context
*msg_ctx
,
345 const char *client_account
,
346 enum netr_SchannelType type
,
347 const char *server_computer
,
348 const char *server_netbios_domain
,
349 const char *server_dns_domain
,
351 struct netlogon_creds_cli_context
**_context
)
353 TALLOC_CTX
*frame
= talloc_stackframe();
355 struct netlogon_creds_cli_context
*context
= NULL
;
356 const char *client_computer
;
357 uint32_t proposed_flags
;
358 uint32_t required_flags
= 0;
359 bool reject_md5_servers
= true;
360 bool require_strong_key
= true;
361 int require_sign_or_seal
= true;
362 bool seal_secure_channel
= true;
363 enum dcerpc_AuthLevel auth_level
= DCERPC_AUTH_LEVEL_NONE
;
364 bool neutralize_nt4_emulation
= false;
368 if (msg_ctx
== NULL
) {
370 return NT_STATUS_INVALID_PARAMETER_MIX
;
373 client_computer
= lpcfg_netbios_name(lp_ctx
);
374 if (strlen(client_computer
) > 15) {
376 return NT_STATUS_INVALID_PARAMETER_MIX
;
380 * allow overwrite per domain
381 * reject md5 servers:<netbios_domain>
383 reject_md5_servers
= lpcfg_reject_md5_servers(lp_ctx
);
384 reject_md5_servers
= lpcfg_parm_bool(lp_ctx
, NULL
,
385 "reject md5 servers",
386 server_netbios_domain
,
390 * allow overwrite per domain
391 * require strong key:<netbios_domain>
393 require_strong_key
= lpcfg_require_strong_key(lp_ctx
);
394 require_strong_key
= lpcfg_parm_bool(lp_ctx
, NULL
,
395 "require strong key",
396 server_netbios_domain
,
400 * allow overwrite per domain
401 * client schannel:<netbios_domain>
403 require_sign_or_seal
= lpcfg_client_schannel(lp_ctx
);
404 require_sign_or_seal
= lpcfg_parm_int(lp_ctx
, NULL
,
406 server_netbios_domain
,
407 require_sign_or_seal
);
410 * allow overwrite per domain
411 * winbind sealed pipes:<netbios_domain>
413 seal_secure_channel
= lpcfg_winbind_sealed_pipes(lp_ctx
);
414 seal_secure_channel
= lpcfg_parm_bool(lp_ctx
, NULL
,
415 "winbind sealed pipes",
416 server_netbios_domain
,
417 seal_secure_channel
);
420 * allow overwrite per domain
421 * neutralize nt4 emulation:<netbios_domain>
423 neutralize_nt4_emulation
= lpcfg_neutralize_nt4_emulation(lp_ctx
);
424 neutralize_nt4_emulation
= lpcfg_parm_bool(lp_ctx
, NULL
,
425 "neutralize nt4 emulation",
426 server_netbios_domain
,
427 neutralize_nt4_emulation
);
429 proposed_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
430 proposed_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
434 if (lpcfg_security(lp_ctx
) == SEC_ADS
) {
436 * AD domains should be secure
438 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
439 require_sign_or_seal
= true;
440 require_strong_key
= true;
444 case SEC_CHAN_DOMAIN
:
447 case SEC_CHAN_DNS_DOMAIN
:
449 * AD domains should be secure
451 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
452 require_sign_or_seal
= true;
453 require_strong_key
= true;
454 neutralize_nt4_emulation
= true;
458 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
459 require_sign_or_seal
= true;
460 require_strong_key
= true;
464 required_flags
|= NETLOGON_NEG_RODC_PASSTHROUGH
;
465 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
466 require_sign_or_seal
= true;
467 require_strong_key
= true;
468 neutralize_nt4_emulation
= true;
473 return NT_STATUS_INVALID_PARAMETER
;
476 if (neutralize_nt4_emulation
) {
477 proposed_flags
|= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION
;
480 if (require_sign_or_seal
) {
481 required_flags
|= NETLOGON_NEG_ARCFOUR
;
482 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
484 proposed_flags
&= ~NETLOGON_NEG_AUTHENTICATED_RPC
;
487 if (reject_md5_servers
) {
488 required_flags
|= NETLOGON_NEG_ARCFOUR
;
489 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
490 required_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
491 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
494 if (require_strong_key
) {
495 required_flags
|= NETLOGON_NEG_ARCFOUR
;
496 required_flags
|= NETLOGON_NEG_STRONG_KEYS
;
497 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
501 * If weak crypto is disabled, do not announce that we support RC4 and
504 if (lpcfg_weak_crypto(lp_ctx
) == SAMBA_WEAK_CRYPTO_DISALLOWED
) {
505 required_flags
&= ~NETLOGON_NEG_ARCFOUR
;
506 required_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
507 proposed_flags
&= ~NETLOGON_NEG_ARCFOUR
;
508 proposed_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
511 proposed_flags
|= required_flags
;
513 if (seal_secure_channel
) {
514 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
516 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
519 status
= netlogon_creds_cli_context_common(client_computer
,
526 server_netbios_domain
,
530 if (!NT_STATUS_IS_OK(status
)) {
535 context
->db
.g_ctx
= g_lock_ctx_init(context
, msg_ctx
);
536 if (context
->db
.g_ctx
== NULL
) {
537 TALLOC_FREE(context
);
539 return NT_STATUS_NO_MEMORY
;
542 status
= netlogon_creds_cli_open_global_db(lp_ctx
);
543 if (!NT_STATUS_IS_OK(status
)) {
544 TALLOC_FREE(context
);
546 return NT_STATUS_NO_MEMORY
;
549 context
->db
.ctx
= netlogon_creds_cli_global_db
;
555 NTSTATUS
netlogon_creds_bind_cli_credentials(
556 struct netlogon_creds_cli_context
*context
, TALLOC_CTX
*mem_ctx
,
557 struct cli_credentials
**pcli_creds
)
559 struct cli_credentials
*cli_creds
;
560 struct netlogon_creds_CredentialState
*ncreds
;
563 cli_creds
= cli_credentials_init(mem_ctx
);
564 if (cli_creds
== NULL
) {
565 return NT_STATUS_NO_MEMORY
;
567 cli_credentials_set_secure_channel_type(cli_creds
,
568 context
->client
.type
);
569 cli_credentials_set_username(cli_creds
, context
->client
.account
,
571 cli_credentials_set_domain(cli_creds
, context
->server
.netbios_domain
,
573 cli_credentials_set_realm(cli_creds
, context
->server
.dns_domain
,
576 status
= netlogon_creds_cli_get(context
, cli_creds
, &ncreds
);
577 if (!NT_STATUS_IS_OK(status
)) {
578 TALLOC_FREE(cli_creds
);
581 cli_credentials_set_netlogon_creds(cli_creds
, ncreds
);
583 *pcli_creds
= cli_creds
;
587 char *netlogon_creds_cli_debug_string(
588 const struct netlogon_creds_cli_context
*context
,
591 return talloc_asprintf(mem_ctx
, "netlogon_creds_cli:%s",
592 context
->db
.key_name
);
595 enum dcerpc_AuthLevel
netlogon_creds_cli_auth_level(
596 struct netlogon_creds_cli_context
*context
)
598 return context
->client
.auth_level
;
601 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags
,
602 uint32_t proposed_flags
,
603 uint32_t required_flags
)
605 uint32_t req_flags
= required_flags
;
608 req_flags
= required_flags
;
609 if ((negotiated_flags
& NETLOGON_NEG_SUPPORTS_AES
) &&
610 (proposed_flags
& NETLOGON_NEG_SUPPORTS_AES
))
612 req_flags
&= ~NETLOGON_NEG_ARCFOUR
|NETLOGON_NEG_STRONG_KEYS
;
615 tmp_flags
= negotiated_flags
;
616 tmp_flags
&= req_flags
;
617 if (tmp_flags
!= req_flags
) {
624 struct netlogon_creds_cli_fetch_state
{
626 struct netlogon_creds_CredentialState
*creds
;
627 uint32_t proposed_flags
;
628 uint32_t required_flags
;
632 static void netlogon_creds_cli_fetch_parser(TDB_DATA key
, TDB_DATA data
,
635 struct netlogon_creds_cli_fetch_state
*state
=
636 (struct netlogon_creds_cli_fetch_state
*)private_data
;
637 enum ndr_err_code ndr_err
;
641 state
->creds
= talloc_zero(state
->mem_ctx
,
642 struct netlogon_creds_CredentialState
);
643 if (state
->creds
== NULL
) {
644 state
->status
= NT_STATUS_NO_MEMORY
;
648 blob
.data
= data
.dptr
;
649 blob
.length
= data
.dsize
;
651 ndr_err
= ndr_pull_struct_blob(&blob
, state
->creds
, state
->creds
,
652 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
654 TALLOC_FREE(state
->creds
);
655 state
->status
= ndr_map_error2ntstatus(ndr_err
);
659 if (DEBUGLEVEL
>= 10) {
660 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, state
->creds
);
663 downgraded
= netlogon_creds_cli_downgraded(
664 state
->creds
->negotiate_flags
,
665 state
->proposed_flags
,
666 state
->required_flags
);
668 TALLOC_FREE(state
->creds
);
669 state
->status
= NT_STATUS_DOWNGRADE_DETECTED
;
673 state
->status
= NT_STATUS_OK
;
676 static NTSTATUS
netlogon_creds_cli_get_internal(
677 struct netlogon_creds_cli_context
*context
,
678 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
);
680 NTSTATUS
netlogon_creds_cli_get(struct netlogon_creds_cli_context
*context
,
682 struct netlogon_creds_CredentialState
**_creds
)
685 struct netlogon_creds_CredentialState
*creds
;
689 status
= netlogon_creds_cli_get_internal(context
, mem_ctx
, &creds
);
690 if (!NT_STATUS_IS_OK(status
)) {
695 * mark it as invalid for step operations.
698 creds
->seed
= (struct netr_Credential
) {{0}};
699 creds
->client
= (struct netr_Credential
) {{0}};
700 creds
->server
= (struct netr_Credential
) {{0}};
706 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context
*context
,
707 const struct netlogon_creds_CredentialState
*creds1
)
709 TALLOC_CTX
*frame
= talloc_stackframe();
710 struct netlogon_creds_CredentialState
*creds2
;
714 enum ndr_err_code ndr_err
;
717 status
= netlogon_creds_cli_get(context
, frame
, &creds2
);
718 if (!NT_STATUS_IS_OK(status
)) {
723 ndr_err
= ndr_push_struct_blob(&blob1
, frame
, creds1
,
724 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
725 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
730 ndr_err
= ndr_push_struct_blob(&blob2
, frame
, creds2
,
731 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
732 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
737 equal
= data_blob_equal_const_time(&blob1
, &blob2
);
744 static NTSTATUS
netlogon_creds_cli_store_internal(
745 struct netlogon_creds_cli_context
*context
,
746 struct netlogon_creds_CredentialState
*creds
)
749 enum ndr_err_code ndr_err
;
753 if (DEBUGLEVEL
>= 10) {
754 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
757 ndr_err
= ndr_push_struct_blob(&blob
, creds
, creds
,
758 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
759 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
760 status
= ndr_map_error2ntstatus(ndr_err
);
764 data
.dptr
= blob
.data
;
765 data
.dsize
= blob
.length
;
767 status
= dbwrap_store(context
->db
.ctx
,
768 context
->db
.key_data
,
770 TALLOC_FREE(data
.dptr
);
771 if (!NT_STATUS_IS_OK(status
)) {
778 NTSTATUS
netlogon_creds_cli_store(struct netlogon_creds_cli_context
*context
,
779 struct netlogon_creds_CredentialState
*creds
)
783 if (context
->db
.locked_state
== NULL
) {
785 * this was not the result of netlogon_creds_cli_lock*()
787 return NT_STATUS_INVALID_PAGE_PROTECTION
;
790 if (context
->db
.locked_state
->creds
!= creds
) {
792 * this was not the result of netlogon_creds_cli_lock*()
794 return NT_STATUS_INVALID_PAGE_PROTECTION
;
797 status
= netlogon_creds_cli_store_internal(context
, creds
);
801 static NTSTATUS
netlogon_creds_cli_delete_internal(
802 struct netlogon_creds_cli_context
*context
)
805 status
= dbwrap_delete(context
->db
.ctx
, context
->db
.key_data
);
809 NTSTATUS
netlogon_creds_cli_delete_lck(
810 struct netlogon_creds_cli_context
*context
)
814 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
815 return NT_STATUS_NOT_LOCKED
;
818 status
= netlogon_creds_cli_delete_internal(context
);
822 NTSTATUS
netlogon_creds_cli_delete(struct netlogon_creds_cli_context
*context
,
823 struct netlogon_creds_CredentialState
*creds
)
827 if (context
->db
.locked_state
== NULL
) {
829 * this was not the result of netlogon_creds_cli_lock*()
831 return NT_STATUS_INVALID_PAGE_PROTECTION
;
834 if (context
->db
.locked_state
->creds
!= creds
) {
836 * this was not the result of netlogon_creds_cli_lock*()
838 return NT_STATUS_INVALID_PAGE_PROTECTION
;
841 status
= netlogon_creds_cli_delete_internal(context
);
845 struct netlogon_creds_cli_lock_state
{
846 struct netlogon_creds_cli_locked_state
*locked_state
;
847 struct netlogon_creds_CredentialState
*creds
;
850 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
);
852 struct tevent_req
*netlogon_creds_cli_lock_send(TALLOC_CTX
*mem_ctx
,
853 struct tevent_context
*ev
,
854 struct netlogon_creds_cli_context
*context
)
856 struct tevent_req
*req
;
857 struct netlogon_creds_cli_lock_state
*state
;
858 struct netlogon_creds_cli_locked_state
*locked_state
;
859 struct tevent_req
*subreq
;
861 req
= tevent_req_create(mem_ctx
, &state
,
862 struct netlogon_creds_cli_lock_state
);
867 if (context
->db
.locked_state
!= NULL
) {
868 tevent_req_nterror(req
, NT_STATUS_LOCK_NOT_GRANTED
);
869 return tevent_req_post(req
, ev
);
872 locked_state
= talloc_zero(state
, struct netlogon_creds_cli_locked_state
);
873 if (tevent_req_nomem(locked_state
, req
)) {
874 return tevent_req_post(req
, ev
);
876 talloc_set_destructor(locked_state
,
877 netlogon_creds_cli_locked_state_destructor
);
878 locked_state
->context
= context
;
880 context
->db
.locked_state
= locked_state
;
881 state
->locked_state
= locked_state
;
883 if (context
->db
.g_ctx
== NULL
) {
886 status
= netlogon_creds_cli_get_internal(
887 context
, state
, &state
->creds
);
888 if (tevent_req_nterror(req
, status
)) {
889 return tevent_req_post(req
, ev
);
895 subreq
= g_lock_lock_send(state
, ev
,
897 string_term_tdb_data(context
->db
.key_name
),
900 if (tevent_req_nomem(subreq
, req
)) {
901 return tevent_req_post(req
, ev
);
903 tevent_req_set_callback(subreq
, netlogon_creds_cli_lock_done
, req
);
908 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
)
910 struct tevent_req
*req
=
911 tevent_req_callback_data(subreq
,
913 struct netlogon_creds_cli_lock_state
*state
=
915 struct netlogon_creds_cli_lock_state
);
918 status
= g_lock_lock_recv(subreq
);
920 if (tevent_req_nterror(req
, status
)) {
923 state
->locked_state
->is_glocked
= true;
925 status
= netlogon_creds_cli_get_internal(state
->locked_state
->context
,
926 state
, &state
->creds
);
927 if (tevent_req_nterror(req
, status
)) {
930 tevent_req_done(req
);
933 static NTSTATUS
netlogon_creds_cli_get_internal(
934 struct netlogon_creds_cli_context
*context
,
935 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
)
937 struct netlogon_creds_cli_fetch_state fstate
= {
938 .status
= NT_STATUS_INTERNAL_ERROR
,
939 .proposed_flags
= context
->client
.proposed_flags
,
940 .required_flags
= context
->client
.required_flags
,
944 fstate
.mem_ctx
= mem_ctx
;
945 status
= dbwrap_parse_record(context
->db
.ctx
,
946 context
->db
.key_data
,
947 netlogon_creds_cli_fetch_parser
,
949 if (!NT_STATUS_IS_OK(status
)) {
952 if (!NT_STATUS_IS_OK(fstate
.status
)) {
953 return fstate
.status
;
956 if (context
->server
.cached_flags
== fstate
.creds
->negotiate_flags
) {
957 *pcreds
= fstate
.creds
;
962 * It is really important to try SamLogonEx here,
963 * because multiple processes can talk to the same
964 * domain controller, without using the credential
967 * With a normal SamLogon call, we must keep the
968 * credentials chain updated and intact between all
969 * users of the machine account (which would imply
970 * cross-node communication for every NTLM logon).
972 * The credentials chain is not per NETLOGON pipe
973 * connection, but globally on the server/client pair
976 * It's also important to use NetlogonValidationSamInfo4 (6),
977 * because it relies on the rpc transport encryption
978 * and avoids using the global netlogon schannel
979 * session key to en/decrypt secret information
980 * like the user_session_key for network logons.
982 * [MS-APDS] 3.1.5.2 NTLM Network Logon
983 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
984 * NETLOGON_NEG_AUTHENTICATED_RPC set together
985 * are the indication that the server supports
986 * NetlogonValidationSamInfo4 (6). And it must only
987 * be used if "SealSecureChannel" is used.
989 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
990 * check is done in netlogon_creds_cli_LogonSamLogon*().
993 context
->server
.cached_flags
= fstate
.creds
->negotiate_flags
;
994 context
->server
.try_validation6
= true;
995 context
->server
.try_logon_ex
= true;
996 context
->server
.try_logon_with
= true;
998 if (!(context
->server
.cached_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
)) {
999 context
->server
.try_validation6
= false;
1000 context
->server
.try_logon_ex
= false;
1002 if (!(context
->server
.cached_flags
& NETLOGON_NEG_CROSS_FOREST_TRUSTS
)) {
1003 context
->server
.try_validation6
= false;
1006 *pcreds
= fstate
.creds
;
1007 return NT_STATUS_OK
;
1010 NTSTATUS
netlogon_creds_cli_lock_recv(struct tevent_req
*req
,
1011 TALLOC_CTX
*mem_ctx
,
1012 struct netlogon_creds_CredentialState
**creds
)
1014 struct netlogon_creds_cli_lock_state
*state
=
1015 tevent_req_data(req
,
1016 struct netlogon_creds_cli_lock_state
);
1019 if (tevent_req_is_nterror(req
, &status
)) {
1020 tevent_req_received(req
);
1024 talloc_steal(state
->creds
, state
->locked_state
);
1025 state
->locked_state
->creds
= state
->creds
;
1026 *creds
= talloc_move(mem_ctx
, &state
->creds
);
1027 tevent_req_received(req
);
1028 return NT_STATUS_OK
;
1031 NTSTATUS
netlogon_creds_cli_lock(struct netlogon_creds_cli_context
*context
,
1032 TALLOC_CTX
*mem_ctx
,
1033 struct netlogon_creds_CredentialState
**creds
)
1035 TALLOC_CTX
*frame
= talloc_stackframe();
1036 struct tevent_context
*ev
;
1037 struct tevent_req
*req
;
1038 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1040 ev
= samba_tevent_context_init(frame
);
1044 req
= netlogon_creds_cli_lock_send(frame
, ev
, context
);
1048 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1051 status
= netlogon_creds_cli_lock_recv(req
, mem_ctx
, creds
);
1057 struct netlogon_creds_cli_lck
{
1058 struct netlogon_creds_cli_context
*context
;
1061 struct netlogon_creds_cli_lck_state
{
1062 struct netlogon_creds_cli_lck
*lck
;
1063 enum netlogon_creds_cli_lck_type type
;
1066 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
);
1067 static int netlogon_creds_cli_lck_destructor(
1068 struct netlogon_creds_cli_lck
*lck
);
1070 struct tevent_req
*netlogon_creds_cli_lck_send(
1071 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
1072 struct netlogon_creds_cli_context
*context
,
1073 enum netlogon_creds_cli_lck_type type
)
1075 struct tevent_req
*req
, *subreq
;
1076 struct netlogon_creds_cli_lck_state
*state
;
1077 enum g_lock_type gtype
;
1079 req
= tevent_req_create(mem_ctx
, &state
,
1080 struct netlogon_creds_cli_lck_state
);
1085 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_NONE
) {
1086 DBG_DEBUG("context already locked\n");
1087 tevent_req_nterror(req
, NT_STATUS_INVALID_LOCK_SEQUENCE
);
1088 return tevent_req_post(req
, ev
);
1092 case NETLOGON_CREDS_CLI_LCK_SHARED
:
1093 gtype
= G_LOCK_READ
;
1095 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
:
1096 gtype
= G_LOCK_WRITE
;
1099 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1100 return tevent_req_post(req
, ev
);
1103 state
->lck
= talloc(state
, struct netlogon_creds_cli_lck
);
1104 if (tevent_req_nomem(state
->lck
, req
)) {
1105 return tevent_req_post(req
, ev
);
1107 state
->lck
->context
= context
;
1110 subreq
= g_lock_lock_send(state
, ev
,
1112 string_term_tdb_data(context
->db
.key_name
),
1115 if (tevent_req_nomem(subreq
, req
)) {
1116 return tevent_req_post(req
, ev
);
1118 tevent_req_set_callback(subreq
, netlogon_creds_cli_lck_locked
, req
);
1123 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
)
1125 struct tevent_req
*req
= tevent_req_callback_data(
1126 subreq
, struct tevent_req
);
1127 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1128 req
, struct netlogon_creds_cli_lck_state
);
1131 status
= g_lock_lock_recv(subreq
);
1132 TALLOC_FREE(subreq
);
1133 if (tevent_req_nterror(req
, status
)) {
1137 state
->lck
->context
->db
.lock
= state
->type
;
1138 talloc_set_destructor(state
->lck
, netlogon_creds_cli_lck_destructor
);
1140 tevent_req_done(req
);
1143 static int netlogon_creds_cli_lck_destructor(
1144 struct netlogon_creds_cli_lck
*lck
)
1146 struct netlogon_creds_cli_context
*ctx
= lck
->context
;
1149 status
= g_lock_unlock(ctx
->db
.g_ctx
,
1150 string_term_tdb_data(ctx
->db
.key_name
));
1151 if (!NT_STATUS_IS_OK(status
)) {
1152 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status
));
1153 smb_panic("g_lock_unlock failed");
1155 ctx
->db
.lock
= NETLOGON_CREDS_CLI_LCK_NONE
;
1159 NTSTATUS
netlogon_creds_cli_lck_recv(
1160 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1161 struct netlogon_creds_cli_lck
**lck
)
1163 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1164 req
, struct netlogon_creds_cli_lck_state
);
1167 if (tevent_req_is_nterror(req
, &status
)) {
1170 *lck
= talloc_move(mem_ctx
, &state
->lck
);
1171 return NT_STATUS_OK
;
1174 NTSTATUS
netlogon_creds_cli_lck(
1175 struct netlogon_creds_cli_context
*context
,
1176 enum netlogon_creds_cli_lck_type type
,
1177 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_cli_lck
**lck
)
1179 TALLOC_CTX
*frame
= talloc_stackframe();
1180 struct tevent_context
*ev
;
1181 struct tevent_req
*req
;
1182 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1184 ev
= samba_tevent_context_init(frame
);
1188 req
= netlogon_creds_cli_lck_send(frame
, ev
, context
, type
);
1192 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1195 status
= netlogon_creds_cli_lck_recv(req
, mem_ctx
, lck
);
1201 struct netlogon_creds_cli_auth_state
{
1202 struct tevent_context
*ev
;
1203 struct netlogon_creds_cli_context
*context
;
1204 struct dcerpc_binding_handle
*binding_handle
;
1205 uint8_t num_nt_hashes
;
1206 uint8_t idx_nt_hashes
;
1207 const struct samr_Password
* const *nt_hashes
;
1208 const struct samr_Password
*used_nt_hash
;
1209 char *srv_name_slash
;
1210 uint32_t current_flags
;
1211 struct netr_Credential client_challenge
;
1212 struct netr_Credential server_challenge
;
1213 struct netlogon_creds_CredentialState
*creds
;
1214 struct netr_Credential client_credential
;
1215 struct netr_Credential server_credential
;
1222 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
);
1224 struct tevent_req
*netlogon_creds_cli_auth_send(TALLOC_CTX
*mem_ctx
,
1225 struct tevent_context
*ev
,
1226 struct netlogon_creds_cli_context
*context
,
1227 struct dcerpc_binding_handle
*b
,
1228 uint8_t num_nt_hashes
,
1229 const struct samr_Password
* const *nt_hashes
)
1231 struct tevent_req
*req
;
1232 struct netlogon_creds_cli_auth_state
*state
;
1235 req
= tevent_req_create(mem_ctx
, &state
,
1236 struct netlogon_creds_cli_auth_state
);
1242 state
->context
= context
;
1243 state
->binding_handle
= b
;
1244 if (num_nt_hashes
< 1) {
1245 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1246 return tevent_req_post(req
, ev
);
1248 if (num_nt_hashes
> 4) {
1249 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1250 return tevent_req_post(req
, ev
);
1253 state
->num_nt_hashes
= num_nt_hashes
;
1254 state
->idx_nt_hashes
= 0;
1255 state
->nt_hashes
= nt_hashes
;
1257 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1258 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1259 return tevent_req_post(req
, ev
);
1262 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1263 context
->server
.computer
);
1264 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1265 return tevent_req_post(req
, ev
);
1268 state
->try_auth3
= true;
1269 state
->try_auth2
= true;
1271 if (context
->client
.required_flags
!= 0) {
1272 state
->require_auth2
= true;
1275 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1276 state
->current_flags
= context
->client
.proposed_flags
;
1278 status
= dbwrap_purge(state
->context
->db
.ctx
,
1279 state
->context
->db
.key_data
);
1280 if (tevent_req_nterror(req
, status
)) {
1281 return tevent_req_post(req
, ev
);
1284 netlogon_creds_cli_auth_challenge_start(req
);
1285 if (!tevent_req_is_in_progress(req
)) {
1286 return tevent_req_post(req
, ev
);
1292 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
);
1294 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
)
1296 struct netlogon_creds_cli_auth_state
*state
=
1297 tevent_req_data(req
,
1298 struct netlogon_creds_cli_auth_state
);
1299 struct tevent_req
*subreq
;
1301 TALLOC_FREE(state
->creds
);
1303 netlogon_creds_random_challenge(&state
->client_challenge
);
1305 subreq
= dcerpc_netr_ServerReqChallenge_send(state
, state
->ev
,
1306 state
->binding_handle
,
1307 state
->srv_name_slash
,
1308 state
->context
->client
.computer
,
1309 &state
->client_challenge
,
1310 &state
->server_challenge
);
1311 if (tevent_req_nomem(subreq
, req
)) {
1314 tevent_req_set_callback(subreq
,
1315 netlogon_creds_cli_auth_challenge_done
,
1319 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
);
1321 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
)
1323 struct tevent_req
*req
=
1324 tevent_req_callback_data(subreq
,
1326 struct netlogon_creds_cli_auth_state
*state
=
1327 tevent_req_data(req
,
1328 struct netlogon_creds_cli_auth_state
);
1332 status
= dcerpc_netr_ServerReqChallenge_recv(subreq
, state
, &result
);
1333 TALLOC_FREE(subreq
);
1334 if (tevent_req_nterror(req
, status
)) {
1337 if (tevent_req_nterror(req
, result
)) {
1341 if (!state
->try_auth3
&& !state
->try_auth2
) {
1342 state
->current_flags
= 0;
1345 /* Calculate the session key and client credentials */
1347 state
->creds
= netlogon_creds_client_init(state
,
1348 state
->context
->client
.account
,
1349 state
->context
->client
.computer
,
1350 state
->context
->client
.type
,
1351 &state
->client_challenge
,
1352 &state
->server_challenge
,
1353 state
->used_nt_hash
,
1354 &state
->client_credential
,
1355 state
->current_flags
);
1356 if (tevent_req_nomem(state
->creds
, req
)) {
1360 if (state
->try_auth3
) {
1361 subreq
= dcerpc_netr_ServerAuthenticate3_send(state
, state
->ev
,
1362 state
->binding_handle
,
1363 state
->srv_name_slash
,
1364 state
->context
->client
.account
,
1365 state
->context
->client
.type
,
1366 state
->context
->client
.computer
,
1367 &state
->client_credential
,
1368 &state
->server_credential
,
1369 &state
->creds
->negotiate_flags
,
1371 if (tevent_req_nomem(subreq
, req
)) {
1374 } else if (state
->try_auth2
) {
1377 subreq
= dcerpc_netr_ServerAuthenticate2_send(state
, state
->ev
,
1378 state
->binding_handle
,
1379 state
->srv_name_slash
,
1380 state
->context
->client
.account
,
1381 state
->context
->client
.type
,
1382 state
->context
->client
.computer
,
1383 &state
->client_credential
,
1384 &state
->server_credential
,
1385 &state
->creds
->negotiate_flags
);
1386 if (tevent_req_nomem(subreq
, req
)) {
1392 subreq
= dcerpc_netr_ServerAuthenticate_send(state
, state
->ev
,
1393 state
->binding_handle
,
1394 state
->srv_name_slash
,
1395 state
->context
->client
.account
,
1396 state
->context
->client
.type
,
1397 state
->context
->client
.computer
,
1398 &state
->client_credential
,
1399 &state
->server_credential
);
1400 if (tevent_req_nomem(subreq
, req
)) {
1404 tevent_req_set_callback(subreq
,
1405 netlogon_creds_cli_auth_srvauth_done
,
1409 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
)
1411 struct tevent_req
*req
=
1412 tevent_req_callback_data(subreq
,
1414 struct netlogon_creds_cli_auth_state
*state
=
1415 tevent_req_data(req
,
1416 struct netlogon_creds_cli_auth_state
);
1420 enum ndr_err_code ndr_err
;
1425 if (state
->try_auth3
) {
1426 status
= dcerpc_netr_ServerAuthenticate3_recv(subreq
, state
,
1428 TALLOC_FREE(subreq
);
1429 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1430 state
->try_auth3
= false;
1431 netlogon_creds_cli_auth_challenge_start(req
);
1434 if (tevent_req_nterror(req
, status
)) {
1437 } else if (state
->try_auth2
) {
1438 status
= dcerpc_netr_ServerAuthenticate2_recv(subreq
, state
,
1440 TALLOC_FREE(subreq
);
1441 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1442 state
->try_auth2
= false;
1443 if (state
->require_auth2
) {
1444 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1445 tevent_req_nterror(req
, status
);
1448 netlogon_creds_cli_auth_challenge_start(req
);
1451 if (tevent_req_nterror(req
, status
)) {
1455 status
= dcerpc_netr_ServerAuthenticate_recv(subreq
, state
,
1457 TALLOC_FREE(subreq
);
1458 if (tevent_req_nterror(req
, status
)) {
1463 if (!NT_STATUS_IS_OK(result
) &&
1464 !NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
))
1466 tevent_req_nterror(req
, result
);
1470 downgraded
= netlogon_creds_cli_downgraded(
1471 state
->creds
->negotiate_flags
,
1472 state
->context
->client
.proposed_flags
,
1473 state
->context
->client
.required_flags
);
1475 if (NT_STATUS_IS_OK(result
)) {
1476 tevent_req_nterror(req
, NT_STATUS_DOWNGRADE_DETECTED
);
1479 tevent_req_nterror(req
, result
);
1483 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
1484 uint32_t tmp_flags
= state
->context
->client
.proposed_flags
;
1485 if ((state
->current_flags
== tmp_flags
) &&
1486 (state
->creds
->negotiate_flags
!= tmp_flags
))
1489 * lets retry with the negotiated flags
1491 state
->current_flags
= state
->creds
->negotiate_flags
;
1492 netlogon_creds_cli_auth_challenge_start(req
);
1496 state
->idx_nt_hashes
+= 1;
1497 if (state
->idx_nt_hashes
>= state
->num_nt_hashes
) {
1499 * we already retried, giving up...
1501 tevent_req_nterror(req
, result
);
1506 * lets retry with the old nt hash.
1508 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1509 state
->current_flags
= state
->context
->client
.proposed_flags
;
1510 netlogon_creds_cli_auth_challenge_start(req
);
1514 ok
= netlogon_creds_client_check(state
->creds
,
1515 &state
->server_credential
);
1517 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
1521 ndr_err
= ndr_push_struct_blob(&blob
, state
, state
->creds
,
1522 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
1523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1524 status
= ndr_map_error2ntstatus(ndr_err
);
1525 tevent_req_nterror(req
, status
);
1529 data
.dptr
= blob
.data
;
1530 data
.dsize
= blob
.length
;
1532 status
= dbwrap_store(state
->context
->db
.ctx
,
1533 state
->context
->db
.key_data
,
1535 if (tevent_req_nterror(req
, status
)) {
1539 tevent_req_done(req
);
1542 NTSTATUS
netlogon_creds_cli_auth_recv(struct tevent_req
*req
,
1543 uint8_t *idx_nt_hashes
)
1545 struct netlogon_creds_cli_auth_state
*state
=
1546 tevent_req_data(req
,
1547 struct netlogon_creds_cli_auth_state
);
1552 if (tevent_req_is_nterror(req
, &status
)) {
1553 tevent_req_received(req
);
1557 *idx_nt_hashes
= state
->idx_nt_hashes
;
1558 tevent_req_received(req
);
1559 return NT_STATUS_OK
;
1562 NTSTATUS
netlogon_creds_cli_auth(struct netlogon_creds_cli_context
*context
,
1563 struct dcerpc_binding_handle
*b
,
1564 uint8_t num_nt_hashes
,
1565 const struct samr_Password
* const *nt_hashes
,
1566 uint8_t *idx_nt_hashes
)
1568 TALLOC_CTX
*frame
= talloc_stackframe();
1569 struct tevent_context
*ev
;
1570 struct tevent_req
*req
;
1571 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1575 ev
= samba_tevent_context_init(frame
);
1579 req
= netlogon_creds_cli_auth_send(frame
, ev
, context
, b
,
1580 num_nt_hashes
, nt_hashes
);
1584 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1587 status
= netlogon_creds_cli_auth_recv(req
, idx_nt_hashes
);
1593 struct netlogon_creds_cli_check_state
{
1594 struct tevent_context
*ev
;
1595 struct netlogon_creds_cli_context
*context
;
1596 struct dcerpc_binding_handle
*binding_handle
;
1598 char *srv_name_slash
;
1600 union netr_Capabilities caps
;
1602 struct netlogon_creds_CredentialState
*creds
;
1603 struct netr_Authenticator req_auth
;
1604 struct netr_Authenticator rep_auth
;
1607 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1609 static void netlogon_creds_cli_check_caps(struct tevent_req
*subreq
);
1611 struct tevent_req
*netlogon_creds_cli_check_send(TALLOC_CTX
*mem_ctx
,
1612 struct tevent_context
*ev
,
1613 struct netlogon_creds_cli_context
*context
,
1614 struct dcerpc_binding_handle
*b
)
1616 struct tevent_req
*req
;
1617 struct netlogon_creds_cli_check_state
*state
;
1618 struct tevent_req
*subreq
;
1619 enum dcerpc_AuthType auth_type
;
1620 enum dcerpc_AuthLevel auth_level
;
1623 req
= tevent_req_create(mem_ctx
, &state
,
1624 struct netlogon_creds_cli_check_state
);
1630 state
->context
= context
;
1631 state
->binding_handle
= b
;
1633 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1634 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1635 return tevent_req_post(req
, ev
);
1638 status
= netlogon_creds_cli_get_internal(context
, state
,
1640 if (tevent_req_nterror(req
, status
)) {
1641 return tevent_req_post(req
, ev
);
1644 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1645 context
->server
.computer
);
1646 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1647 return tevent_req_post(req
, ev
);
1650 dcerpc_binding_handle_auth_info(state
->binding_handle
,
1651 &auth_type
, &auth_level
);
1653 if (auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
1654 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1655 return tevent_req_post(req
, ev
);
1658 switch (auth_level
) {
1659 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1660 case DCERPC_AUTH_LEVEL_PRIVACY
:
1663 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1664 return tevent_req_post(req
, ev
);
1668 * we defer all callbacks in order to cleanup
1669 * the database record.
1671 tevent_req_defer_callback(req
, state
->ev
);
1673 status
= netlogon_creds_client_authenticator(state
->creds
,
1675 if (tevent_req_nterror(req
, status
)) {
1676 return tevent_req_post(req
, ev
);
1678 ZERO_STRUCT(state
->rep_auth
);
1680 subreq
= dcerpc_netr_LogonGetCapabilities_send(state
, state
->ev
,
1681 state
->binding_handle
,
1682 state
->srv_name_slash
,
1683 state
->context
->client
.computer
,
1688 if (tevent_req_nomem(subreq
, req
)) {
1689 return tevent_req_post(req
, ev
);
1692 tevent_req_set_callback(subreq
,
1693 netlogon_creds_cli_check_caps
,
1699 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1702 struct netlogon_creds_cli_check_state
*state
=
1703 tevent_req_data(req
,
1704 struct netlogon_creds_cli_check_state
);
1706 if (state
->creds
== NULL
) {
1710 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
1711 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
1712 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
1713 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
1714 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
1715 TALLOC_FREE(state
->creds
);
1719 netlogon_creds_cli_delete_lck(state
->context
);
1720 TALLOC_FREE(state
->creds
);
1723 static void netlogon_creds_cli_check_caps(struct tevent_req
*subreq
)
1725 struct tevent_req
*req
=
1726 tevent_req_callback_data(subreq
,
1728 struct netlogon_creds_cli_check_state
*state
=
1729 tevent_req_data(req
,
1730 struct netlogon_creds_cli_check_state
);
1735 status
= dcerpc_netr_LogonGetCapabilities_recv(subreq
, state
,
1737 TALLOC_FREE(subreq
);
1738 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1740 * Note that the negotiated flags are already checked
1741 * for our required flags after the ServerAuthenticate3/2 call.
1743 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1745 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1747 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1748 * already, we expect this to work!
1750 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1751 tevent_req_nterror(req
, status
);
1752 netlogon_creds_cli_check_cleanup(req
, status
);
1756 if (negotiated
& NETLOGON_NEG_STRONG_KEYS
) {
1758 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1759 * we expect this to work at least as far as the
1760 * NOT_SUPPORTED error handled below!
1762 * NT 4.0 and Old Samba servers are not
1763 * allowed without "require strong key = no"
1765 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1766 tevent_req_nterror(req
, status
);
1767 netlogon_creds_cli_check_cleanup(req
, status
);
1772 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1773 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1774 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1776 * This is needed against NT 4.0 and old Samba servers.
1778 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1779 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1780 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1781 * with the next request as the sequence number processing
1784 netlogon_creds_cli_check_cleanup(req
, status
);
1785 tevent_req_done(req
);
1788 if (tevent_req_nterror(req
, status
)) {
1789 netlogon_creds_cli_check_cleanup(req
, status
);
1793 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
1795 * Note that the negotiated flags are already checked
1796 * for our required flags after the ServerAuthenticate3/2 call.
1798 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1800 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1802 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1803 * already, we expect this to work!
1805 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1806 tevent_req_nterror(req
, status
);
1807 netlogon_creds_cli_check_cleanup(req
, status
);
1812 * This is ok, the server does not support
1813 * NETLOGON_NEG_SUPPORTS_AES.
1815 * netr_LogonGetCapabilities() was
1816 * netr_LogonDummyRoutine1() before
1817 * NETLOGON_NEG_SUPPORTS_AES was invented.
1819 netlogon_creds_cli_check_cleanup(req
, result
);
1820 tevent_req_done(req
);
1824 ok
= netlogon_creds_client_check(state
->creds
, &state
->rep_auth
.cred
);
1826 status
= NT_STATUS_ACCESS_DENIED
;
1827 tevent_req_nterror(req
, status
);
1828 netlogon_creds_cli_check_cleanup(req
, status
);
1832 if (tevent_req_nterror(req
, result
)) {
1833 netlogon_creds_cli_check_cleanup(req
, result
);
1837 if (state
->caps
.server_capabilities
!= state
->creds
->negotiate_flags
) {
1838 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1839 tevent_req_nterror(req
, status
);
1840 netlogon_creds_cli_check_cleanup(req
, status
);
1845 * This is the key check that makes this check secure. If we
1846 * get OK here (rather than NOT_SUPPORTED), then the server
1847 * did support AES. If the server only proposed STRONG_KEYS
1848 * and not AES, then it should have failed with
1849 * NOT_IMPLEMENTED. We always send AES as a client, so the
1850 * server should always have returned it.
1852 if (!(state
->caps
.server_capabilities
& NETLOGON_NEG_SUPPORTS_AES
)) {
1853 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1854 tevent_req_nterror(req
, status
);
1855 netlogon_creds_cli_check_cleanup(req
, status
);
1859 status
= netlogon_creds_cli_store_internal(state
->context
,
1861 if (tevent_req_nterror(req
, status
)) {
1865 tevent_req_done(req
);
1868 NTSTATUS
netlogon_creds_cli_check_recv(struct tevent_req
*req
,
1869 union netr_Capabilities
*capabilities
)
1871 struct netlogon_creds_cli_check_state
*state
= tevent_req_data(
1872 req
, struct netlogon_creds_cli_check_state
);
1875 if (tevent_req_is_nterror(req
, &status
)) {
1876 netlogon_creds_cli_check_cleanup(req
, status
);
1877 tevent_req_received(req
);
1881 if (capabilities
!= NULL
) {
1882 *capabilities
= state
->caps
;
1885 tevent_req_received(req
);
1886 return NT_STATUS_OK
;
1889 NTSTATUS
netlogon_creds_cli_check(struct netlogon_creds_cli_context
*context
,
1890 struct dcerpc_binding_handle
*b
,
1891 union netr_Capabilities
*capabilities
)
1893 TALLOC_CTX
*frame
= talloc_stackframe();
1894 struct tevent_context
*ev
;
1895 struct tevent_req
*req
;
1896 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1898 ev
= samba_tevent_context_init(frame
);
1902 req
= netlogon_creds_cli_check_send(frame
, ev
, context
, b
);
1906 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1909 status
= netlogon_creds_cli_check_recv(req
, capabilities
);
1915 struct netlogon_creds_cli_ServerPasswordSet_state
{
1916 struct tevent_context
*ev
;
1917 struct netlogon_creds_cli_context
*context
;
1918 struct dcerpc_binding_handle
*binding_handle
;
1919 uint32_t old_timeout
;
1921 char *srv_name_slash
;
1922 enum dcerpc_AuthType auth_type
;
1923 enum dcerpc_AuthLevel auth_level
;
1925 struct samr_CryptPassword samr_crypt_password
;
1926 struct netr_CryptPassword netr_crypt_password
;
1927 struct samr_Password samr_password
;
1929 struct netlogon_creds_CredentialState
*creds
;
1930 struct netlogon_creds_CredentialState tmp_creds
;
1931 struct netr_Authenticator req_auth
;
1932 struct netr_Authenticator rep_auth
;
1935 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
1937 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
);
1939 struct tevent_req
*netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX
*mem_ctx
,
1940 struct tevent_context
*ev
,
1941 struct netlogon_creds_cli_context
*context
,
1942 struct dcerpc_binding_handle
*b
,
1943 const DATA_BLOB
*new_password
,
1944 const uint32_t *new_version
)
1946 struct tevent_req
*req
;
1947 struct netlogon_creds_cli_ServerPasswordSet_state
*state
;
1948 struct tevent_req
*subreq
;
1951 req
= tevent_req_create(mem_ctx
, &state
,
1952 struct netlogon_creds_cli_ServerPasswordSet_state
);
1958 state
->context
= context
;
1959 state
->binding_handle
= b
;
1961 if (new_password
->length
< 14) {
1962 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1963 return tevent_req_post(req
, ev
);
1967 * netr_ServerPasswordSet
1969 mdfour(state
->samr_password
.hash
, new_password
->data
, new_password
->length
);
1972 * netr_ServerPasswordSet2
1974 ok
= set_pw_in_buffer(state
->samr_crypt_password
.data
,
1977 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1978 return tevent_req_post(req
, ev
);
1981 if (new_version
!= NULL
) {
1982 struct NL_PASSWORD_VERSION version
;
1983 uint32_t len
= IVAL(state
->samr_crypt_password
.data
, 512);
1984 uint32_t ofs
= 512 - len
;
1988 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1989 return tevent_req_post(req
, ev
);
1993 version
.ReservedField
= 0;
1994 version
.PasswordVersionNumber
= *new_version
;
1995 version
.PasswordVersionPresent
=
1996 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT
;
1998 p
= state
->samr_crypt_password
.data
+ ofs
;
1999 SIVAL(p
, 0, version
.ReservedField
);
2000 SIVAL(p
, 4, version
.PasswordVersionNumber
);
2001 SIVAL(p
, 8, version
.PasswordVersionPresent
);
2004 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2005 context
->server
.computer
);
2006 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2007 return tevent_req_post(req
, ev
);
2010 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2012 &state
->auth_level
);
2014 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2016 if (tevent_req_nomem(subreq
, req
)) {
2017 return tevent_req_post(req
, ev
);
2020 tevent_req_set_callback(subreq
,
2021 netlogon_creds_cli_ServerPasswordSet_locked
,
2027 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
2030 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2031 tevent_req_data(req
,
2032 struct netlogon_creds_cli_ServerPasswordSet_state
);
2034 if (state
->creds
== NULL
) {
2038 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
2039 state
->old_timeout
);
2041 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2042 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2043 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2044 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2045 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2046 TALLOC_FREE(state
->creds
);
2050 netlogon_creds_cli_delete(state
->context
, state
->creds
);
2051 TALLOC_FREE(state
->creds
);
2054 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
);
2056 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
)
2058 struct tevent_req
*req
=
2059 tevent_req_callback_data(subreq
,
2061 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2062 tevent_req_data(req
,
2063 struct netlogon_creds_cli_ServerPasswordSet_state
);
2066 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2068 TALLOC_FREE(subreq
);
2069 if (tevent_req_nterror(req
, status
)) {
2073 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
2074 switch (state
->auth_level
) {
2075 case DCERPC_AUTH_LEVEL_INTEGRITY
:
2076 case DCERPC_AUTH_LEVEL_PRIVACY
:
2079 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2083 uint32_t tmp
= state
->creds
->negotiate_flags
;
2085 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
2087 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2088 * it should be used, which means
2089 * we had a chance to verify no downgrade
2092 * This relies on netlogon_creds_cli_check*
2093 * being called before, as first request after
2096 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2101 state
->old_timeout
= dcerpc_binding_handle_set_timeout(
2102 state
->binding_handle
, 600000);
2105 * we defer all callbacks in order to cleanup
2106 * the database record.
2108 tevent_req_defer_callback(req
, state
->ev
);
2110 state
->tmp_creds
= *state
->creds
;
2111 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2113 if (tevent_req_nterror(req
, status
)) {
2116 ZERO_STRUCT(state
->rep_auth
);
2118 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
2120 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
2121 status
= netlogon_creds_aes_encrypt(&state
->tmp_creds
,
2122 state
->samr_crypt_password
.data
,
2124 if (tevent_req_nterror(req
, status
)) {
2125 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2129 status
= netlogon_creds_arcfour_crypt(&state
->tmp_creds
,
2130 state
->samr_crypt_password
.data
,
2132 if (tevent_req_nterror(req
, status
)) {
2133 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2138 memcpy(state
->netr_crypt_password
.data
,
2139 state
->samr_crypt_password
.data
, 512);
2140 state
->netr_crypt_password
.length
=
2141 IVAL(state
->samr_crypt_password
.data
, 512);
2143 subreq
= dcerpc_netr_ServerPasswordSet2_send(state
, state
->ev
,
2144 state
->binding_handle
,
2145 state
->srv_name_slash
,
2146 state
->tmp_creds
.account_name
,
2147 state
->tmp_creds
.secure_channel_type
,
2148 state
->tmp_creds
.computer_name
,
2151 &state
->netr_crypt_password
);
2152 if (tevent_req_nomem(subreq
, req
)) {
2153 status
= NT_STATUS_NO_MEMORY
;
2154 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2158 status
= netlogon_creds_des_encrypt(&state
->tmp_creds
,
2159 &state
->samr_password
);
2160 if (tevent_req_nterror(req
, status
)) {
2161 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2165 subreq
= dcerpc_netr_ServerPasswordSet_send(state
, state
->ev
,
2166 state
->binding_handle
,
2167 state
->srv_name_slash
,
2168 state
->tmp_creds
.account_name
,
2169 state
->tmp_creds
.secure_channel_type
,
2170 state
->tmp_creds
.computer_name
,
2173 &state
->samr_password
);
2174 if (tevent_req_nomem(subreq
, req
)) {
2175 status
= NT_STATUS_NO_MEMORY
;
2176 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2181 tevent_req_set_callback(subreq
,
2182 netlogon_creds_cli_ServerPasswordSet_done
,
2186 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
)
2188 struct tevent_req
*req
=
2189 tevent_req_callback_data(subreq
,
2191 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2192 tevent_req_data(req
,
2193 struct netlogon_creds_cli_ServerPasswordSet_state
);
2198 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
2199 status
= dcerpc_netr_ServerPasswordSet2_recv(subreq
, state
,
2201 TALLOC_FREE(subreq
);
2202 if (tevent_req_nterror(req
, status
)) {
2203 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2207 status
= dcerpc_netr_ServerPasswordSet_recv(subreq
, state
,
2209 TALLOC_FREE(subreq
);
2210 if (tevent_req_nterror(req
, status
)) {
2211 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2216 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
2217 &state
->rep_auth
.cred
);
2219 status
= NT_STATUS_ACCESS_DENIED
;
2220 tevent_req_nterror(req
, status
);
2221 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2225 if (tevent_req_nterror(req
, result
)) {
2226 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, result
);
2230 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
2231 state
->old_timeout
);
2233 *state
->creds
= state
->tmp_creds
;
2234 status
= netlogon_creds_cli_store(state
->context
,
2236 TALLOC_FREE(state
->creds
);
2237 if (tevent_req_nterror(req
, status
)) {
2238 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2242 tevent_req_done(req
);
2245 NTSTATUS
netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req
*req
)
2249 if (tevent_req_is_nterror(req
, &status
)) {
2250 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2251 tevent_req_received(req
);
2255 tevent_req_received(req
);
2256 return NT_STATUS_OK
;
2259 NTSTATUS
netlogon_creds_cli_ServerPasswordSet(
2260 struct netlogon_creds_cli_context
*context
,
2261 struct dcerpc_binding_handle
*b
,
2262 const DATA_BLOB
*new_password
,
2263 const uint32_t *new_version
)
2265 TALLOC_CTX
*frame
= talloc_stackframe();
2266 struct tevent_context
*ev
;
2267 struct tevent_req
*req
;
2268 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2270 ev
= samba_tevent_context_init(frame
);
2274 req
= netlogon_creds_cli_ServerPasswordSet_send(frame
, ev
, context
, b
,
2280 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2283 status
= netlogon_creds_cli_ServerPasswordSet_recv(req
);
2289 struct netlogon_creds_cli_LogonSamLogon_state
{
2290 struct tevent_context
*ev
;
2291 struct netlogon_creds_cli_context
*context
;
2292 struct dcerpc_binding_handle
*binding_handle
;
2294 char *srv_name_slash
;
2296 enum netr_LogonInfoClass logon_level
;
2297 const union netr_LogonLevel
*const_logon
;
2298 union netr_LogonLevel
*logon
;
2301 uint16_t validation_level
;
2302 union netr_Validation
*validation
;
2303 uint8_t authoritative
;
2306 * do we need encryption at the application layer?
2310 bool try_validation6
;
2313 * the read only credentials before we started the operation
2314 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2316 struct netlogon_creds_CredentialState
*ro_creds
;
2319 * The (locked) credentials used for the credential chain
2320 * used for netr_LogonSamLogonWithFlags() or
2321 * netr_LogonSamLogonWith().
2323 struct netlogon_creds_CredentialState
*lk_creds
;
2326 * While we have locked the global credentials (lk_creds above)
2327 * we operate an a temporary copy, because a server
2328 * may not support netr_LogonSamLogonWithFlags() and
2329 * didn't process our netr_Authenticator, so we need to
2330 * restart from lk_creds.
2332 struct netlogon_creds_CredentialState tmp_creds
;
2333 struct netr_Authenticator req_auth
;
2334 struct netr_Authenticator rep_auth
;
2337 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
);
2338 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2341 struct tevent_req
*netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX
*mem_ctx
,
2342 struct tevent_context
*ev
,
2343 struct netlogon_creds_cli_context
*context
,
2344 struct dcerpc_binding_handle
*b
,
2345 enum netr_LogonInfoClass logon_level
,
2346 const union netr_LogonLevel
*logon
,
2349 struct tevent_req
*req
;
2350 struct netlogon_creds_cli_LogonSamLogon_state
*state
;
2352 req
= tevent_req_create(mem_ctx
, &state
,
2353 struct netlogon_creds_cli_LogonSamLogon_state
);
2359 state
->context
= context
;
2360 state
->binding_handle
= b
;
2362 state
->logon_level
= logon_level
;
2363 state
->const_logon
= logon
;
2364 state
->flags
= flags
;
2366 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2367 context
->server
.computer
);
2368 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2369 return tevent_req_post(req
, ev
);
2372 switch (logon_level
) {
2373 case NetlogonInteractiveInformation
:
2374 case NetlogonInteractiveTransitiveInformation
:
2375 case NetlogonServiceInformation
:
2376 case NetlogonServiceTransitiveInformation
:
2377 case NetlogonGenericInformation
:
2378 state
->user_encrypt
= true;
2381 case NetlogonNetworkInformation
:
2382 case NetlogonNetworkTransitiveInformation
:
2386 state
->validation
= talloc_zero(state
, union netr_Validation
);
2387 if (tevent_req_nomem(state
->validation
, req
)) {
2388 return tevent_req_post(req
, ev
);
2391 netlogon_creds_cli_LogonSamLogon_start(req
);
2392 if (!tevent_req_is_in_progress(req
)) {
2393 return tevent_req_post(req
, ev
);
2397 * we defer all callbacks in order to cleanup
2398 * the database record.
2400 tevent_req_defer_callback(req
, state
->ev
);
2404 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2407 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2408 tevent_req_data(req
,
2409 struct netlogon_creds_cli_LogonSamLogon_state
);
2411 if (state
->lk_creds
== NULL
) {
2415 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2417 * This is a hack to recover from a bug in old
2418 * Samba servers, when LogonSamLogonEx() fails:
2420 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2422 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2424 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2425 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2426 * If the sign/seal check fails.
2428 * In that case we need to cleanup the netlogon session.
2430 * It's the job of the caller to disconnect the current
2431 * connection, if netlogon_creds_cli_LogonSamLogon()
2432 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2434 if (!state
->context
->server
.try_logon_with
) {
2435 status
= NT_STATUS_NETWORK_ACCESS_DENIED
;
2439 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2440 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2441 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2442 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2443 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2444 TALLOC_FREE(state
->lk_creds
);
2448 netlogon_creds_cli_delete(state
->context
, state
->lk_creds
);
2449 TALLOC_FREE(state
->lk_creds
);
2452 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
);
2454 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
)
2456 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2457 tevent_req_data(req
,
2458 struct netlogon_creds_cli_LogonSamLogon_state
);
2459 struct tevent_req
*subreq
;
2461 enum dcerpc_AuthType auth_type
;
2462 enum dcerpc_AuthLevel auth_level
;
2464 TALLOC_FREE(state
->ro_creds
);
2465 TALLOC_FREE(state
->logon
);
2466 ZERO_STRUCTP(state
->validation
);
2468 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2469 &auth_type
, &auth_level
);
2471 state
->try_logon_ex
= state
->context
->server
.try_logon_ex
;
2472 state
->try_validation6
= state
->context
->server
.try_validation6
;
2474 if (auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
2475 state
->try_logon_ex
= false;
2478 if (auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
2479 state
->try_validation6
= false;
2482 if (state
->try_logon_ex
) {
2483 if (state
->try_validation6
) {
2484 state
->validation_level
= 6;
2486 state
->validation_level
= 3;
2487 state
->user_encrypt
= true;
2490 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2492 state
->const_logon
);
2493 if (tevent_req_nomem(state
->logon
, req
)) {
2494 status
= NT_STATUS_NO_MEMORY
;
2495 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2499 if (state
->user_encrypt
) {
2500 status
= netlogon_creds_cli_get(state
->context
,
2503 if (!NT_STATUS_IS_OK(status
)) {
2504 status
= NT_STATUS_ACCESS_DENIED
;
2505 tevent_req_nterror(req
, status
);
2506 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2510 status
= netlogon_creds_encrypt_samlogon_logon(state
->ro_creds
,
2513 if (!NT_STATUS_IS_OK(status
)) {
2514 status
= NT_STATUS_ACCESS_DENIED
;
2515 tevent_req_nterror(req
, status
);
2516 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2521 subreq
= dcerpc_netr_LogonSamLogonEx_send(state
, state
->ev
,
2522 state
->binding_handle
,
2523 state
->srv_name_slash
,
2524 state
->context
->client
.computer
,
2527 state
->validation_level
,
2529 &state
->authoritative
,
2531 if (tevent_req_nomem(subreq
, req
)) {
2532 status
= NT_STATUS_NO_MEMORY
;
2533 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2536 tevent_req_set_callback(subreq
,
2537 netlogon_creds_cli_LogonSamLogon_done
,
2542 if (state
->lk_creds
== NULL
) {
2543 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2545 if (tevent_req_nomem(subreq
, req
)) {
2546 status
= NT_STATUS_NO_MEMORY
;
2547 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2550 tevent_req_set_callback(subreq
,
2551 netlogon_creds_cli_LogonSamLogon_done
,
2556 state
->tmp_creds
= *state
->lk_creds
;
2557 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2559 if (tevent_req_nterror(req
, status
)) {
2560 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2563 ZERO_STRUCT(state
->rep_auth
);
2565 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2567 state
->const_logon
);
2568 if (tevent_req_nomem(state
->logon
, req
)) {
2569 status
= NT_STATUS_NO_MEMORY
;
2570 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2574 status
= netlogon_creds_encrypt_samlogon_logon(&state
->tmp_creds
,
2577 if (tevent_req_nterror(req
, status
)) {
2578 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2582 state
->validation_level
= 3;
2584 if (state
->context
->server
.try_logon_with
) {
2585 subreq
= dcerpc_netr_LogonSamLogonWithFlags_send(state
, state
->ev
,
2586 state
->binding_handle
,
2587 state
->srv_name_slash
,
2588 state
->context
->client
.computer
,
2593 state
->validation_level
,
2595 &state
->authoritative
,
2597 if (tevent_req_nomem(subreq
, req
)) {
2598 status
= NT_STATUS_NO_MEMORY
;
2599 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2605 subreq
= dcerpc_netr_LogonSamLogon_send(state
, state
->ev
,
2606 state
->binding_handle
,
2607 state
->srv_name_slash
,
2608 state
->context
->client
.computer
,
2613 state
->validation_level
,
2615 &state
->authoritative
);
2616 if (tevent_req_nomem(subreq
, req
)) {
2617 status
= NT_STATUS_NO_MEMORY
;
2618 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2623 tevent_req_set_callback(subreq
,
2624 netlogon_creds_cli_LogonSamLogon_done
,
2628 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
)
2630 struct tevent_req
*req
=
2631 tevent_req_callback_data(subreq
,
2633 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2634 tevent_req_data(req
,
2635 struct netlogon_creds_cli_LogonSamLogon_state
);
2640 if (state
->try_logon_ex
) {
2641 status
= dcerpc_netr_LogonSamLogonEx_recv(subreq
,
2644 TALLOC_FREE(subreq
);
2645 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2646 state
->context
->server
.try_validation6
= false;
2647 state
->context
->server
.try_logon_ex
= false;
2648 netlogon_creds_cli_LogonSamLogon_start(req
);
2651 if (tevent_req_nterror(req
, status
)) {
2652 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2656 if ((state
->validation_level
== 6) &&
2657 (NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_INFO_CLASS
) ||
2658 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_PARAMETER
) ||
2659 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
)))
2661 state
->context
->server
.try_validation6
= false;
2662 netlogon_creds_cli_LogonSamLogon_start(req
);
2666 if (tevent_req_nterror(req
, result
)) {
2667 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2671 if (state
->ro_creds
== NULL
) {
2672 tevent_req_done(req
);
2676 ok
= netlogon_creds_cli_validate(state
->context
, state
->ro_creds
);
2679 * We got a race, lets retry with on authenticator
2682 * netlogon_creds_cli_LogonSamLogon_start()
2683 * will TALLOC_FREE(state->ro_creds);
2685 state
->try_logon_ex
= false;
2686 netlogon_creds_cli_LogonSamLogon_start(req
);
2690 status
= netlogon_creds_decrypt_samlogon_validation(state
->ro_creds
,
2691 state
->validation_level
,
2693 if (tevent_req_nterror(req
, status
)) {
2694 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2698 tevent_req_done(req
);
2702 if (state
->lk_creds
== NULL
) {
2703 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2705 TALLOC_FREE(subreq
);
2706 if (tevent_req_nterror(req
, status
)) {
2707 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2711 netlogon_creds_cli_LogonSamLogon_start(req
);
2715 if (state
->context
->server
.try_logon_with
) {
2716 status
= dcerpc_netr_LogonSamLogonWithFlags_recv(subreq
,
2719 TALLOC_FREE(subreq
);
2720 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2721 state
->context
->server
.try_logon_with
= false;
2722 netlogon_creds_cli_LogonSamLogon_start(req
);
2725 if (tevent_req_nterror(req
, status
)) {
2726 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2730 status
= dcerpc_netr_LogonSamLogon_recv(subreq
,
2733 TALLOC_FREE(subreq
);
2734 if (tevent_req_nterror(req
, status
)) {
2735 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2740 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
2741 &state
->rep_auth
.cred
);
2743 status
= NT_STATUS_ACCESS_DENIED
;
2744 tevent_req_nterror(req
, status
);
2745 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2749 *state
->lk_creds
= state
->tmp_creds
;
2750 status
= netlogon_creds_cli_store(state
->context
,
2752 TALLOC_FREE(state
->lk_creds
);
2754 if (tevent_req_nterror(req
, status
)) {
2755 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2759 if (tevent_req_nterror(req
, result
)) {
2760 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2764 status
= netlogon_creds_decrypt_samlogon_validation(&state
->tmp_creds
,
2765 state
->validation_level
,
2767 if (tevent_req_nterror(req
, status
)) {
2768 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2772 tevent_req_done(req
);
2775 NTSTATUS
netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req
*req
,
2776 TALLOC_CTX
*mem_ctx
,
2777 uint16_t *validation_level
,
2778 union netr_Validation
**validation
,
2779 uint8_t *authoritative
,
2782 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2783 tevent_req_data(req
,
2784 struct netlogon_creds_cli_LogonSamLogon_state
);
2787 /* authoritative is also returned on error */
2788 *authoritative
= state
->authoritative
;
2790 if (tevent_req_is_nterror(req
, &status
)) {
2791 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2792 tevent_req_received(req
);
2796 *validation_level
= state
->validation_level
;
2797 *validation
= talloc_move(mem_ctx
, &state
->validation
);
2798 *flags
= state
->flags
;
2800 tevent_req_received(req
);
2801 return NT_STATUS_OK
;
2804 NTSTATUS
netlogon_creds_cli_LogonSamLogon(
2805 struct netlogon_creds_cli_context
*context
,
2806 struct dcerpc_binding_handle
*b
,
2807 enum netr_LogonInfoClass logon_level
,
2808 const union netr_LogonLevel
*logon
,
2809 TALLOC_CTX
*mem_ctx
,
2810 uint16_t *validation_level
,
2811 union netr_Validation
**validation
,
2812 uint8_t *authoritative
,
2815 TALLOC_CTX
*frame
= talloc_stackframe();
2816 struct tevent_context
*ev
;
2817 struct tevent_req
*req
;
2818 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2820 ev
= samba_tevent_context_init(frame
);
2824 req
= netlogon_creds_cli_LogonSamLogon_send(frame
, ev
, context
, b
,
2830 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2833 status
= netlogon_creds_cli_LogonSamLogon_recv(req
, mem_ctx
,
2843 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
{
2844 struct tevent_context
*ev
;
2845 struct netlogon_creds_cli_context
*context
;
2846 struct dcerpc_binding_handle
*binding_handle
;
2848 char *srv_name_slash
;
2849 enum dcerpc_AuthType auth_type
;
2850 enum dcerpc_AuthLevel auth_level
;
2852 const char *site_name
;
2854 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
;
2856 struct netlogon_creds_CredentialState
*creds
;
2857 struct netlogon_creds_CredentialState tmp_creds
;
2858 struct netr_Authenticator req_auth
;
2859 struct netr_Authenticator rep_auth
;
2862 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
2864 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
);
2866 struct tevent_req
*netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX
*mem_ctx
,
2867 struct tevent_context
*ev
,
2868 struct netlogon_creds_cli_context
*context
,
2869 struct dcerpc_binding_handle
*b
,
2870 const char *site_name
,
2872 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
2874 struct tevent_req
*req
;
2875 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
;
2876 struct tevent_req
*subreq
;
2878 req
= tevent_req_create(mem_ctx
, &state
,
2879 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2885 state
->context
= context
;
2886 state
->binding_handle
= b
;
2888 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2889 context
->server
.computer
);
2890 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2891 return tevent_req_post(req
, ev
);
2894 state
->site_name
= site_name
;
2895 state
->dns_ttl
= dns_ttl
;
2896 state
->dns_names
= dns_names
;
2898 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2900 &state
->auth_level
);
2902 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2904 if (tevent_req_nomem(subreq
, req
)) {
2905 return tevent_req_post(req
, ev
);
2908 tevent_req_set_callback(subreq
,
2909 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked
,
2915 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
2918 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
2919 tevent_req_data(req
,
2920 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2922 if (state
->creds
== NULL
) {
2926 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2927 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2928 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2929 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2930 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2931 TALLOC_FREE(state
->creds
);
2935 netlogon_creds_cli_delete(state
->context
, state
->creds
);
2936 TALLOC_FREE(state
->creds
);
2939 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
);
2941 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
)
2943 struct tevent_req
*req
=
2944 tevent_req_callback_data(subreq
,
2946 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
2947 tevent_req_data(req
,
2948 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2951 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2953 TALLOC_FREE(subreq
);
2954 if (tevent_req_nterror(req
, status
)) {
2958 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
2959 switch (state
->auth_level
) {
2960 case DCERPC_AUTH_LEVEL_INTEGRITY
:
2961 case DCERPC_AUTH_LEVEL_PRIVACY
:
2964 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2968 uint32_t tmp
= state
->creds
->negotiate_flags
;
2970 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
2972 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2973 * it should be used, which means
2974 * we had a chance to verify no downgrade
2977 * This relies on netlogon_creds_cli_check*
2978 * being called before, as first request after
2981 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2987 * we defer all callbacks in order to cleanup
2988 * the database record.
2990 tevent_req_defer_callback(req
, state
->ev
);
2992 state
->tmp_creds
= *state
->creds
;
2993 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2995 if (tevent_req_nterror(req
, status
)) {
2998 ZERO_STRUCT(state
->rep_auth
);
3000 subreq
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state
, state
->ev
,
3001 state
->binding_handle
,
3002 state
->srv_name_slash
,
3003 state
->tmp_creds
.computer_name
,
3009 if (tevent_req_nomem(subreq
, req
)) {
3010 status
= NT_STATUS_NO_MEMORY
;
3011 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3015 tevent_req_set_callback(subreq
,
3016 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done
,
3020 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
)
3022 struct tevent_req
*req
=
3023 tevent_req_callback_data(subreq
,
3025 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
3026 tevent_req_data(req
,
3027 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
3033 * We use state->dns_names as the memory context, as this is
3034 * the only in/out variable and it has been overwritten by the
3035 * out parameter from the server.
3037 * We need to preserve the return value until the caller can use it.
3039 status
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq
, state
->dns_names
,
3041 TALLOC_FREE(subreq
);
3042 if (tevent_req_nterror(req
, status
)) {
3043 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3047 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3048 &state
->rep_auth
.cred
);
3050 status
= NT_STATUS_ACCESS_DENIED
;
3051 tevent_req_nterror(req
, status
);
3052 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3056 *state
->creds
= state
->tmp_creds
;
3057 status
= netlogon_creds_cli_store(state
->context
,
3059 TALLOC_FREE(state
->creds
);
3061 if (tevent_req_nterror(req
, status
)) {
3062 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3066 if (tevent_req_nterror(req
, result
)) {
3067 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, result
);
3071 tevent_req_done(req
);
3074 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req
*req
)
3078 if (tevent_req_is_nterror(req
, &status
)) {
3079 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3080 tevent_req_received(req
);
3084 tevent_req_received(req
);
3085 return NT_STATUS_OK
;
3088 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3089 struct netlogon_creds_cli_context
*context
,
3090 struct dcerpc_binding_handle
*b
,
3091 const char *site_name
,
3093 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
3095 TALLOC_CTX
*frame
= talloc_stackframe();
3096 struct tevent_context
*ev
;
3097 struct tevent_req
*req
;
3098 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3100 ev
= samba_tevent_context_init(frame
);
3104 req
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame
, ev
, context
, b
,
3111 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3114 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req
);
3120 struct netlogon_creds_cli_ServerGetTrustInfo_state
{
3121 struct tevent_context
*ev
;
3122 struct netlogon_creds_cli_context
*context
;
3123 struct dcerpc_binding_handle
*binding_handle
;
3125 char *srv_name_slash
;
3126 enum dcerpc_AuthType auth_type
;
3127 enum dcerpc_AuthLevel auth_level
;
3129 struct samr_Password new_owf_password
;
3130 struct samr_Password old_owf_password
;
3131 struct netr_TrustInfo
*trust_info
;
3133 struct netlogon_creds_CredentialState
*creds
;
3134 struct netlogon_creds_CredentialState tmp_creds
;
3135 struct netr_Authenticator req_auth
;
3136 struct netr_Authenticator rep_auth
;
3139 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3141 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
);
3143 struct tevent_req
*netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX
*mem_ctx
,
3144 struct tevent_context
*ev
,
3145 struct netlogon_creds_cli_context
*context
,
3146 struct dcerpc_binding_handle
*b
)
3148 struct tevent_req
*req
;
3149 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
;
3150 struct tevent_req
*subreq
;
3152 req
= tevent_req_create(mem_ctx
, &state
,
3153 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3159 state
->context
= context
;
3160 state
->binding_handle
= b
;
3162 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3163 context
->server
.computer
);
3164 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3165 return tevent_req_post(req
, ev
);
3168 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3170 &state
->auth_level
);
3172 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3174 if (tevent_req_nomem(subreq
, req
)) {
3175 return tevent_req_post(req
, ev
);
3178 tevent_req_set_callback(subreq
,
3179 netlogon_creds_cli_ServerGetTrustInfo_locked
,
3185 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3188 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3189 tevent_req_data(req
,
3190 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3192 if (state
->creds
== NULL
) {
3196 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3197 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3198 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3199 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3200 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3201 TALLOC_FREE(state
->creds
);
3205 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3206 TALLOC_FREE(state
->creds
);
3209 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
);
3211 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
)
3213 struct tevent_req
*req
=
3214 tevent_req_callback_data(subreq
,
3216 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3217 tevent_req_data(req
,
3218 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3221 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3223 TALLOC_FREE(subreq
);
3224 if (tevent_req_nterror(req
, status
)) {
3228 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3229 switch (state
->auth_level
) {
3230 case DCERPC_AUTH_LEVEL_PRIVACY
:
3233 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3237 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3242 * we defer all callbacks in order to cleanup
3243 * the database record.
3245 tevent_req_defer_callback(req
, state
->ev
);
3247 state
->tmp_creds
= *state
->creds
;
3248 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3250 if (tevent_req_nterror(req
, status
)) {
3253 ZERO_STRUCT(state
->rep_auth
);
3255 subreq
= dcerpc_netr_ServerGetTrustInfo_send(state
, state
->ev
,
3256 state
->binding_handle
,
3257 state
->srv_name_slash
,
3258 state
->tmp_creds
.account_name
,
3259 state
->tmp_creds
.secure_channel_type
,
3260 state
->tmp_creds
.computer_name
,
3263 &state
->new_owf_password
,
3264 &state
->old_owf_password
,
3265 &state
->trust_info
);
3266 if (tevent_req_nomem(subreq
, req
)) {
3267 status
= NT_STATUS_NO_MEMORY
;
3268 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3272 tevent_req_set_callback(subreq
,
3273 netlogon_creds_cli_ServerGetTrustInfo_done
,
3277 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
)
3279 struct tevent_req
*req
=
3280 tevent_req_callback_data(subreq
,
3282 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3283 tevent_req_data(req
,
3284 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3287 const struct samr_Password zero
= {};
3292 * We use state->dns_names as the memory context, as this is
3293 * the only in/out variable and it has been overwritten by the
3294 * out parameter from the server.
3296 * We need to preserve the return value until the caller can use it.
3298 status
= dcerpc_netr_ServerGetTrustInfo_recv(subreq
, state
, &result
);
3299 TALLOC_FREE(subreq
);
3300 if (tevent_req_nterror(req
, status
)) {
3301 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3305 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3306 &state
->rep_auth
.cred
);
3308 status
= NT_STATUS_ACCESS_DENIED
;
3309 tevent_req_nterror(req
, status
);
3310 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3314 cmp
= mem_equal_const_time(state
->new_owf_password
.hash
,
3315 zero
.hash
, sizeof(zero
.hash
));
3317 status
= netlogon_creds_des_decrypt(&state
->tmp_creds
,
3318 &state
->new_owf_password
);
3319 if (tevent_req_nterror(req
, status
)) {
3320 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3324 cmp
= mem_equal_const_time(state
->old_owf_password
.hash
,
3325 zero
.hash
, sizeof(zero
.hash
));
3327 status
= netlogon_creds_des_decrypt(&state
->tmp_creds
,
3328 &state
->old_owf_password
);
3329 if (tevent_req_nterror(req
, status
)) {
3330 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3335 *state
->creds
= state
->tmp_creds
;
3336 status
= netlogon_creds_cli_store(state
->context
,
3338 TALLOC_FREE(state
->creds
);
3339 if (tevent_req_nterror(req
, status
)) {
3340 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3344 if (tevent_req_nterror(req
, result
)) {
3345 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, result
);
3349 tevent_req_done(req
);
3352 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req
*req
,
3353 TALLOC_CTX
*mem_ctx
,
3354 struct samr_Password
*new_owf_password
,
3355 struct samr_Password
*old_owf_password
,
3356 struct netr_TrustInfo
**trust_info
)
3358 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3359 tevent_req_data(req
,
3360 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3363 if (tevent_req_is_nterror(req
, &status
)) {
3364 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3365 tevent_req_received(req
);
3369 if (new_owf_password
!= NULL
) {
3370 *new_owf_password
= state
->new_owf_password
;
3372 if (old_owf_password
!= NULL
) {
3373 *old_owf_password
= state
->old_owf_password
;
3375 if (trust_info
!= NULL
) {
3376 *trust_info
= talloc_move(mem_ctx
, &state
->trust_info
);
3379 tevent_req_received(req
);
3380 return NT_STATUS_OK
;
3383 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo(
3384 struct netlogon_creds_cli_context
*context
,
3385 struct dcerpc_binding_handle
*b
,
3386 TALLOC_CTX
*mem_ctx
,
3387 struct samr_Password
*new_owf_password
,
3388 struct samr_Password
*old_owf_password
,
3389 struct netr_TrustInfo
**trust_info
)
3391 TALLOC_CTX
*frame
= talloc_stackframe();
3392 struct tevent_context
*ev
;
3393 struct tevent_req
*req
;
3394 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3396 ev
= samba_tevent_context_init(frame
);
3400 req
= netlogon_creds_cli_ServerGetTrustInfo_send(frame
, ev
, context
, b
);
3404 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3407 status
= netlogon_creds_cli_ServerGetTrustInfo_recv(req
,
3417 struct netlogon_creds_cli_GetForestTrustInformation_state
{
3418 struct tevent_context
*ev
;
3419 struct netlogon_creds_cli_context
*context
;
3420 struct dcerpc_binding_handle
*binding_handle
;
3422 char *srv_name_slash
;
3423 enum dcerpc_AuthType auth_type
;
3424 enum dcerpc_AuthLevel auth_level
;
3427 struct lsa_ForestTrustInformation
*forest_trust_info
;
3429 struct netlogon_creds_CredentialState
*creds
;
3430 struct netlogon_creds_CredentialState tmp_creds
;
3431 struct netr_Authenticator req_auth
;
3432 struct netr_Authenticator rep_auth
;
3435 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3437 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
);
3439 struct tevent_req
*netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX
*mem_ctx
,
3440 struct tevent_context
*ev
,
3441 struct netlogon_creds_cli_context
*context
,
3442 struct dcerpc_binding_handle
*b
)
3444 struct tevent_req
*req
;
3445 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
;
3446 struct tevent_req
*subreq
;
3448 req
= tevent_req_create(mem_ctx
, &state
,
3449 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3455 state
->context
= context
;
3456 state
->binding_handle
= b
;
3458 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3459 context
->server
.computer
);
3460 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3461 return tevent_req_post(req
, ev
);
3466 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3468 &state
->auth_level
);
3470 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3472 if (tevent_req_nomem(subreq
, req
)) {
3473 return tevent_req_post(req
, ev
);
3476 tevent_req_set_callback(subreq
,
3477 netlogon_creds_cli_GetForestTrustInformation_locked
,
3483 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3486 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3487 tevent_req_data(req
,
3488 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3490 if (state
->creds
== NULL
) {
3494 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3495 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3496 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3497 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3498 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3499 TALLOC_FREE(state
->creds
);
3503 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3504 TALLOC_FREE(state
->creds
);
3507 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
);
3509 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
)
3511 struct tevent_req
*req
=
3512 tevent_req_callback_data(subreq
,
3514 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3515 tevent_req_data(req
,
3516 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3519 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3521 TALLOC_FREE(subreq
);
3522 if (tevent_req_nterror(req
, status
)) {
3526 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3527 switch (state
->auth_level
) {
3528 case DCERPC_AUTH_LEVEL_INTEGRITY
:
3529 case DCERPC_AUTH_LEVEL_PRIVACY
:
3532 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3536 uint32_t tmp
= state
->creds
->negotiate_flags
;
3538 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
3540 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3541 * it should be used, which means
3542 * we had a chance to verify no downgrade
3545 * This relies on netlogon_creds_cli_check*
3546 * being called before, as first request after
3549 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3555 * we defer all callbacks in order to cleanup
3556 * the database record.
3558 tevent_req_defer_callback(req
, state
->ev
);
3560 state
->tmp_creds
= *state
->creds
;
3561 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3563 if (tevent_req_nterror(req
, status
)) {
3566 ZERO_STRUCT(state
->rep_auth
);
3568 subreq
= dcerpc_netr_GetForestTrustInformation_send(state
, state
->ev
,
3569 state
->binding_handle
,
3570 state
->srv_name_slash
,
3571 state
->tmp_creds
.computer_name
,
3575 &state
->forest_trust_info
);
3576 if (tevent_req_nomem(subreq
, req
)) {
3577 status
= NT_STATUS_NO_MEMORY
;
3578 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3582 tevent_req_set_callback(subreq
,
3583 netlogon_creds_cli_GetForestTrustInformation_done
,
3587 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
)
3589 struct tevent_req
*req
=
3590 tevent_req_callback_data(subreq
,
3592 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3593 tevent_req_data(req
,
3594 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3600 * We use state->dns_names as the memory context, as this is
3601 * the only in/out variable and it has been overwritten by the
3602 * out parameter from the server.
3604 * We need to preserve the return value until the caller can use it.
3606 status
= dcerpc_netr_GetForestTrustInformation_recv(subreq
, state
, &result
);
3607 TALLOC_FREE(subreq
);
3608 if (tevent_req_nterror(req
, status
)) {
3609 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3613 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3614 &state
->rep_auth
.cred
);
3616 status
= NT_STATUS_ACCESS_DENIED
;
3617 tevent_req_nterror(req
, status
);
3618 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3622 *state
->creds
= state
->tmp_creds
;
3623 status
= netlogon_creds_cli_store(state
->context
,
3625 TALLOC_FREE(state
->creds
);
3627 if (tevent_req_nterror(req
, status
)) {
3628 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3632 if (tevent_req_nterror(req
, result
)) {
3633 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, result
);
3637 tevent_req_done(req
);
3640 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req
*req
,
3641 TALLOC_CTX
*mem_ctx
,
3642 struct lsa_ForestTrustInformation
**forest_trust_info
)
3644 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3645 tevent_req_data(req
,
3646 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3649 if (tevent_req_is_nterror(req
, &status
)) {
3650 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3651 tevent_req_received(req
);
3655 *forest_trust_info
= talloc_move(mem_ctx
, &state
->forest_trust_info
);
3657 tevent_req_received(req
);
3658 return NT_STATUS_OK
;
3661 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation(
3662 struct netlogon_creds_cli_context
*context
,
3663 struct dcerpc_binding_handle
*b
,
3664 TALLOC_CTX
*mem_ctx
,
3665 struct lsa_ForestTrustInformation
**forest_trust_info
)
3667 TALLOC_CTX
*frame
= talloc_stackframe();
3668 struct tevent_context
*ev
;
3669 struct tevent_req
*req
;
3670 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3672 ev
= samba_tevent_context_init(frame
);
3676 req
= netlogon_creds_cli_GetForestTrustInformation_send(frame
, ev
, context
, b
);
3680 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3683 status
= netlogon_creds_cli_GetForestTrustInformation_recv(req
,
3690 struct netlogon_creds_cli_SendToSam_state
{
3691 struct tevent_context
*ev
;
3692 struct netlogon_creds_cli_context
*context
;
3693 struct dcerpc_binding_handle
*binding_handle
;
3695 char *srv_name_slash
;
3696 enum dcerpc_AuthType auth_type
;
3697 enum dcerpc_AuthLevel auth_level
;
3701 struct netlogon_creds_CredentialState
*creds
;
3702 struct netlogon_creds_CredentialState tmp_creds
;
3703 struct netr_Authenticator req_auth
;
3704 struct netr_Authenticator rep_auth
;
3707 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3709 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
);
3711 struct tevent_req
*netlogon_creds_cli_SendToSam_send(TALLOC_CTX
*mem_ctx
,
3712 struct tevent_context
*ev
,
3713 struct netlogon_creds_cli_context
*context
,
3714 struct dcerpc_binding_handle
*b
,
3715 struct netr_SendToSamBase
*message
)
3717 struct tevent_req
*req
;
3718 struct netlogon_creds_cli_SendToSam_state
*state
;
3719 struct tevent_req
*subreq
;
3720 enum ndr_err_code ndr_err
;
3722 req
= tevent_req_create(mem_ctx
, &state
,
3723 struct netlogon_creds_cli_SendToSam_state
);
3729 state
->context
= context
;
3730 state
->binding_handle
= b
;
3732 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3733 context
->server
.computer
);
3734 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3735 return tevent_req_post(req
, ev
);
3738 ndr_err
= ndr_push_struct_blob(&state
->opaque
, mem_ctx
, message
,
3739 (ndr_push_flags_fn_t
)ndr_push_netr_SendToSamBase
);
3740 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
3741 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
3742 tevent_req_nterror(req
, status
);
3743 return tevent_req_post(req
, ev
);
3746 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3748 &state
->auth_level
);
3750 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3752 if (tevent_req_nomem(subreq
, req
)) {
3753 return tevent_req_post(req
, ev
);
3756 tevent_req_set_callback(subreq
,
3757 netlogon_creds_cli_SendToSam_locked
,
3763 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3766 struct netlogon_creds_cli_SendToSam_state
*state
=
3767 tevent_req_data(req
,
3768 struct netlogon_creds_cli_SendToSam_state
);
3770 if (state
->creds
== NULL
) {
3774 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3775 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3776 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3777 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3778 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3779 TALLOC_FREE(state
->creds
);
3783 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3784 TALLOC_FREE(state
->creds
);
3787 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
);
3789 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
)
3791 struct tevent_req
*req
=
3792 tevent_req_callback_data(subreq
,
3794 struct netlogon_creds_cli_SendToSam_state
*state
=
3795 tevent_req_data(req
,
3796 struct netlogon_creds_cli_SendToSam_state
);
3799 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3801 TALLOC_FREE(subreq
);
3802 if (tevent_req_nterror(req
, status
)) {
3806 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3807 switch (state
->auth_level
) {
3808 case DCERPC_AUTH_LEVEL_INTEGRITY
:
3809 case DCERPC_AUTH_LEVEL_PRIVACY
:
3812 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3816 uint32_t tmp
= state
->creds
->negotiate_flags
;
3818 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
3820 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3821 * it should be used, which means
3822 * we had a chance to verify no downgrade
3825 * This relies on netlogon_creds_cli_check*
3826 * being called before, as first request after
3829 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3835 * we defer all callbacks in order to cleanup
3836 * the database record.
3838 tevent_req_defer_callback(req
, state
->ev
);
3840 state
->tmp_creds
= *state
->creds
;
3841 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3843 if (tevent_req_nterror(req
, status
)) {
3846 ZERO_STRUCT(state
->rep_auth
);
3848 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
3849 status
= netlogon_creds_aes_encrypt(&state
->tmp_creds
,
3851 state
->opaque
.length
);
3852 if (tevent_req_nterror(req
, status
)) {
3853 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3857 status
= netlogon_creds_arcfour_crypt(&state
->tmp_creds
,
3859 state
->opaque
.length
);
3860 if (tevent_req_nterror(req
, status
)) {
3861 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3866 subreq
= dcerpc_netr_NetrLogonSendToSam_send(state
, state
->ev
,
3867 state
->binding_handle
,
3868 state
->srv_name_slash
,
3869 state
->tmp_creds
.computer_name
,
3873 state
->opaque
.length
);
3874 if (tevent_req_nomem(subreq
, req
)) {
3875 status
= NT_STATUS_NO_MEMORY
;
3876 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3880 tevent_req_set_callback(subreq
,
3881 netlogon_creds_cli_SendToSam_done
,
3885 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
)
3887 struct tevent_req
*req
=
3888 tevent_req_callback_data(subreq
,
3890 struct netlogon_creds_cli_SendToSam_state
*state
=
3891 tevent_req_data(req
,
3892 struct netlogon_creds_cli_SendToSam_state
);
3897 status
= dcerpc_netr_NetrLogonSendToSam_recv(subreq
, state
, &result
);
3898 TALLOC_FREE(subreq
);
3899 if (tevent_req_nterror(req
, status
)) {
3900 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3904 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3905 &state
->rep_auth
.cred
);
3907 status
= NT_STATUS_ACCESS_DENIED
;
3908 tevent_req_nterror(req
, status
);
3909 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3913 *state
->creds
= state
->tmp_creds
;
3914 status
= netlogon_creds_cli_store(state
->context
,
3916 TALLOC_FREE(state
->creds
);
3918 if (tevent_req_nterror(req
, status
)) {
3919 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3924 * Creds must be stored before we send back application errors
3925 * e.g. NT_STATUS_NOT_IMPLEMENTED
3927 if (tevent_req_nterror(req
, result
)) {
3928 netlogon_creds_cli_SendToSam_cleanup(req
, result
);
3932 tevent_req_done(req
);
3935 NTSTATUS
netlogon_creds_cli_SendToSam_recv(struct tevent_req
*req
)
3939 if (tevent_req_is_nterror(req
, &status
)) {
3940 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3941 tevent_req_received(req
);
3945 tevent_req_received(req
);
3946 return NT_STATUS_OK
;
3949 NTSTATUS
netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context
*context
,
3950 struct dcerpc_binding_handle
*b
,
3951 struct netr_SendToSamBase
*message
)
3953 TALLOC_CTX
*frame
= talloc_stackframe();
3954 struct tevent_context
*ev
;
3955 struct tevent_req
*req
;
3956 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3958 ev
= samba_tevent_context_init(frame
);
3962 req
= netlogon_creds_cli_SendToSam_send(frame
, ev
, context
, b
, message
);
3966 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3969 status
= netlogon_creds_cli_SendToSam_recv(req
);
3975 struct netlogon_creds_cli_LogonGetDomainInfo_state
{
3976 struct tevent_context
*ev
;
3977 struct netlogon_creds_cli_context
*context
;
3978 struct dcerpc_binding_handle
*binding_handle
;
3980 char *srv_name_slash
;
3981 enum dcerpc_AuthType auth_type
;
3982 enum dcerpc_AuthLevel auth_level
;
3985 union netr_WorkstationInfo
*query
;
3986 union netr_DomainInfo
*info
;
3988 struct netlogon_creds_CredentialState
*creds
;
3989 struct netlogon_creds_CredentialState tmp_creds
;
3990 struct netr_Authenticator req_auth
;
3991 struct netr_Authenticator rep_auth
;
3994 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
3996 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
);
3998 struct tevent_req
*netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX
*mem_ctx
,
3999 struct tevent_context
*ev
,
4000 struct netlogon_creds_cli_context
*context
,
4001 struct dcerpc_binding_handle
*b
,
4003 union netr_WorkstationInfo
*query
)
4005 struct tevent_req
*req
;
4006 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
;
4007 struct tevent_req
*subreq
;
4009 req
= tevent_req_create(mem_ctx
, &state
,
4010 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4016 state
->context
= context
;
4017 state
->binding_handle
= b
;
4019 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
4020 context
->server
.computer
);
4021 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
4022 return tevent_req_post(req
, ev
);
4025 state
->level
= level
;
4026 state
->query
= query
;
4027 state
->info
= talloc_zero(state
, union netr_DomainInfo
);
4028 if (tevent_req_nomem(state
->info
, req
)) {
4029 return tevent_req_post(req
, ev
);
4032 dcerpc_binding_handle_auth_info(state
->binding_handle
,
4034 &state
->auth_level
);
4036 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
4038 if (tevent_req_nomem(subreq
, req
)) {
4039 return tevent_req_post(req
, ev
);
4042 tevent_req_set_callback(subreq
,
4043 netlogon_creds_cli_LogonGetDomainInfo_locked
,
4049 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
4052 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4053 tevent_req_data(req
,
4054 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4056 if (state
->creds
== NULL
) {
4060 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
4061 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
4062 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
4063 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
4064 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
4065 TALLOC_FREE(state
->creds
);
4069 netlogon_creds_cli_delete(state
->context
, state
->creds
);
4072 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
);
4074 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
)
4076 struct tevent_req
*req
=
4077 tevent_req_callback_data(subreq
,
4079 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4080 tevent_req_data(req
,
4081 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4084 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
4086 TALLOC_FREE(subreq
);
4087 if (tevent_req_nterror(req
, status
)) {
4091 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
4092 switch (state
->auth_level
) {
4093 case DCERPC_AUTH_LEVEL_INTEGRITY
:
4094 case DCERPC_AUTH_LEVEL_PRIVACY
:
4097 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
4101 uint32_t tmp
= state
->creds
->negotiate_flags
;
4103 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
4105 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
4106 * it should be used, which means
4107 * we had a chance to verify no downgrade
4110 * This relies on netlogon_creds_cli_check*
4111 * being called before, as first request after
4114 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
4120 * we defer all callbacks in order to cleanup
4121 * the database record.
4123 tevent_req_defer_callback(req
, state
->ev
);
4125 state
->tmp_creds
= *state
->creds
;
4126 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
4128 if (tevent_req_nterror(req
, status
)) {
4131 ZERO_STRUCT(state
->rep_auth
);
4133 subreq
= dcerpc_netr_LogonGetDomainInfo_send(state
, state
->ev
,
4134 state
->binding_handle
,
4135 state
->srv_name_slash
,
4136 state
->tmp_creds
.computer_name
,
4142 if (tevent_req_nomem(subreq
, req
)) {
4143 status
= NT_STATUS_NO_MEMORY
;
4144 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4148 tevent_req_set_callback(subreq
,
4149 netlogon_creds_cli_LogonGetDomainInfo_done
,
4153 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
)
4155 struct tevent_req
*req
=
4156 tevent_req_callback_data(subreq
,
4158 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4159 tevent_req_data(req
,
4160 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4166 * We use state->dns_names as the memory context, as this is
4167 * the only in/out variable and it has been overwritten by the
4168 * out parameter from the server.
4170 * We need to preserve the return value until the caller can use it.
4172 status
= dcerpc_netr_LogonGetDomainInfo_recv(subreq
, state
->info
, &result
);
4173 TALLOC_FREE(subreq
);
4174 if (tevent_req_nterror(req
, status
)) {
4175 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4179 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
4180 &state
->rep_auth
.cred
);
4182 status
= NT_STATUS_ACCESS_DENIED
;
4183 tevent_req_nterror(req
, status
);
4184 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4188 if (tevent_req_nterror(req
, result
)) {
4189 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, result
);
4193 *state
->creds
= state
->tmp_creds
;
4194 status
= netlogon_creds_cli_store(state
->context
,
4196 if (tevent_req_nterror(req
, status
)) {
4197 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4201 tevent_req_done(req
);
4204 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req
*req
,
4205 TALLOC_CTX
*mem_ctx
,
4206 union netr_DomainInfo
**info
)
4208 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4209 tevent_req_data(req
,
4210 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4213 if (tevent_req_is_nterror(req
, &status
)) {
4214 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4215 tevent_req_received(req
);
4219 *info
= talloc_move(mem_ctx
, &state
->info
);
4221 tevent_req_received(req
);
4222 return NT_STATUS_OK
;
4225 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo(
4226 struct netlogon_creds_cli_context
*context
,
4227 struct dcerpc_binding_handle
*b
,
4228 TALLOC_CTX
*mem_ctx
,
4230 union netr_WorkstationInfo
*query
,
4231 union netr_DomainInfo
**info
)
4233 TALLOC_CTX
*frame
= talloc_stackframe();
4234 struct tevent_context
*ev
;
4235 struct tevent_req
*req
;
4236 NTSTATUS status
= NT_STATUS_OK
;
4238 ev
= samba_tevent_context_init(frame
);
4242 req
= netlogon_creds_cli_LogonGetDomainInfo_send(frame
, ev
, context
, b
,
4247 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4250 status
= netlogon_creds_cli_LogonGetDomainInfo_recv(req
,