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_SUPPORTS_AES
;
508 proposed_flags
|= required_flags
;
510 if (required_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
511 required_flags
&= ~NETLOGON_NEG_ARCFOUR
;
512 required_flags
&= ~NETLOGON_NEG_STRONG_KEYS
;
515 if (seal_secure_channel
) {
516 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
518 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
521 if (server_dns_domain
== NULL
) {
522 server_dns_domain
= "";
525 status
= netlogon_creds_cli_context_common(client_computer
,
532 server_netbios_domain
,
536 if (!NT_STATUS_IS_OK(status
)) {
541 context
->db
.g_ctx
= g_lock_ctx_init(context
, msg_ctx
);
542 if (context
->db
.g_ctx
== NULL
) {
543 TALLOC_FREE(context
);
545 return NT_STATUS_NO_MEMORY
;
548 status
= netlogon_creds_cli_open_global_db(lp_ctx
);
549 if (!NT_STATUS_IS_OK(status
)) {
550 TALLOC_FREE(context
);
552 return NT_STATUS_NO_MEMORY
;
555 context
->db
.ctx
= netlogon_creds_cli_global_db
;
561 NTSTATUS
netlogon_creds_bind_cli_credentials(
562 struct netlogon_creds_cli_context
*context
, TALLOC_CTX
*mem_ctx
,
563 struct cli_credentials
**pcli_creds
)
565 struct cli_credentials
*cli_creds
;
566 struct netlogon_creds_CredentialState
*ncreds
;
569 cli_creds
= cli_credentials_init(mem_ctx
);
570 if (cli_creds
== NULL
) {
571 return NT_STATUS_NO_MEMORY
;
573 cli_credentials_set_secure_channel_type(cli_creds
,
574 context
->client
.type
);
575 cli_credentials_set_username(cli_creds
, context
->client
.account
,
577 cli_credentials_set_domain(cli_creds
, context
->server
.netbios_domain
,
579 cli_credentials_set_realm(cli_creds
, context
->server
.dns_domain
,
582 status
= netlogon_creds_cli_get(context
, cli_creds
, &ncreds
);
583 if (!NT_STATUS_IS_OK(status
)) {
584 TALLOC_FREE(cli_creds
);
587 cli_credentials_set_netlogon_creds(cli_creds
, ncreds
);
589 *pcli_creds
= cli_creds
;
593 char *netlogon_creds_cli_debug_string(
594 const struct netlogon_creds_cli_context
*context
,
597 return talloc_asprintf(mem_ctx
, "netlogon_creds_cli:%s",
598 context
->db
.key_name
);
601 enum dcerpc_AuthLevel
netlogon_creds_cli_auth_level(
602 struct netlogon_creds_cli_context
*context
)
604 return context
->client
.auth_level
;
607 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags
,
608 uint32_t proposed_flags
,
609 uint32_t required_flags
)
611 uint32_t req_flags
= required_flags
;
614 req_flags
= required_flags
;
615 if ((negotiated_flags
& NETLOGON_NEG_SUPPORTS_AES
) &&
616 (proposed_flags
& NETLOGON_NEG_SUPPORTS_AES
))
618 req_flags
&= ~NETLOGON_NEG_ARCFOUR
|NETLOGON_NEG_STRONG_KEYS
;
621 tmp_flags
= negotiated_flags
;
622 tmp_flags
&= req_flags
;
623 if (tmp_flags
!= req_flags
) {
630 struct netlogon_creds_cli_fetch_state
{
632 struct netlogon_creds_CredentialState
*creds
;
633 uint32_t proposed_flags
;
634 uint32_t required_flags
;
638 static void netlogon_creds_cli_fetch_parser(TDB_DATA key
, TDB_DATA data
,
641 struct netlogon_creds_cli_fetch_state
*state
=
642 (struct netlogon_creds_cli_fetch_state
*)private_data
;
643 enum ndr_err_code ndr_err
;
647 state
->creds
= talloc_zero(state
->mem_ctx
,
648 struct netlogon_creds_CredentialState
);
649 if (state
->creds
== NULL
) {
650 state
->status
= NT_STATUS_NO_MEMORY
;
654 blob
.data
= data
.dptr
;
655 blob
.length
= data
.dsize
;
657 ndr_err
= ndr_pull_struct_blob(&blob
, state
->creds
, state
->creds
,
658 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
659 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
660 TALLOC_FREE(state
->creds
);
661 state
->status
= ndr_map_error2ntstatus(ndr_err
);
665 if (DEBUGLEVEL
>= 10) {
666 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, state
->creds
);
669 if (state
->proposed_flags
!= state
->creds
->client_requested_flags
) {
670 TALLOC_FREE(state
->creds
);
671 state
->status
= NT_STATUS_RESOURCE_REQUIREMENTS_CHANGED
;
675 downgraded
= netlogon_creds_cli_downgraded(
676 state
->creds
->negotiate_flags
,
677 state
->proposed_flags
,
678 state
->required_flags
);
680 TALLOC_FREE(state
->creds
);
681 state
->status
= NT_STATUS_DOWNGRADE_DETECTED
;
685 state
->status
= NT_STATUS_OK
;
688 static NTSTATUS
netlogon_creds_cli_get_internal(
689 struct netlogon_creds_cli_context
*context
,
690 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
);
692 NTSTATUS
netlogon_creds_cli_get(struct netlogon_creds_cli_context
*context
,
694 struct netlogon_creds_CredentialState
**_creds
)
697 struct netlogon_creds_CredentialState
*creds
;
701 status
= netlogon_creds_cli_get_internal(context
, mem_ctx
, &creds
);
702 if (!NT_STATUS_IS_OK(status
)) {
707 * mark it as invalid for step operations.
710 creds
->seed
= (struct netr_Credential
) {{0}};
711 creds
->client
= (struct netr_Credential
) {{0}};
712 creds
->server
= (struct netr_Credential
) {{0}};
718 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context
*context
,
719 const struct netlogon_creds_CredentialState
*creds1
)
721 TALLOC_CTX
*frame
= talloc_stackframe();
722 struct netlogon_creds_CredentialState
*creds2
;
726 enum ndr_err_code ndr_err
;
729 status
= netlogon_creds_cli_get(context
, frame
, &creds2
);
730 if (!NT_STATUS_IS_OK(status
)) {
735 ndr_err
= ndr_push_struct_blob(&blob1
, frame
, creds1
,
736 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
737 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
742 ndr_err
= ndr_push_struct_blob(&blob2
, frame
, creds2
,
743 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
749 equal
= data_blob_equal_const_time(&blob1
, &blob2
);
756 static NTSTATUS
netlogon_creds_cli_store_internal(
757 struct netlogon_creds_cli_context
*context
,
758 struct netlogon_creds_CredentialState
*creds
)
760 TALLOC_CTX
*frame
= talloc_stackframe();
762 enum ndr_err_code ndr_err
;
766 if (DEBUGLEVEL
>= 10) {
767 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
770 ndr_err
= ndr_push_struct_blob(&blob
, frame
, creds
,
771 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
772 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
773 status
= ndr_map_error2ntstatus(ndr_err
);
778 data
.dptr
= blob
.data
;
779 data
.dsize
= blob
.length
;
781 status
= dbwrap_store(context
->db
.ctx
,
782 context
->db
.key_data
,
784 if (!NT_STATUS_IS_OK(status
)) {
793 NTSTATUS
netlogon_creds_cli_store(struct netlogon_creds_cli_context
*context
,
794 struct netlogon_creds_CredentialState
*creds
)
798 if (context
->db
.locked_state
== NULL
) {
800 * this was not the result of netlogon_creds_cli_lock*()
802 return NT_STATUS_INVALID_PAGE_PROTECTION
;
805 if (context
->db
.locked_state
->creds
!= creds
) {
807 * this was not the result of netlogon_creds_cli_lock*()
809 return NT_STATUS_INVALID_PAGE_PROTECTION
;
812 status
= netlogon_creds_cli_store_internal(context
, creds
);
816 static NTSTATUS
netlogon_creds_cli_delete_internal(
817 struct netlogon_creds_cli_context
*context
)
820 status
= dbwrap_delete(context
->db
.ctx
, context
->db
.key_data
);
824 NTSTATUS
netlogon_creds_cli_delete_lck(
825 struct netlogon_creds_cli_context
*context
)
829 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
830 return NT_STATUS_NOT_LOCKED
;
833 status
= netlogon_creds_cli_delete_internal(context
);
837 NTSTATUS
netlogon_creds_cli_delete(struct netlogon_creds_cli_context
*context
,
838 struct netlogon_creds_CredentialState
*creds
)
842 if (context
->db
.locked_state
== NULL
) {
844 * this was not the result of netlogon_creds_cli_lock*()
846 return NT_STATUS_INVALID_PAGE_PROTECTION
;
849 if (context
->db
.locked_state
->creds
!= creds
) {
851 * this was not the result of netlogon_creds_cli_lock*()
853 return NT_STATUS_INVALID_PAGE_PROTECTION
;
856 status
= netlogon_creds_cli_delete_internal(context
);
860 struct netlogon_creds_cli_lock_state
{
861 struct netlogon_creds_cli_locked_state
*locked_state
;
862 struct netlogon_creds_CredentialState
*creds
;
865 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
);
867 struct tevent_req
*netlogon_creds_cli_lock_send(TALLOC_CTX
*mem_ctx
,
868 struct tevent_context
*ev
,
869 struct netlogon_creds_cli_context
*context
)
871 struct tevent_req
*req
;
872 struct netlogon_creds_cli_lock_state
*state
;
873 struct netlogon_creds_cli_locked_state
*locked_state
;
874 struct tevent_req
*subreq
;
876 req
= tevent_req_create(mem_ctx
, &state
,
877 struct netlogon_creds_cli_lock_state
);
882 if (context
->db
.locked_state
!= NULL
) {
883 tevent_req_nterror(req
, NT_STATUS_LOCK_NOT_GRANTED
);
884 return tevent_req_post(req
, ev
);
887 locked_state
= talloc_zero(state
, struct netlogon_creds_cli_locked_state
);
888 if (tevent_req_nomem(locked_state
, req
)) {
889 return tevent_req_post(req
, ev
);
891 talloc_set_destructor(locked_state
,
892 netlogon_creds_cli_locked_state_destructor
);
893 locked_state
->context
= context
;
895 context
->db
.locked_state
= locked_state
;
896 state
->locked_state
= locked_state
;
898 if (context
->db
.g_ctx
== NULL
) {
901 status
= netlogon_creds_cli_get_internal(
902 context
, state
, &state
->creds
);
903 if (tevent_req_nterror(req
, status
)) {
904 return tevent_req_post(req
, ev
);
910 subreq
= g_lock_lock_send(state
, ev
,
912 string_term_tdb_data(context
->db
.key_name
),
915 if (tevent_req_nomem(subreq
, req
)) {
916 return tevent_req_post(req
, ev
);
918 tevent_req_set_callback(subreq
, netlogon_creds_cli_lock_done
, req
);
923 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
)
925 struct tevent_req
*req
=
926 tevent_req_callback_data(subreq
,
928 struct netlogon_creds_cli_lock_state
*state
=
930 struct netlogon_creds_cli_lock_state
);
933 status
= g_lock_lock_recv(subreq
);
935 if (tevent_req_nterror(req
, status
)) {
938 state
->locked_state
->is_glocked
= true;
940 status
= netlogon_creds_cli_get_internal(state
->locked_state
->context
,
941 state
, &state
->creds
);
942 if (tevent_req_nterror(req
, status
)) {
945 tevent_req_done(req
);
948 static NTSTATUS
netlogon_creds_cli_get_internal(
949 struct netlogon_creds_cli_context
*context
,
950 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
)
952 struct netlogon_creds_cli_fetch_state fstate
= {
953 .status
= NT_STATUS_INTERNAL_ERROR
,
954 .proposed_flags
= context
->client
.proposed_flags
,
955 .required_flags
= context
->client
.required_flags
,
959 fstate
.mem_ctx
= mem_ctx
;
960 status
= dbwrap_parse_record(context
->db
.ctx
,
961 context
->db
.key_data
,
962 netlogon_creds_cli_fetch_parser
,
964 if (!NT_STATUS_IS_OK(status
)) {
967 if (!NT_STATUS_IS_OK(fstate
.status
)) {
968 return fstate
.status
;
971 if (context
->server
.cached_flags
== fstate
.creds
->negotiate_flags
) {
972 *pcreds
= fstate
.creds
;
977 * It is really important to try SamLogonEx here,
978 * because multiple processes can talk to the same
979 * domain controller, without using the credential
982 * With a normal SamLogon call, we must keep the
983 * credentials chain updated and intact between all
984 * users of the machine account (which would imply
985 * cross-node communication for every NTLM logon).
987 * The credentials chain is not per NETLOGON pipe
988 * connection, but globally on the server/client pair
991 * It's also important to use NetlogonValidationSamInfo4 (6),
992 * because it relies on the rpc transport encryption
993 * and avoids using the global netlogon schannel
994 * session key to en/decrypt secret information
995 * like the user_session_key for network logons.
997 * [MS-APDS] 3.1.5.2 NTLM Network Logon
998 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
999 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1000 * are the indication that the server supports
1001 * NetlogonValidationSamInfo4 (6). And it must only
1002 * be used if "SealSecureChannel" is used.
1004 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
1005 * check is done in netlogon_creds_cli_LogonSamLogon*().
1008 context
->server
.cached_flags
= fstate
.creds
->negotiate_flags
;
1009 context
->server
.try_validation6
= true;
1010 context
->server
.try_logon_ex
= true;
1011 context
->server
.try_logon_with
= true;
1013 if (!(context
->server
.cached_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
)) {
1014 context
->server
.try_validation6
= false;
1015 context
->server
.try_logon_ex
= false;
1017 if (!(context
->server
.cached_flags
& NETLOGON_NEG_CROSS_FOREST_TRUSTS
)) {
1018 context
->server
.try_validation6
= false;
1021 *pcreds
= fstate
.creds
;
1022 return NT_STATUS_OK
;
1025 NTSTATUS
netlogon_creds_cli_lock_recv(struct tevent_req
*req
,
1026 TALLOC_CTX
*mem_ctx
,
1027 struct netlogon_creds_CredentialState
**creds
)
1029 struct netlogon_creds_cli_lock_state
*state
=
1030 tevent_req_data(req
,
1031 struct netlogon_creds_cli_lock_state
);
1034 if (tevent_req_is_nterror(req
, &status
)) {
1035 tevent_req_received(req
);
1039 talloc_steal(state
->creds
, state
->locked_state
);
1040 state
->locked_state
->creds
= state
->creds
;
1041 *creds
= talloc_move(mem_ctx
, &state
->creds
);
1042 tevent_req_received(req
);
1043 return NT_STATUS_OK
;
1046 NTSTATUS
netlogon_creds_cli_lock(struct netlogon_creds_cli_context
*context
,
1047 TALLOC_CTX
*mem_ctx
,
1048 struct netlogon_creds_CredentialState
**creds
)
1050 TALLOC_CTX
*frame
= talloc_stackframe();
1051 struct tevent_context
*ev
;
1052 struct tevent_req
*req
;
1053 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1055 ev
= samba_tevent_context_init(frame
);
1059 req
= netlogon_creds_cli_lock_send(frame
, ev
, context
);
1063 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1066 status
= netlogon_creds_cli_lock_recv(req
, mem_ctx
, creds
);
1072 struct netlogon_creds_cli_lck
{
1073 struct netlogon_creds_cli_context
*context
;
1076 struct netlogon_creds_cli_lck_state
{
1077 struct netlogon_creds_cli_lck
*lck
;
1078 enum netlogon_creds_cli_lck_type type
;
1081 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
);
1082 static int netlogon_creds_cli_lck_destructor(
1083 struct netlogon_creds_cli_lck
*lck
);
1085 struct tevent_req
*netlogon_creds_cli_lck_send(
1086 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
1087 struct netlogon_creds_cli_context
*context
,
1088 enum netlogon_creds_cli_lck_type type
)
1090 struct tevent_req
*req
, *subreq
;
1091 struct netlogon_creds_cli_lck_state
*state
;
1092 enum g_lock_type gtype
;
1094 req
= tevent_req_create(mem_ctx
, &state
,
1095 struct netlogon_creds_cli_lck_state
);
1100 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_NONE
) {
1101 DBG_DEBUG("context already locked\n");
1102 tevent_req_nterror(req
, NT_STATUS_INVALID_LOCK_SEQUENCE
);
1103 return tevent_req_post(req
, ev
);
1107 case NETLOGON_CREDS_CLI_LCK_SHARED
:
1108 gtype
= G_LOCK_READ
;
1110 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
:
1111 gtype
= G_LOCK_WRITE
;
1114 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1115 return tevent_req_post(req
, ev
);
1118 state
->lck
= talloc(state
, struct netlogon_creds_cli_lck
);
1119 if (tevent_req_nomem(state
->lck
, req
)) {
1120 return tevent_req_post(req
, ev
);
1122 state
->lck
->context
= context
;
1125 subreq
= g_lock_lock_send(state
, ev
,
1127 string_term_tdb_data(context
->db
.key_name
),
1130 if (tevent_req_nomem(subreq
, req
)) {
1131 return tevent_req_post(req
, ev
);
1133 tevent_req_set_callback(subreq
, netlogon_creds_cli_lck_locked
, req
);
1138 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
)
1140 struct tevent_req
*req
= tevent_req_callback_data(
1141 subreq
, struct tevent_req
);
1142 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1143 req
, struct netlogon_creds_cli_lck_state
);
1146 status
= g_lock_lock_recv(subreq
);
1147 TALLOC_FREE(subreq
);
1148 if (tevent_req_nterror(req
, status
)) {
1152 state
->lck
->context
->db
.lock
= state
->type
;
1153 talloc_set_destructor(state
->lck
, netlogon_creds_cli_lck_destructor
);
1155 tevent_req_done(req
);
1158 static int netlogon_creds_cli_lck_destructor(
1159 struct netlogon_creds_cli_lck
*lck
)
1161 struct netlogon_creds_cli_context
*ctx
= lck
->context
;
1164 status
= g_lock_unlock(ctx
->db
.g_ctx
,
1165 string_term_tdb_data(ctx
->db
.key_name
));
1166 if (!NT_STATUS_IS_OK(status
)) {
1167 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status
));
1168 smb_panic("g_lock_unlock failed");
1170 ctx
->db
.lock
= NETLOGON_CREDS_CLI_LCK_NONE
;
1174 NTSTATUS
netlogon_creds_cli_lck_recv(
1175 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1176 struct netlogon_creds_cli_lck
**lck
)
1178 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1179 req
, struct netlogon_creds_cli_lck_state
);
1182 if (tevent_req_is_nterror(req
, &status
)) {
1185 *lck
= talloc_move(mem_ctx
, &state
->lck
);
1186 return NT_STATUS_OK
;
1189 NTSTATUS
netlogon_creds_cli_lck(
1190 struct netlogon_creds_cli_context
*context
,
1191 enum netlogon_creds_cli_lck_type type
,
1192 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_cli_lck
**lck
)
1194 TALLOC_CTX
*frame
= talloc_stackframe();
1195 struct tevent_context
*ev
;
1196 struct tevent_req
*req
;
1197 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1199 ev
= samba_tevent_context_init(frame
);
1203 req
= netlogon_creds_cli_lck_send(frame
, ev
, context
, type
);
1207 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1210 status
= netlogon_creds_cli_lck_recv(req
, mem_ctx
, lck
);
1216 static NTSTATUS
netlogon_creds_cli_check_transport(
1217 enum dcerpc_AuthType auth_type
,
1218 enum dcerpc_AuthLevel auth_level
,
1219 const struct netlogon_creds_CredentialState
*creds
,
1220 enum dcerpc_AuthLevel min_auth_level
)
1222 if (auth_level
< min_auth_level
) {
1223 return NT_STATUS_INVALID_PARAMETER_MIX
;
1226 if (creds
== NULL
) {
1227 return NT_STATUS_INVALID_PARAMETER_MIX
;
1230 if (auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
1231 switch (auth_level
) {
1232 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1233 case DCERPC_AUTH_LEVEL_PRIVACY
:
1234 return NT_STATUS_OK
;
1239 return NT_STATUS_INVALID_PARAMETER_MIX
;
1242 if (creds
->negotiate_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
1244 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1245 * it should be used, which means
1246 * we had a chance to verify no downgrade
1249 * This relies on netlogon_creds_cli_check*
1250 * being called before, as first request after
1253 return NT_STATUS_INVALID_PARAMETER_MIX
;
1256 return NT_STATUS_OK
;
1259 struct netlogon_creds_cli_auth_state
{
1260 struct tevent_context
*ev
;
1261 struct netlogon_creds_cli_context
*context
;
1262 struct dcerpc_binding_handle
*binding_handle
;
1263 enum dcerpc_AuthType auth_type
;
1264 enum dcerpc_AuthLevel auth_level
;
1265 uint8_t num_nt_hashes
;
1266 uint8_t idx_nt_hashes
;
1267 const struct samr_Password
* const *nt_hashes
;
1268 const struct samr_Password
*used_nt_hash
;
1269 char *srv_name_slash
;
1270 uint32_t current_flags
;
1271 struct netr_Credential client_challenge
;
1272 struct netr_Credential server_challenge
;
1273 struct netlogon_creds_CredentialState
*creds
;
1274 struct netr_Credential client_credential
;
1275 struct netr_Credential server_credential
;
1276 uint32_t negotiate_flags
;
1283 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
);
1285 struct tevent_req
*netlogon_creds_cli_auth_send(TALLOC_CTX
*mem_ctx
,
1286 struct tevent_context
*ev
,
1287 struct netlogon_creds_cli_context
*context
,
1288 struct dcerpc_binding_handle
*b
,
1289 uint8_t num_nt_hashes
,
1290 const struct samr_Password
* const *nt_hashes
)
1292 struct tevent_req
*req
;
1293 struct netlogon_creds_cli_auth_state
*state
;
1296 req
= tevent_req_create(mem_ctx
, &state
,
1297 struct netlogon_creds_cli_auth_state
);
1303 state
->context
= context
;
1304 state
->binding_handle
= b
;
1305 if (num_nt_hashes
< 1) {
1306 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1307 return tevent_req_post(req
, ev
);
1309 if (num_nt_hashes
> 4) {
1310 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1311 return tevent_req_post(req
, ev
);
1314 state
->num_nt_hashes
= num_nt_hashes
;
1315 state
->idx_nt_hashes
= 0;
1316 state
->nt_hashes
= nt_hashes
;
1318 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1319 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1320 return tevent_req_post(req
, ev
);
1323 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1324 context
->server
.computer
);
1325 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1326 return tevent_req_post(req
, ev
);
1329 dcerpc_binding_handle_auth_info(state
->binding_handle
,
1331 &state
->auth_level
);
1333 state
->try_auth3
= true;
1334 state
->try_auth2
= true;
1336 if (context
->client
.required_flags
!= 0) {
1337 state
->require_auth2
= true;
1340 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1341 state
->current_flags
= context
->client
.proposed_flags
;
1343 status
= dbwrap_purge(state
->context
->db
.ctx
,
1344 state
->context
->db
.key_data
);
1345 if (tevent_req_nterror(req
, status
)) {
1346 return tevent_req_post(req
, ev
);
1349 netlogon_creds_cli_auth_challenge_start(req
);
1350 if (!tevent_req_is_in_progress(req
)) {
1351 return tevent_req_post(req
, ev
);
1357 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
);
1359 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
)
1361 struct netlogon_creds_cli_auth_state
*state
=
1362 tevent_req_data(req
,
1363 struct netlogon_creds_cli_auth_state
);
1364 struct tevent_req
*subreq
;
1366 TALLOC_FREE(state
->creds
);
1368 netlogon_creds_random_challenge(&state
->client_challenge
);
1370 subreq
= dcerpc_netr_ServerReqChallenge_send(state
, state
->ev
,
1371 state
->binding_handle
,
1372 state
->srv_name_slash
,
1373 state
->context
->client
.computer
,
1374 &state
->client_challenge
,
1375 &state
->server_challenge
);
1376 if (tevent_req_nomem(subreq
, req
)) {
1379 tevent_req_set_callback(subreq
,
1380 netlogon_creds_cli_auth_challenge_done
,
1384 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
);
1386 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
)
1388 struct tevent_req
*req
=
1389 tevent_req_callback_data(subreq
,
1391 struct netlogon_creds_cli_auth_state
*state
=
1392 tevent_req_data(req
,
1393 struct netlogon_creds_cli_auth_state
);
1397 status
= dcerpc_netr_ServerReqChallenge_recv(subreq
, state
, &result
);
1398 TALLOC_FREE(subreq
);
1399 if (tevent_req_nterror(req
, status
)) {
1402 if (tevent_req_nterror(req
, result
)) {
1406 if (!state
->try_auth3
&& !state
->try_auth2
) {
1407 state
->current_flags
= 0;
1410 /* Calculate the session key and client credentials */
1412 state
->creds
= netlogon_creds_client_init(state
,
1413 state
->context
->client
.account
,
1414 state
->context
->client
.computer
,
1415 state
->context
->client
.type
,
1416 &state
->client_challenge
,
1417 &state
->server_challenge
,
1418 state
->used_nt_hash
,
1419 &state
->client_credential
,
1420 state
->context
->client
.proposed_flags
,
1421 state
->current_flags
);
1422 if (tevent_req_nomem(state
->creds
, req
)) {
1426 if (state
->try_auth3
) {
1428 * We always need to send our proposed flags,
1429 * even if state->current_flags we passed to
1430 * netlogon_creds_client_init() is already downgraded,
1432 * An old server will just ignore the bits it doesn't
1433 * know about, but LogonGetCapabilities(level=2) will
1434 * report what we proposed.
1436 state
->negotiate_flags
= state
->context
->client
.proposed_flags
;
1438 subreq
= dcerpc_netr_ServerAuthenticate3_send(state
, state
->ev
,
1439 state
->binding_handle
,
1440 state
->srv_name_slash
,
1441 state
->context
->client
.account
,
1442 state
->context
->client
.type
,
1443 state
->context
->client
.computer
,
1444 &state
->client_credential
,
1445 &state
->server_credential
,
1446 &state
->negotiate_flags
,
1448 if (tevent_req_nomem(subreq
, req
)) {
1451 } else if (state
->try_auth2
) {
1453 * We always need to send our proposed flags,
1454 * even if state->current_flags we passed to
1455 * netlogon_creds_client_init() is already downgraded,
1457 * An old server will just ignore the bits it doesn't
1458 * know about, but LogonGetCapabilities(level=2) will
1459 * report what we proposed.
1461 state
->negotiate_flags
= state
->context
->client
.proposed_flags
;
1464 subreq
= dcerpc_netr_ServerAuthenticate2_send(state
, state
->ev
,
1465 state
->binding_handle
,
1466 state
->srv_name_slash
,
1467 state
->context
->client
.account
,
1468 state
->context
->client
.type
,
1469 state
->context
->client
.computer
,
1470 &state
->client_credential
,
1471 &state
->server_credential
,
1472 &state
->negotiate_flags
);
1473 if (tevent_req_nomem(subreq
, req
)) {
1477 state
->negotiate_flags
= 0;
1480 subreq
= dcerpc_netr_ServerAuthenticate_send(state
, state
->ev
,
1481 state
->binding_handle
,
1482 state
->srv_name_slash
,
1483 state
->context
->client
.account
,
1484 state
->context
->client
.type
,
1485 state
->context
->client
.computer
,
1486 &state
->client_credential
,
1487 &state
->server_credential
);
1488 if (tevent_req_nomem(subreq
, req
)) {
1492 tevent_req_set_callback(subreq
,
1493 netlogon_creds_cli_auth_srvauth_done
,
1497 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
)
1499 struct tevent_req
*req
=
1500 tevent_req_callback_data(subreq
,
1502 struct netlogon_creds_cli_auth_state
*state
=
1503 tevent_req_data(req
,
1504 struct netlogon_creds_cli_auth_state
);
1509 if (state
->try_auth3
) {
1510 status
= dcerpc_netr_ServerAuthenticate3_recv(subreq
, state
,
1512 TALLOC_FREE(subreq
);
1513 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1514 state
->try_auth3
= false;
1515 netlogon_creds_cli_auth_challenge_start(req
);
1518 if (tevent_req_nterror(req
, status
)) {
1521 } else if (state
->try_auth2
) {
1522 status
= dcerpc_netr_ServerAuthenticate2_recv(subreq
, state
,
1524 TALLOC_FREE(subreq
);
1525 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1526 state
->try_auth2
= false;
1527 if (state
->require_auth2
) {
1528 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1529 tevent_req_nterror(req
, status
);
1532 netlogon_creds_cli_auth_challenge_start(req
);
1535 if (tevent_req_nterror(req
, status
)) {
1539 status
= dcerpc_netr_ServerAuthenticate_recv(subreq
, state
,
1541 TALLOC_FREE(subreq
);
1542 if (tevent_req_nterror(req
, status
)) {
1547 if (!NT_STATUS_IS_OK(result
) &&
1548 !NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
))
1550 tevent_req_nterror(req
, result
);
1554 downgraded
= netlogon_creds_cli_downgraded(
1555 state
->negotiate_flags
,
1556 state
->context
->client
.proposed_flags
,
1557 state
->context
->client
.required_flags
);
1559 if (NT_STATUS_IS_OK(result
)) {
1560 tevent_req_nterror(req
, NT_STATUS_DOWNGRADE_DETECTED
);
1563 tevent_req_nterror(req
, result
);
1567 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
1568 uint32_t prop_f
= state
->context
->client
.proposed_flags
;
1569 uint32_t cli_f
= state
->current_flags
;
1570 uint32_t srv_f
= state
->negotiate_flags
;
1571 uint32_t nego_f
= cli_f
& srv_f
;
1573 if (cli_f
== prop_f
&& nego_f
!= prop_f
) {
1575 * lets retry with the negotiated flags
1577 state
->current_flags
= nego_f
;
1578 netlogon_creds_cli_auth_challenge_start(req
);
1582 state
->idx_nt_hashes
+= 1;
1583 if (state
->idx_nt_hashes
>= state
->num_nt_hashes
) {
1585 * we already retried, giving up...
1587 tevent_req_nterror(req
, result
);
1592 * lets retry with the old nt hash.
1594 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1595 state
->current_flags
= state
->context
->client
.proposed_flags
;
1596 netlogon_creds_cli_auth_challenge_start(req
);
1600 status
= netlogon_creds_client_verify(state
->creds
,
1601 &state
->server_credential
,
1604 if (tevent_req_nterror(req
, status
)) {
1608 if (state
->current_flags
== state
->context
->client
.proposed_flags
) {
1610 * Without a downgrade in the crypto we proposed
1611 * we can adjust the otherwise downgraded flags
1614 state
->creds
->negotiate_flags
&= state
->negotiate_flags
;
1615 } else if (state
->current_flags
!= state
->negotiate_flags
) {
1617 * We downgraded our crypto once, we should not
1618 * allow any additional downgrade!
1620 tevent_req_nterror(req
, NT_STATUS_DOWNGRADE_DETECTED
);
1624 state
->creds
->client_sid
.sub_auths
[0] = state
->rid
;
1625 status
= netlogon_creds_cli_store_internal(state
->context
,
1627 if (tevent_req_nterror(req
, status
)) {
1631 tevent_req_done(req
);
1634 NTSTATUS
netlogon_creds_cli_auth_recv(struct tevent_req
*req
,
1635 uint8_t *idx_nt_hashes
)
1637 struct netlogon_creds_cli_auth_state
*state
=
1638 tevent_req_data(req
,
1639 struct netlogon_creds_cli_auth_state
);
1644 if (tevent_req_is_nterror(req
, &status
)) {
1645 tevent_req_received(req
);
1649 *idx_nt_hashes
= state
->idx_nt_hashes
;
1650 tevent_req_received(req
);
1651 return NT_STATUS_OK
;
1654 NTSTATUS
netlogon_creds_cli_auth(struct netlogon_creds_cli_context
*context
,
1655 struct dcerpc_binding_handle
*b
,
1656 uint8_t num_nt_hashes
,
1657 const struct samr_Password
* const *nt_hashes
,
1658 uint8_t *idx_nt_hashes
)
1660 TALLOC_CTX
*frame
= talloc_stackframe();
1661 struct tevent_context
*ev
;
1662 struct tevent_req
*req
;
1663 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1667 ev
= samba_tevent_context_init(frame
);
1671 req
= netlogon_creds_cli_auth_send(frame
, ev
, context
, b
,
1672 num_nt_hashes
, nt_hashes
);
1676 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1679 status
= netlogon_creds_cli_auth_recv(req
, idx_nt_hashes
);
1685 struct netlogon_creds_cli_check_state
{
1686 struct tevent_context
*ev
;
1687 struct netlogon_creds_cli_context
*context
;
1688 struct dcerpc_binding_handle
*binding_handle
;
1689 enum dcerpc_AuthType auth_type
;
1690 enum dcerpc_AuthLevel auth_level
;
1692 char *srv_name_slash
;
1694 union netr_Capabilities caps
;
1695 union netr_Capabilities client_caps
;
1697 struct netlogon_creds_CredentialState
*creds
;
1698 struct netr_Authenticator req_auth
;
1699 struct netr_Authenticator rep_auth
;
1701 union netr_CONTROL_QUERY_INFORMATION ctrl_info
;
1704 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1706 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req
*subreq
);
1707 static void netlogon_creds_cli_check_client_caps(struct tevent_req
*subreq
);
1709 struct tevent_req
*netlogon_creds_cli_check_send(TALLOC_CTX
*mem_ctx
,
1710 struct tevent_context
*ev
,
1711 struct netlogon_creds_cli_context
*context
,
1712 struct dcerpc_binding_handle
*b
)
1714 struct tevent_req
*req
;
1715 struct netlogon_creds_cli_check_state
*state
;
1716 struct tevent_req
*subreq
;
1719 req
= tevent_req_create(mem_ctx
, &state
,
1720 struct netlogon_creds_cli_check_state
);
1726 state
->context
= context
;
1727 state
->binding_handle
= b
;
1729 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1730 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1731 return tevent_req_post(req
, ev
);
1734 status
= netlogon_creds_cli_get_internal(context
, state
,
1736 if (tevent_req_nterror(req
, status
)) {
1737 return tevent_req_post(req
, ev
);
1740 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1741 context
->server
.computer
);
1742 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1743 return tevent_req_post(req
, ev
);
1746 dcerpc_binding_handle_auth_info(state
->binding_handle
,
1748 &state
->auth_level
);
1750 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
1753 DCERPC_AUTH_LEVEL_INTEGRITY
);
1754 if (tevent_req_nterror(req
, status
)) {
1755 return tevent_req_post(req
, ev
);
1759 * we defer all callbacks in order to cleanup
1760 * the database record.
1762 tevent_req_defer_callback(req
, state
->ev
);
1764 status
= netlogon_creds_client_authenticator(state
->creds
,
1766 if (tevent_req_nterror(req
, status
)) {
1767 return tevent_req_post(req
, ev
);
1769 ZERO_STRUCT(state
->rep_auth
);
1771 subreq
= dcerpc_netr_LogonGetCapabilities_send(state
, state
->ev
,
1772 state
->binding_handle
,
1773 state
->srv_name_slash
,
1774 state
->context
->client
.computer
,
1779 if (tevent_req_nomem(subreq
, req
)) {
1780 return tevent_req_post(req
, ev
);
1783 tevent_req_set_callback(subreq
,
1784 netlogon_creds_cli_check_negotiate_caps
,
1790 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1793 struct netlogon_creds_cli_check_state
*state
=
1794 tevent_req_data(req
,
1795 struct netlogon_creds_cli_check_state
);
1797 if (state
->creds
== NULL
) {
1801 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
1802 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
1803 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
1804 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
1805 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
1806 TALLOC_FREE(state
->creds
);
1810 netlogon_creds_cli_delete_lck(state
->context
);
1811 TALLOC_FREE(state
->creds
);
1814 static void netlogon_creds_cli_check_control_do(struct tevent_req
*req
);
1816 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req
*subreq
)
1818 struct tevent_req
*req
=
1819 tevent_req_callback_data(subreq
,
1821 struct netlogon_creds_cli_check_state
*state
=
1822 tevent_req_data(req
,
1823 struct netlogon_creds_cli_check_state
);
1827 status
= dcerpc_netr_LogonGetCapabilities_recv(subreq
, state
,
1829 TALLOC_FREE(subreq
);
1830 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1832 * Note that the negotiated flags are already checked
1833 * for our required flags after the ServerAuthenticate3/2 call.
1835 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1837 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1839 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1840 * already, we expect this to work!
1842 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1843 tevent_req_nterror(req
, status
);
1844 netlogon_creds_cli_check_cleanup(req
, status
);
1848 if (negotiated
& NETLOGON_NEG_STRONG_KEYS
) {
1850 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1851 * we expect this to work at least as far as the
1852 * NOT_SUPPORTED error handled below!
1854 * NT 4.0 and Old Samba servers are not
1855 * allowed without "require strong key = no"
1857 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1858 tevent_req_nterror(req
, status
);
1859 netlogon_creds_cli_check_cleanup(req
, status
);
1864 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1865 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1866 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1868 * This is needed against NT 4.0 and old Samba servers.
1870 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1871 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1872 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1873 * with the next request as the sequence number processing
1876 * So we'll do a LogonControl message to check that...
1878 netlogon_creds_cli_check_control_do(req
);
1881 if (tevent_req_nterror(req
, status
)) {
1882 netlogon_creds_cli_check_cleanup(req
, status
);
1886 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
1888 * Note that the negotiated flags are already checked
1889 * for our required flags after the ServerAuthenticate3/2 call.
1891 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1893 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1895 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1896 * already, we expect this to work!
1898 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1899 tevent_req_nterror(req
, status
);
1900 netlogon_creds_cli_check_cleanup(req
, status
);
1905 * This is ok, the server does not support
1906 * NETLOGON_NEG_SUPPORTS_AES.
1908 * netr_LogonGetCapabilities() was
1909 * netr_LogonDummyRoutine1() before
1910 * NETLOGON_NEG_SUPPORTS_AES was invented.
1912 netlogon_creds_cli_check_cleanup(req
, result
);
1913 tevent_req_done(req
);
1917 status
= netlogon_creds_client_verify(state
->creds
,
1918 &state
->rep_auth
.cred
,
1921 if (tevent_req_nterror(req
, status
)) {
1922 netlogon_creds_cli_check_cleanup(req
, status
);
1926 if (tevent_req_nterror(req
, result
)) {
1927 netlogon_creds_cli_check_cleanup(req
, result
);
1931 if (state
->caps
.server_capabilities
!= state
->creds
->negotiate_flags
) {
1932 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1933 tevent_req_nterror(req
, status
);
1934 netlogon_creds_cli_check_cleanup(req
, status
);
1939 * This is the key check that makes this check secure. If we
1940 * get OK here (rather than NOT_SUPPORTED), then the server
1941 * did support AES. If the server only proposed STRONG_KEYS
1942 * and not AES, then it should have failed with
1943 * NOT_IMPLEMENTED. We always send AES as a client, so the
1944 * server should always have returned it.
1946 if (!(state
->caps
.server_capabilities
& NETLOGON_NEG_SUPPORTS_AES
)) {
1947 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1948 tevent_req_nterror(req
, status
);
1949 netlogon_creds_cli_check_cleanup(req
, status
);
1953 status
= netlogon_creds_cli_store_internal(state
->context
,
1955 if (tevent_req_nterror(req
, status
)) {
1960 * Now try to verify our client proposed flags
1961 * arrived at the server, using query_level = 2
1964 status
= netlogon_creds_client_authenticator(state
->creds
,
1966 if (tevent_req_nterror(req
, status
)) {
1969 ZERO_STRUCT(state
->rep_auth
);
1971 subreq
= dcerpc_netr_LogonGetCapabilities_send(state
, state
->ev
,
1972 state
->binding_handle
,
1973 state
->srv_name_slash
,
1974 state
->context
->client
.computer
,
1978 &state
->client_caps
);
1979 if (tevent_req_nomem(subreq
, req
)) {
1983 tevent_req_set_callback(subreq
,
1984 netlogon_creds_cli_check_client_caps
,
1989 static void netlogon_creds_cli_check_client_caps(struct tevent_req
*subreq
)
1991 struct tevent_req
*req
=
1992 tevent_req_callback_data(subreq
,
1994 struct netlogon_creds_cli_check_state
*state
=
1995 tevent_req_data(req
,
1996 struct netlogon_creds_cli_check_state
);
1997 uint32_t requested_flags
;
2001 status
= dcerpc_netr_LogonGetCapabilities_recv(subreq
, state
,
2003 TALLOC_FREE(subreq
);
2004 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_BAD_STUB_DATA
)) {
2006 * unpatched Samba server, see
2007 * https://bugzilla.samba.org/show_bug.cgi?id=15418
2009 status
= NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
;
2011 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
)) {
2013 * Here we know the negotiated flags were already
2014 * verified with query_level=1, which means
2015 * the server supported NETLOGON_NEG_SUPPORTS_AES
2016 * and also NETLOGON_NEG_AUTHENTICATED_RPC
2018 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
2019 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
2020 * we should detect a faked
2021 * NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
2022 * with the next request as the sequence number processing
2025 * So we'll do a LogonControl message to check that...
2027 netlogon_creds_cli_check_control_do(req
);
2030 if (tevent_req_nterror(req
, status
)) {
2031 netlogon_creds_cli_check_cleanup(req
, status
);
2035 status
= netlogon_creds_client_verify(state
->creds
,
2036 &state
->rep_auth
.cred
,
2039 if (tevent_req_nterror(req
, status
)) {
2040 netlogon_creds_cli_check_cleanup(req
, status
);
2043 if (tevent_req_nterror(req
, result
)) {
2044 netlogon_creds_cli_check_cleanup(req
, result
);
2048 requested_flags
= state
->creds
->client_requested_flags
;
2050 if (state
->client_caps
.requested_flags
!= requested_flags
) {
2051 status
= NT_STATUS_DOWNGRADE_DETECTED
;
2052 tevent_req_nterror(req
, status
);
2053 netlogon_creds_cli_check_cleanup(req
, status
);
2057 status
= netlogon_creds_cli_store_internal(state
->context
,
2059 if (tevent_req_nterror(req
, status
)) {
2063 tevent_req_done(req
);
2066 static void netlogon_creds_cli_check_control_done(struct tevent_req
*subreq
);
2068 static void netlogon_creds_cli_check_control_do(struct tevent_req
*req
)
2070 struct netlogon_creds_cli_check_state
*state
=
2071 tevent_req_data(req
,
2072 struct netlogon_creds_cli_check_state
);
2073 struct tevent_req
*subreq
= NULL
;
2076 * In case we got a downgrade based on a FAULT
2077 * we use a LogonControl that is supposed to
2078 * return WERR_NOT_SUPPORTED (without a DCERPC FAULT)
2079 * to verify that the connection is still ok and didn't
2082 subreq
= dcerpc_netr_LogonControl_send(state
,
2084 state
->binding_handle
,
2085 state
->srv_name_slash
,
2086 NETLOGON_CONTROL_QUERY
,
2089 if (tevent_req_nomem(subreq
, req
)) {
2093 tevent_req_set_callback(subreq
,
2094 netlogon_creds_cli_check_control_done
,
2099 static void netlogon_creds_cli_check_control_done(struct tevent_req
*subreq
)
2101 struct tevent_req
*req
=
2102 tevent_req_callback_data(subreq
,
2104 struct netlogon_creds_cli_check_state
*state
=
2105 tevent_req_data(req
,
2106 struct netlogon_creds_cli_check_state
);
2110 status
= dcerpc_netr_LogonControl_recv(subreq
, state
, &result
);
2111 TALLOC_FREE(subreq
);
2112 if (tevent_req_nterror(req
, status
)) {
2114 * We want to delete the creds,
2115 * so we pass NT_STATUS_DOWNGRADE_DETECTED
2116 * to netlogon_creds_cli_check_cleanup()
2118 status
= NT_STATUS_DOWNGRADE_DETECTED
;
2119 netlogon_creds_cli_check_cleanup(req
, status
);
2123 if (!W_ERROR_EQUAL(result
, WERR_NOT_SUPPORTED
)) {
2124 status
= NT_STATUS_DOWNGRADE_DETECTED
;
2125 tevent_req_nterror(req
, status
);
2126 netlogon_creds_cli_check_cleanup(req
, status
);
2130 tevent_req_done(req
);
2133 NTSTATUS
netlogon_creds_cli_check_recv(struct tevent_req
*req
,
2134 union netr_Capabilities
*capabilities
)
2136 struct netlogon_creds_cli_check_state
*state
= tevent_req_data(
2137 req
, struct netlogon_creds_cli_check_state
);
2140 if (tevent_req_is_nterror(req
, &status
)) {
2141 netlogon_creds_cli_check_cleanup(req
, status
);
2142 tevent_req_received(req
);
2146 if (capabilities
!= NULL
) {
2147 *capabilities
= state
->caps
;
2150 tevent_req_received(req
);
2151 return NT_STATUS_OK
;
2154 NTSTATUS
netlogon_creds_cli_check(struct netlogon_creds_cli_context
*context
,
2155 struct dcerpc_binding_handle
*b
,
2156 union netr_Capabilities
*capabilities
)
2158 TALLOC_CTX
*frame
= talloc_stackframe();
2159 struct tevent_context
*ev
;
2160 struct tevent_req
*req
;
2161 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2163 ev
= samba_tevent_context_init(frame
);
2167 req
= netlogon_creds_cli_check_send(frame
, ev
, context
, b
);
2171 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2174 status
= netlogon_creds_cli_check_recv(req
, capabilities
);
2180 struct netlogon_creds_cli_ServerPasswordSet_state
{
2181 struct tevent_context
*ev
;
2182 struct netlogon_creds_cli_context
*context
;
2183 struct dcerpc_binding_handle
*binding_handle
;
2184 uint32_t old_timeout
;
2186 char *srv_name_slash
;
2187 enum dcerpc_AuthType auth_type
;
2188 enum dcerpc_AuthLevel auth_level
;
2190 struct samr_CryptPassword samr_crypt_password
;
2191 struct netr_CryptPassword netr_crypt_password
;
2192 struct samr_Password samr_password
;
2194 struct netlogon_creds_CredentialState
*creds
;
2195 struct netlogon_creds_CredentialState tmp_creds
;
2196 struct netr_Authenticator req_auth
;
2197 struct netr_Authenticator rep_auth
;
2200 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
2202 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
);
2204 struct tevent_req
*netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX
*mem_ctx
,
2205 struct tevent_context
*ev
,
2206 struct netlogon_creds_cli_context
*context
,
2207 struct dcerpc_binding_handle
*b
,
2208 const DATA_BLOB
*new_password
,
2209 const uint32_t *new_version
)
2211 struct tevent_req
*req
;
2212 struct netlogon_creds_cli_ServerPasswordSet_state
*state
;
2213 struct tevent_req
*subreq
;
2216 req
= tevent_req_create(mem_ctx
, &state
,
2217 struct netlogon_creds_cli_ServerPasswordSet_state
);
2223 state
->context
= context
;
2224 state
->binding_handle
= b
;
2226 if (new_password
->length
< 14) {
2227 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2228 return tevent_req_post(req
, ev
);
2232 * netr_ServerPasswordSet
2234 mdfour(state
->samr_password
.hash
, new_password
->data
, new_password
->length
);
2237 * netr_ServerPasswordSet2
2239 ok
= set_pw_in_buffer(state
->samr_crypt_password
.data
,
2242 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2243 return tevent_req_post(req
, ev
);
2246 if (new_version
!= NULL
) {
2247 struct NL_PASSWORD_VERSION version
;
2248 uint32_t len
= IVAL(state
->samr_crypt_password
.data
, 512);
2249 uint32_t ofs
= 512 - len
;
2253 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2254 return tevent_req_post(req
, ev
);
2258 version
.ReservedField
= 0;
2259 version
.PasswordVersionNumber
= *new_version
;
2260 version
.PasswordVersionPresent
=
2261 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT
;
2263 p
= state
->samr_crypt_password
.data
+ ofs
;
2264 SIVAL(p
, 0, version
.ReservedField
);
2265 SIVAL(p
, 4, version
.PasswordVersionNumber
);
2266 SIVAL(p
, 8, version
.PasswordVersionPresent
);
2269 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2270 context
->server
.computer
);
2271 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2272 return tevent_req_post(req
, ev
);
2275 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2277 &state
->auth_level
);
2279 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2281 if (tevent_req_nomem(subreq
, req
)) {
2282 return tevent_req_post(req
, ev
);
2285 tevent_req_set_callback(subreq
,
2286 netlogon_creds_cli_ServerPasswordSet_locked
,
2292 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
2295 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2296 tevent_req_data(req
,
2297 struct netlogon_creds_cli_ServerPasswordSet_state
);
2299 if (state
->creds
== NULL
) {
2303 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
2304 state
->old_timeout
);
2306 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2307 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2308 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2309 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2310 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2311 TALLOC_FREE(state
->creds
);
2315 netlogon_creds_cli_delete(state
->context
, state
->creds
);
2316 TALLOC_FREE(state
->creds
);
2319 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
);
2321 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
)
2323 struct tevent_req
*req
=
2324 tevent_req_callback_data(subreq
,
2326 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2327 tevent_req_data(req
,
2328 struct netlogon_creds_cli_ServerPasswordSet_state
);
2331 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2333 TALLOC_FREE(subreq
);
2334 if (tevent_req_nterror(req
, status
)) {
2338 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
2341 DCERPC_AUTH_LEVEL_NONE
);
2342 if (tevent_req_nterror(req
, status
)) {
2346 state
->old_timeout
= dcerpc_binding_handle_set_timeout(
2347 state
->binding_handle
, 600000);
2350 * we defer all callbacks in order to cleanup
2351 * the database record.
2353 tevent_req_defer_callback(req
, state
->ev
);
2355 state
->tmp_creds
= *state
->creds
;
2356 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2358 if (tevent_req_nterror(req
, status
)) {
2361 ZERO_STRUCT(state
->rep_auth
);
2363 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
2365 status
= netlogon_creds_encrypt_samr_CryptPassword(&state
->tmp_creds
,
2366 &state
->samr_crypt_password
,
2369 if (tevent_req_nterror(req
, status
)) {
2370 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2374 memcpy(state
->netr_crypt_password
.data
,
2375 state
->samr_crypt_password
.data
, 512);
2376 state
->netr_crypt_password
.length
=
2377 IVAL(state
->samr_crypt_password
.data
, 512);
2379 subreq
= dcerpc_netr_ServerPasswordSet2_send(state
, state
->ev
,
2380 state
->binding_handle
,
2381 state
->srv_name_slash
,
2382 state
->tmp_creds
.account_name
,
2383 state
->tmp_creds
.secure_channel_type
,
2384 state
->tmp_creds
.computer_name
,
2387 &state
->netr_crypt_password
);
2388 if (tevent_req_nomem(subreq
, req
)) {
2389 status
= NT_STATUS_NO_MEMORY
;
2390 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2394 status
= netlogon_creds_encrypt_samr_Password(&state
->tmp_creds
,
2395 &state
->samr_password
,
2398 if (tevent_req_nterror(req
, status
)) {
2399 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2403 subreq
= dcerpc_netr_ServerPasswordSet_send(state
, state
->ev
,
2404 state
->binding_handle
,
2405 state
->srv_name_slash
,
2406 state
->tmp_creds
.account_name
,
2407 state
->tmp_creds
.secure_channel_type
,
2408 state
->tmp_creds
.computer_name
,
2411 &state
->samr_password
);
2412 if (tevent_req_nomem(subreq
, req
)) {
2413 status
= NT_STATUS_NO_MEMORY
;
2414 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2419 tevent_req_set_callback(subreq
,
2420 netlogon_creds_cli_ServerPasswordSet_done
,
2424 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
)
2426 struct tevent_req
*req
=
2427 tevent_req_callback_data(subreq
,
2429 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2430 tevent_req_data(req
,
2431 struct netlogon_creds_cli_ServerPasswordSet_state
);
2435 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
2436 status
= dcerpc_netr_ServerPasswordSet2_recv(subreq
, state
,
2438 TALLOC_FREE(subreq
);
2439 if (tevent_req_nterror(req
, status
)) {
2440 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2444 status
= dcerpc_netr_ServerPasswordSet_recv(subreq
, state
,
2446 TALLOC_FREE(subreq
);
2447 if (tevent_req_nterror(req
, status
)) {
2448 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2453 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
2454 &state
->rep_auth
.cred
,
2457 if (tevent_req_nterror(req
, status
)) {
2458 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2462 if (tevent_req_nterror(req
, result
)) {
2463 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, result
);
2467 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
2468 state
->old_timeout
);
2470 *state
->creds
= state
->tmp_creds
;
2471 status
= netlogon_creds_cli_store(state
->context
,
2473 TALLOC_FREE(state
->creds
);
2474 if (tevent_req_nterror(req
, status
)) {
2475 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2479 tevent_req_done(req
);
2482 NTSTATUS
netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req
*req
)
2486 if (tevent_req_is_nterror(req
, &status
)) {
2487 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2488 tevent_req_received(req
);
2492 tevent_req_received(req
);
2493 return NT_STATUS_OK
;
2496 NTSTATUS
netlogon_creds_cli_ServerPasswordSet(
2497 struct netlogon_creds_cli_context
*context
,
2498 struct dcerpc_binding_handle
*b
,
2499 const DATA_BLOB
*new_password
,
2500 const uint32_t *new_version
)
2502 TALLOC_CTX
*frame
= talloc_stackframe();
2503 struct tevent_context
*ev
;
2504 struct tevent_req
*req
;
2505 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2507 ev
= samba_tevent_context_init(frame
);
2511 req
= netlogon_creds_cli_ServerPasswordSet_send(frame
, ev
, context
, b
,
2517 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2520 status
= netlogon_creds_cli_ServerPasswordSet_recv(req
);
2526 struct netlogon_creds_cli_LogonSamLogon_state
{
2527 struct tevent_context
*ev
;
2528 struct netlogon_creds_cli_context
*context
;
2529 struct dcerpc_binding_handle
*binding_handle
;
2531 char *srv_name_slash
;
2533 enum netr_LogonInfoClass logon_level
;
2534 const union netr_LogonLevel
*const_logon
;
2535 union netr_LogonLevel
*logon
;
2538 uint16_t validation_level
;
2539 union netr_Validation
*validation
;
2540 uint8_t authoritative
;
2543 * do we need encryption at the application layer?
2547 bool try_validation6
;
2550 * the read only credentials before we started the operation
2551 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2553 struct netlogon_creds_CredentialState
*ro_creds
;
2556 * The (locked) credentials used for the credential chain
2557 * used for netr_LogonSamLogonWithFlags() or
2558 * netr_LogonSamLogonWith().
2560 struct netlogon_creds_CredentialState
*lk_creds
;
2563 * While we have locked the global credentials (lk_creds above)
2564 * we operate an a temporary copy, because a server
2565 * may not support netr_LogonSamLogonWithFlags() and
2566 * didn't process our netr_Authenticator, so we need to
2567 * restart from lk_creds.
2569 struct netlogon_creds_CredentialState tmp_creds
;
2570 struct netr_Authenticator req_auth
;
2571 struct netr_Authenticator rep_auth
;
2574 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
);
2575 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2578 struct tevent_req
*netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX
*mem_ctx
,
2579 struct tevent_context
*ev
,
2580 struct netlogon_creds_cli_context
*context
,
2581 struct dcerpc_binding_handle
*b
,
2582 enum netr_LogonInfoClass logon_level
,
2583 const union netr_LogonLevel
*logon
,
2586 struct tevent_req
*req
;
2587 struct netlogon_creds_cli_LogonSamLogon_state
*state
;
2589 req
= tevent_req_create(mem_ctx
, &state
,
2590 struct netlogon_creds_cli_LogonSamLogon_state
);
2596 state
->context
= context
;
2597 state
->binding_handle
= b
;
2599 state
->logon_level
= logon_level
;
2600 state
->const_logon
= logon
;
2601 state
->flags
= flags
;
2603 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2604 context
->server
.computer
);
2605 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2606 return tevent_req_post(req
, ev
);
2609 switch (logon_level
) {
2610 case NetlogonInteractiveInformation
:
2611 case NetlogonInteractiveTransitiveInformation
:
2612 case NetlogonServiceInformation
:
2613 case NetlogonServiceTransitiveInformation
:
2614 case NetlogonGenericInformation
:
2615 state
->user_encrypt
= true;
2618 case NetlogonNetworkInformation
:
2619 case NetlogonNetworkTransitiveInformation
:
2620 case NetlogonTicketLogonInformation
:
2624 state
->validation
= talloc_zero(state
, union netr_Validation
);
2625 if (tevent_req_nomem(state
->validation
, req
)) {
2626 return tevent_req_post(req
, ev
);
2629 netlogon_creds_cli_LogonSamLogon_start(req
);
2630 if (!tevent_req_is_in_progress(req
)) {
2631 return tevent_req_post(req
, ev
);
2635 * we defer all callbacks in order to cleanup
2636 * the database record.
2638 tevent_req_defer_callback(req
, state
->ev
);
2642 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2645 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2646 tevent_req_data(req
,
2647 struct netlogon_creds_cli_LogonSamLogon_state
);
2649 if (state
->lk_creds
== NULL
) {
2653 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2655 * This is a hack to recover from a bug in old
2656 * Samba servers, when LogonSamLogonEx() fails:
2658 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2660 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2662 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2663 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2664 * If the sign/seal check fails.
2666 * In that case we need to cleanup the netlogon session.
2668 * It's the job of the caller to disconnect the current
2669 * connection, if netlogon_creds_cli_LogonSamLogon()
2670 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2672 if (!state
->context
->server
.try_logon_with
) {
2673 status
= NT_STATUS_NETWORK_ACCESS_DENIED
;
2677 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2678 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2679 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2680 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2681 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2682 TALLOC_FREE(state
->lk_creds
);
2686 netlogon_creds_cli_delete(state
->context
, state
->lk_creds
);
2687 TALLOC_FREE(state
->lk_creds
);
2690 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
);
2692 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
)
2694 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2695 tevent_req_data(req
,
2696 struct netlogon_creds_cli_LogonSamLogon_state
);
2697 struct tevent_req
*subreq
;
2699 enum dcerpc_AuthType auth_type
;
2700 enum dcerpc_AuthLevel auth_level
;
2702 TALLOC_FREE(state
->ro_creds
);
2703 TALLOC_FREE(state
->logon
);
2704 ZERO_STRUCTP(state
->validation
);
2706 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2707 &auth_type
, &auth_level
);
2709 state
->try_logon_ex
= state
->context
->server
.try_logon_ex
;
2710 state
->try_validation6
= state
->context
->server
.try_validation6
;
2712 if (auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
2713 state
->try_logon_ex
= false;
2716 if (auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
2717 state
->try_validation6
= false;
2720 if (state
->try_logon_ex
) {
2721 if (state
->try_validation6
) {
2722 state
->validation_level
= 6;
2724 state
->validation_level
= 3;
2725 state
->user_encrypt
= true;
2728 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2730 state
->const_logon
);
2731 if (tevent_req_nomem(state
->logon
, req
)) {
2732 status
= NT_STATUS_NO_MEMORY
;
2733 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2737 if (state
->user_encrypt
) {
2738 status
= netlogon_creds_cli_get(state
->context
,
2741 if (!NT_STATUS_IS_OK(status
)) {
2742 status
= NT_STATUS_ACCESS_DENIED
;
2743 tevent_req_nterror(req
, status
);
2744 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2748 status
= netlogon_creds_encrypt_samlogon_logon(state
->ro_creds
,
2753 if (!NT_STATUS_IS_OK(status
)) {
2754 status
= NT_STATUS_ACCESS_DENIED
;
2755 tevent_req_nterror(req
, status
);
2756 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2761 subreq
= dcerpc_netr_LogonSamLogonEx_send(state
, state
->ev
,
2762 state
->binding_handle
,
2763 state
->srv_name_slash
,
2764 state
->context
->client
.computer
,
2767 state
->validation_level
,
2769 &state
->authoritative
,
2771 if (tevent_req_nomem(subreq
, req
)) {
2772 status
= NT_STATUS_NO_MEMORY
;
2773 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2776 tevent_req_set_callback(subreq
,
2777 netlogon_creds_cli_LogonSamLogon_done
,
2782 if (state
->lk_creds
== NULL
) {
2783 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2785 if (tevent_req_nomem(subreq
, req
)) {
2786 status
= NT_STATUS_NO_MEMORY
;
2787 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2790 tevent_req_set_callback(subreq
,
2791 netlogon_creds_cli_LogonSamLogon_done
,
2796 state
->tmp_creds
= *state
->lk_creds
;
2797 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2799 if (tevent_req_nterror(req
, status
)) {
2800 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2803 ZERO_STRUCT(state
->rep_auth
);
2805 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2807 state
->const_logon
);
2808 if (tevent_req_nomem(state
->logon
, req
)) {
2809 status
= NT_STATUS_NO_MEMORY
;
2810 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2814 status
= netlogon_creds_encrypt_samlogon_logon(&state
->tmp_creds
,
2819 if (tevent_req_nterror(req
, status
)) {
2820 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2824 state
->validation_level
= 3;
2826 if (state
->context
->server
.try_logon_with
) {
2827 subreq
= dcerpc_netr_LogonSamLogonWithFlags_send(state
, state
->ev
,
2828 state
->binding_handle
,
2829 state
->srv_name_slash
,
2830 state
->context
->client
.computer
,
2835 state
->validation_level
,
2837 &state
->authoritative
,
2839 if (tevent_req_nomem(subreq
, req
)) {
2840 status
= NT_STATUS_NO_MEMORY
;
2841 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2847 subreq
= dcerpc_netr_LogonSamLogon_send(state
, state
->ev
,
2848 state
->binding_handle
,
2849 state
->srv_name_slash
,
2850 state
->context
->client
.computer
,
2855 state
->validation_level
,
2857 &state
->authoritative
);
2858 if (tevent_req_nomem(subreq
, req
)) {
2859 status
= NT_STATUS_NO_MEMORY
;
2860 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2865 tevent_req_set_callback(subreq
,
2866 netlogon_creds_cli_LogonSamLogon_done
,
2870 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
)
2872 struct tevent_req
*req
=
2873 tevent_req_callback_data(subreq
,
2875 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2876 tevent_req_data(req
,
2877 struct netlogon_creds_cli_LogonSamLogon_state
);
2878 enum dcerpc_AuthType auth_type
;
2879 enum dcerpc_AuthLevel auth_level
;
2884 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2888 if (state
->try_logon_ex
) {
2889 status
= dcerpc_netr_LogonSamLogonEx_recv(subreq
,
2892 TALLOC_FREE(subreq
);
2893 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2894 state
->context
->server
.try_validation6
= false;
2895 state
->context
->server
.try_logon_ex
= false;
2896 netlogon_creds_cli_LogonSamLogon_start(req
);
2899 if (tevent_req_nterror(req
, status
)) {
2900 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2904 if ((state
->validation_level
== 6) &&
2905 (NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_INFO_CLASS
) ||
2906 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_PARAMETER
) ||
2907 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
)))
2909 state
->context
->server
.try_validation6
= false;
2910 netlogon_creds_cli_LogonSamLogon_start(req
);
2914 if (tevent_req_nterror(req
, result
)) {
2915 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2919 if (state
->ro_creds
== NULL
) {
2920 tevent_req_done(req
);
2924 ok
= netlogon_creds_cli_validate(state
->context
, state
->ro_creds
);
2927 * We got a race, lets retry with on authenticator
2930 * netlogon_creds_cli_LogonSamLogon_start()
2931 * will TALLOC_FREE(state->ro_creds);
2933 state
->try_logon_ex
= false;
2934 netlogon_creds_cli_LogonSamLogon_start(req
);
2938 status
= netlogon_creds_decrypt_samlogon_validation(state
->ro_creds
,
2939 state
->validation_level
,
2943 if (tevent_req_nterror(req
, status
)) {
2944 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2948 tevent_req_done(req
);
2952 if (state
->lk_creds
== NULL
) {
2953 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2955 TALLOC_FREE(subreq
);
2956 if (tevent_req_nterror(req
, status
)) {
2957 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2961 netlogon_creds_cli_LogonSamLogon_start(req
);
2965 if (state
->context
->server
.try_logon_with
) {
2966 status
= dcerpc_netr_LogonSamLogonWithFlags_recv(subreq
,
2969 TALLOC_FREE(subreq
);
2970 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2971 state
->context
->server
.try_logon_with
= false;
2972 netlogon_creds_cli_LogonSamLogon_start(req
);
2975 if (tevent_req_nterror(req
, status
)) {
2976 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2980 status
= dcerpc_netr_LogonSamLogon_recv(subreq
,
2983 TALLOC_FREE(subreq
);
2984 if (tevent_req_nterror(req
, status
)) {
2985 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2990 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
2991 &state
->rep_auth
.cred
,
2994 if (tevent_req_nterror(req
, status
)) {
2995 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2999 *state
->lk_creds
= state
->tmp_creds
;
3000 status
= netlogon_creds_cli_store(state
->context
,
3002 TALLOC_FREE(state
->lk_creds
);
3004 if (tevent_req_nterror(req
, status
)) {
3005 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
3009 if (tevent_req_nterror(req
, result
)) {
3010 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
3014 status
= netlogon_creds_decrypt_samlogon_validation(&state
->tmp_creds
,
3015 state
->validation_level
,
3019 if (tevent_req_nterror(req
, status
)) {
3020 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
3024 tevent_req_done(req
);
3027 NTSTATUS
netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req
*req
,
3028 TALLOC_CTX
*mem_ctx
,
3029 uint16_t *validation_level
,
3030 union netr_Validation
**validation
,
3031 uint8_t *authoritative
,
3034 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
3035 tevent_req_data(req
,
3036 struct netlogon_creds_cli_LogonSamLogon_state
);
3039 /* authoritative is also returned on error */
3040 *authoritative
= state
->authoritative
;
3042 if (tevent_req_is_nterror(req
, &status
)) {
3043 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
3044 tevent_req_received(req
);
3048 *validation_level
= state
->validation_level
;
3049 *validation
= talloc_move(mem_ctx
, &state
->validation
);
3050 *flags
= state
->flags
;
3052 tevent_req_received(req
);
3053 return NT_STATUS_OK
;
3056 NTSTATUS
netlogon_creds_cli_LogonSamLogon(
3057 struct netlogon_creds_cli_context
*context
,
3058 struct dcerpc_binding_handle
*b
,
3059 enum netr_LogonInfoClass logon_level
,
3060 const union netr_LogonLevel
*logon
,
3061 TALLOC_CTX
*mem_ctx
,
3062 uint16_t *validation_level
,
3063 union netr_Validation
**validation
,
3064 uint8_t *authoritative
,
3067 TALLOC_CTX
*frame
= talloc_stackframe();
3068 struct tevent_context
*ev
;
3069 struct tevent_req
*req
;
3070 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3072 ev
= samba_tevent_context_init(frame
);
3076 req
= netlogon_creds_cli_LogonSamLogon_send(frame
, ev
, context
, b
,
3082 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3085 status
= netlogon_creds_cli_LogonSamLogon_recv(req
, mem_ctx
,
3095 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
{
3096 struct tevent_context
*ev
;
3097 struct netlogon_creds_cli_context
*context
;
3098 struct dcerpc_binding_handle
*binding_handle
;
3100 char *srv_name_slash
;
3101 enum dcerpc_AuthType auth_type
;
3102 enum dcerpc_AuthLevel auth_level
;
3104 const char *site_name
;
3106 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
;
3108 struct netlogon_creds_CredentialState
*creds
;
3109 struct netlogon_creds_CredentialState tmp_creds
;
3110 struct netr_Authenticator req_auth
;
3111 struct netr_Authenticator rep_auth
;
3114 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
3116 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
);
3118 struct tevent_req
*netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX
*mem_ctx
,
3119 struct tevent_context
*ev
,
3120 struct netlogon_creds_cli_context
*context
,
3121 struct dcerpc_binding_handle
*b
,
3122 const char *site_name
,
3124 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
3126 struct tevent_req
*req
;
3127 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
;
3128 struct tevent_req
*subreq
;
3130 req
= tevent_req_create(mem_ctx
, &state
,
3131 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
3137 state
->context
= context
;
3138 state
->binding_handle
= b
;
3140 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3141 context
->server
.computer
);
3142 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3143 return tevent_req_post(req
, ev
);
3146 state
->site_name
= site_name
;
3147 state
->dns_ttl
= dns_ttl
;
3148 state
->dns_names
= dns_names
;
3150 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3152 &state
->auth_level
);
3154 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3156 if (tevent_req_nomem(subreq
, req
)) {
3157 return tevent_req_post(req
, ev
);
3160 tevent_req_set_callback(subreq
,
3161 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked
,
3167 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
3170 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
3171 tevent_req_data(req
,
3172 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
3174 if (state
->creds
== NULL
) {
3178 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3179 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3180 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3181 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3182 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3183 TALLOC_FREE(state
->creds
);
3187 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3188 TALLOC_FREE(state
->creds
);
3191 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
);
3193 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
)
3195 struct tevent_req
*req
=
3196 tevent_req_callback_data(subreq
,
3198 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
3199 tevent_req_data(req
,
3200 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
3203 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3205 TALLOC_FREE(subreq
);
3206 if (tevent_req_nterror(req
, status
)) {
3210 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
3213 DCERPC_AUTH_LEVEL_NONE
);
3214 if (tevent_req_nterror(req
, status
)) {
3219 * we defer all callbacks in order to cleanup
3220 * the database record.
3222 tevent_req_defer_callback(req
, state
->ev
);
3224 state
->tmp_creds
= *state
->creds
;
3225 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3227 if (tevent_req_nterror(req
, status
)) {
3230 ZERO_STRUCT(state
->rep_auth
);
3232 subreq
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state
, state
->ev
,
3233 state
->binding_handle
,
3234 state
->srv_name_slash
,
3235 state
->tmp_creds
.computer_name
,
3241 if (tevent_req_nomem(subreq
, req
)) {
3242 status
= NT_STATUS_NO_MEMORY
;
3243 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3247 tevent_req_set_callback(subreq
,
3248 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done
,
3252 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
)
3254 struct tevent_req
*req
=
3255 tevent_req_callback_data(subreq
,
3257 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
3258 tevent_req_data(req
,
3259 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
3264 * We use state->dns_names as the memory context, as this is
3265 * the only in/out variable and it has been overwritten by the
3266 * out parameter from the server.
3268 * We need to preserve the return value until the caller can use it.
3270 status
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq
, state
->dns_names
,
3272 TALLOC_FREE(subreq
);
3273 if (tevent_req_nterror(req
, status
)) {
3274 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3278 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
3279 &state
->rep_auth
.cred
,
3282 if (tevent_req_nterror(req
, status
)) {
3283 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3287 *state
->creds
= state
->tmp_creds
;
3288 status
= netlogon_creds_cli_store(state
->context
,
3290 TALLOC_FREE(state
->creds
);
3292 if (tevent_req_nterror(req
, status
)) {
3293 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3297 if (tevent_req_nterror(req
, result
)) {
3298 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, result
);
3302 tevent_req_done(req
);
3305 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req
*req
)
3309 if (tevent_req_is_nterror(req
, &status
)) {
3310 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
3311 tevent_req_received(req
);
3315 tevent_req_received(req
);
3316 return NT_STATUS_OK
;
3319 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3320 struct netlogon_creds_cli_context
*context
,
3321 struct dcerpc_binding_handle
*b
,
3322 const char *site_name
,
3324 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
3326 TALLOC_CTX
*frame
= talloc_stackframe();
3327 struct tevent_context
*ev
;
3328 struct tevent_req
*req
;
3329 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3331 ev
= samba_tevent_context_init(frame
);
3335 req
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame
, ev
, context
, b
,
3342 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3345 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req
);
3351 struct netlogon_creds_cli_ServerGetTrustInfo_state
{
3352 struct tevent_context
*ev
;
3353 struct netlogon_creds_cli_context
*context
;
3354 struct dcerpc_binding_handle
*binding_handle
;
3356 char *srv_name_slash
;
3357 enum dcerpc_AuthType auth_type
;
3358 enum dcerpc_AuthLevel auth_level
;
3360 struct samr_Password new_owf_password
;
3361 struct samr_Password old_owf_password
;
3362 struct netr_TrustInfo
*trust_info
;
3364 struct netlogon_creds_CredentialState
*creds
;
3365 struct netlogon_creds_CredentialState tmp_creds
;
3366 struct netr_Authenticator req_auth
;
3367 struct netr_Authenticator rep_auth
;
3370 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3372 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
);
3374 struct tevent_req
*netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX
*mem_ctx
,
3375 struct tevent_context
*ev
,
3376 struct netlogon_creds_cli_context
*context
,
3377 struct dcerpc_binding_handle
*b
)
3379 struct tevent_req
*req
;
3380 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
;
3381 struct tevent_req
*subreq
;
3383 req
= tevent_req_create(mem_ctx
, &state
,
3384 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3390 state
->context
= context
;
3391 state
->binding_handle
= b
;
3393 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3394 context
->server
.computer
);
3395 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3396 return tevent_req_post(req
, ev
);
3399 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3401 &state
->auth_level
);
3403 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3405 if (tevent_req_nomem(subreq
, req
)) {
3406 return tevent_req_post(req
, ev
);
3409 tevent_req_set_callback(subreq
,
3410 netlogon_creds_cli_ServerGetTrustInfo_locked
,
3416 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3419 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3420 tevent_req_data(req
,
3421 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3423 if (state
->creds
== NULL
) {
3427 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3428 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3429 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3430 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3431 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3432 TALLOC_FREE(state
->creds
);
3436 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3437 TALLOC_FREE(state
->creds
);
3440 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
);
3442 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
)
3444 struct tevent_req
*req
=
3445 tevent_req_callback_data(subreq
,
3447 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3448 tevent_req_data(req
,
3449 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3452 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3454 TALLOC_FREE(subreq
);
3455 if (tevent_req_nterror(req
, status
)) {
3459 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
3462 DCERPC_AUTH_LEVEL_PRIVACY
);
3463 if (tevent_req_nterror(req
, status
)) {
3468 * we defer all callbacks in order to cleanup
3469 * the database record.
3471 tevent_req_defer_callback(req
, state
->ev
);
3473 state
->tmp_creds
= *state
->creds
;
3474 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3476 if (tevent_req_nterror(req
, status
)) {
3479 ZERO_STRUCT(state
->rep_auth
);
3481 subreq
= dcerpc_netr_ServerGetTrustInfo_send(state
, state
->ev
,
3482 state
->binding_handle
,
3483 state
->srv_name_slash
,
3484 state
->tmp_creds
.account_name
,
3485 state
->tmp_creds
.secure_channel_type
,
3486 state
->tmp_creds
.computer_name
,
3489 &state
->new_owf_password
,
3490 &state
->old_owf_password
,
3491 &state
->trust_info
);
3492 if (tevent_req_nomem(subreq
, req
)) {
3493 status
= NT_STATUS_NO_MEMORY
;
3494 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3498 tevent_req_set_callback(subreq
,
3499 netlogon_creds_cli_ServerGetTrustInfo_done
,
3503 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
)
3505 struct tevent_req
*req
=
3506 tevent_req_callback_data(subreq
,
3508 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3509 tevent_req_data(req
,
3510 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3515 * We use state->dns_names as the memory context, as this is
3516 * the only in/out variable and it has been overwritten by the
3517 * out parameter from the server.
3519 * We need to preserve the return value until the caller can use it.
3521 status
= dcerpc_netr_ServerGetTrustInfo_recv(subreq
, state
, &result
);
3522 TALLOC_FREE(subreq
);
3523 if (tevent_req_nterror(req
, status
)) {
3524 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3528 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
3529 &state
->rep_auth
.cred
,
3532 if (tevent_req_nterror(req
, status
)) {
3533 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3537 status
= netlogon_creds_decrypt_samr_Password(&state
->tmp_creds
,
3538 &state
->new_owf_password
,
3541 if (tevent_req_nterror(req
, status
)) {
3542 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3545 status
= netlogon_creds_decrypt_samr_Password(&state
->tmp_creds
,
3546 &state
->old_owf_password
,
3549 if (tevent_req_nterror(req
, status
)) {
3550 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3554 *state
->creds
= state
->tmp_creds
;
3555 status
= netlogon_creds_cli_store(state
->context
,
3557 TALLOC_FREE(state
->creds
);
3558 if (tevent_req_nterror(req
, status
)) {
3559 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3563 if (tevent_req_nterror(req
, result
)) {
3564 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, result
);
3568 tevent_req_done(req
);
3571 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req
*req
,
3572 TALLOC_CTX
*mem_ctx
,
3573 struct samr_Password
*new_owf_password
,
3574 struct samr_Password
*old_owf_password
,
3575 struct netr_TrustInfo
**trust_info
)
3577 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3578 tevent_req_data(req
,
3579 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3582 if (tevent_req_is_nterror(req
, &status
)) {
3583 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3584 tevent_req_received(req
);
3588 if (new_owf_password
!= NULL
) {
3589 *new_owf_password
= state
->new_owf_password
;
3591 if (old_owf_password
!= NULL
) {
3592 *old_owf_password
= state
->old_owf_password
;
3594 if (trust_info
!= NULL
) {
3595 *trust_info
= talloc_move(mem_ctx
, &state
->trust_info
);
3598 tevent_req_received(req
);
3599 return NT_STATUS_OK
;
3602 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo(
3603 struct netlogon_creds_cli_context
*context
,
3604 struct dcerpc_binding_handle
*b
,
3605 TALLOC_CTX
*mem_ctx
,
3606 struct samr_Password
*new_owf_password
,
3607 struct samr_Password
*old_owf_password
,
3608 struct netr_TrustInfo
**trust_info
)
3610 TALLOC_CTX
*frame
= talloc_stackframe();
3611 struct tevent_context
*ev
;
3612 struct tevent_req
*req
;
3613 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3615 ev
= samba_tevent_context_init(frame
);
3619 req
= netlogon_creds_cli_ServerGetTrustInfo_send(frame
, ev
, context
, b
);
3623 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3626 status
= netlogon_creds_cli_ServerGetTrustInfo_recv(req
,
3636 struct netlogon_creds_cli_GetForestTrustInformation_state
{
3637 struct tevent_context
*ev
;
3638 struct netlogon_creds_cli_context
*context
;
3639 struct dcerpc_binding_handle
*binding_handle
;
3641 char *srv_name_slash
;
3642 enum dcerpc_AuthType auth_type
;
3643 enum dcerpc_AuthLevel auth_level
;
3646 struct lsa_ForestTrustInformation
*forest_trust_info
;
3648 struct netlogon_creds_CredentialState
*creds
;
3649 struct netlogon_creds_CredentialState tmp_creds
;
3650 struct netr_Authenticator req_auth
;
3651 struct netr_Authenticator rep_auth
;
3654 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3656 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
);
3658 struct tevent_req
*netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX
*mem_ctx
,
3659 struct tevent_context
*ev
,
3660 struct netlogon_creds_cli_context
*context
,
3661 struct dcerpc_binding_handle
*b
)
3663 struct tevent_req
*req
;
3664 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
;
3665 struct tevent_req
*subreq
;
3667 req
= tevent_req_create(mem_ctx
, &state
,
3668 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3674 state
->context
= context
;
3675 state
->binding_handle
= b
;
3677 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3678 context
->server
.computer
);
3679 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3680 return tevent_req_post(req
, ev
);
3685 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3687 &state
->auth_level
);
3689 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3691 if (tevent_req_nomem(subreq
, req
)) {
3692 return tevent_req_post(req
, ev
);
3695 tevent_req_set_callback(subreq
,
3696 netlogon_creds_cli_GetForestTrustInformation_locked
,
3702 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3705 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3706 tevent_req_data(req
,
3707 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3709 if (state
->creds
== NULL
) {
3713 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3714 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3715 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3716 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3717 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3718 TALLOC_FREE(state
->creds
);
3722 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3723 TALLOC_FREE(state
->creds
);
3726 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
);
3728 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
)
3730 struct tevent_req
*req
=
3731 tevent_req_callback_data(subreq
,
3733 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3734 tevent_req_data(req
,
3735 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3738 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3740 TALLOC_FREE(subreq
);
3741 if (tevent_req_nterror(req
, status
)) {
3745 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
3748 DCERPC_AUTH_LEVEL_NONE
);
3749 if (tevent_req_nterror(req
, status
)) {
3754 * we defer all callbacks in order to cleanup
3755 * the database record.
3757 tevent_req_defer_callback(req
, state
->ev
);
3759 state
->tmp_creds
= *state
->creds
;
3760 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3762 if (tevent_req_nterror(req
, status
)) {
3765 ZERO_STRUCT(state
->rep_auth
);
3767 subreq
= dcerpc_netr_GetForestTrustInformation_send(state
, state
->ev
,
3768 state
->binding_handle
,
3769 state
->srv_name_slash
,
3770 state
->tmp_creds
.computer_name
,
3774 &state
->forest_trust_info
);
3775 if (tevent_req_nomem(subreq
, req
)) {
3776 status
= NT_STATUS_NO_MEMORY
;
3777 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3781 tevent_req_set_callback(subreq
,
3782 netlogon_creds_cli_GetForestTrustInformation_done
,
3786 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
)
3788 struct tevent_req
*req
=
3789 tevent_req_callback_data(subreq
,
3791 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3792 tevent_req_data(req
,
3793 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3798 * We use state->dns_names as the memory context, as this is
3799 * the only in/out variable and it has been overwritten by the
3800 * out parameter from the server.
3802 * We need to preserve the return value until the caller can use it.
3804 status
= dcerpc_netr_GetForestTrustInformation_recv(subreq
, state
, &result
);
3805 TALLOC_FREE(subreq
);
3806 if (tevent_req_nterror(req
, status
)) {
3807 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3811 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
3812 &state
->rep_auth
.cred
,
3815 if (tevent_req_nterror(req
, status
)) {
3816 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3820 *state
->creds
= state
->tmp_creds
;
3821 status
= netlogon_creds_cli_store(state
->context
,
3823 TALLOC_FREE(state
->creds
);
3825 if (tevent_req_nterror(req
, status
)) {
3826 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3830 if (tevent_req_nterror(req
, result
)) {
3831 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, result
);
3835 tevent_req_done(req
);
3838 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req
*req
,
3839 TALLOC_CTX
*mem_ctx
,
3840 struct lsa_ForestTrustInformation
**forest_trust_info
)
3842 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3843 tevent_req_data(req
,
3844 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3847 if (tevent_req_is_nterror(req
, &status
)) {
3848 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3849 tevent_req_received(req
);
3853 *forest_trust_info
= talloc_move(mem_ctx
, &state
->forest_trust_info
);
3855 tevent_req_received(req
);
3856 return NT_STATUS_OK
;
3859 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation(
3860 struct netlogon_creds_cli_context
*context
,
3861 struct dcerpc_binding_handle
*b
,
3862 TALLOC_CTX
*mem_ctx
,
3863 struct lsa_ForestTrustInformation
**forest_trust_info
)
3865 TALLOC_CTX
*frame
= talloc_stackframe();
3866 struct tevent_context
*ev
;
3867 struct tevent_req
*req
;
3868 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3870 ev
= samba_tevent_context_init(frame
);
3874 req
= netlogon_creds_cli_GetForestTrustInformation_send(frame
, ev
, context
, b
);
3878 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3881 status
= netlogon_creds_cli_GetForestTrustInformation_recv(req
,
3888 struct netlogon_creds_cli_SendToSam_state
{
3889 struct tevent_context
*ev
;
3890 struct netlogon_creds_cli_context
*context
;
3891 struct dcerpc_binding_handle
*binding_handle
;
3893 char *srv_name_slash
;
3894 enum dcerpc_AuthType auth_type
;
3895 enum dcerpc_AuthLevel auth_level
;
3899 struct netlogon_creds_CredentialState
*creds
;
3900 struct netlogon_creds_CredentialState tmp_creds
;
3901 struct netr_Authenticator req_auth
;
3902 struct netr_Authenticator rep_auth
;
3905 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3907 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
);
3909 struct tevent_req
*netlogon_creds_cli_SendToSam_send(TALLOC_CTX
*mem_ctx
,
3910 struct tevent_context
*ev
,
3911 struct netlogon_creds_cli_context
*context
,
3912 struct dcerpc_binding_handle
*b
,
3913 struct netr_SendToSamBase
*message
)
3915 struct tevent_req
*req
;
3916 struct netlogon_creds_cli_SendToSam_state
*state
;
3917 struct tevent_req
*subreq
;
3918 enum ndr_err_code ndr_err
;
3920 req
= tevent_req_create(mem_ctx
, &state
,
3921 struct netlogon_creds_cli_SendToSam_state
);
3927 state
->context
= context
;
3928 state
->binding_handle
= b
;
3930 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3931 context
->server
.computer
);
3932 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3933 return tevent_req_post(req
, ev
);
3936 ndr_err
= ndr_push_struct_blob(&state
->opaque
, mem_ctx
, message
,
3937 (ndr_push_flags_fn_t
)ndr_push_netr_SendToSamBase
);
3938 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
3939 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
3940 tevent_req_nterror(req
, status
);
3941 return tevent_req_post(req
, ev
);
3944 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3946 &state
->auth_level
);
3948 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3950 if (tevent_req_nomem(subreq
, req
)) {
3951 return tevent_req_post(req
, ev
);
3954 tevent_req_set_callback(subreq
,
3955 netlogon_creds_cli_SendToSam_locked
,
3961 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3964 struct netlogon_creds_cli_SendToSam_state
*state
=
3965 tevent_req_data(req
,
3966 struct netlogon_creds_cli_SendToSam_state
);
3968 if (state
->creds
== NULL
) {
3972 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3973 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3974 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3975 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3976 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3977 TALLOC_FREE(state
->creds
);
3981 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3982 TALLOC_FREE(state
->creds
);
3985 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
);
3987 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
)
3989 struct tevent_req
*req
=
3990 tevent_req_callback_data(subreq
,
3992 struct netlogon_creds_cli_SendToSam_state
*state
=
3993 tevent_req_data(req
,
3994 struct netlogon_creds_cli_SendToSam_state
);
3997 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3999 TALLOC_FREE(subreq
);
4000 if (tevent_req_nterror(req
, status
)) {
4004 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
4007 DCERPC_AUTH_LEVEL_NONE
);
4008 if (tevent_req_nterror(req
, status
)) {
4013 * we defer all callbacks in order to cleanup
4014 * the database record.
4016 tevent_req_defer_callback(req
, state
->ev
);
4018 state
->tmp_creds
= *state
->creds
;
4019 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
4021 if (tevent_req_nterror(req
, status
)) {
4024 ZERO_STRUCT(state
->rep_auth
);
4026 status
= netlogon_creds_encrypt_SendToSam(&state
->tmp_creds
,
4028 state
->opaque
.length
,
4031 if (tevent_req_nterror(req
, status
)) {
4032 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4036 subreq
= dcerpc_netr_NetrLogonSendToSam_send(state
, state
->ev
,
4037 state
->binding_handle
,
4038 state
->srv_name_slash
,
4039 state
->tmp_creds
.computer_name
,
4043 state
->opaque
.length
);
4044 if (tevent_req_nomem(subreq
, req
)) {
4045 status
= NT_STATUS_NO_MEMORY
;
4046 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4050 tevent_req_set_callback(subreq
,
4051 netlogon_creds_cli_SendToSam_done
,
4055 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
)
4057 struct tevent_req
*req
=
4058 tevent_req_callback_data(subreq
,
4060 struct netlogon_creds_cli_SendToSam_state
*state
=
4061 tevent_req_data(req
,
4062 struct netlogon_creds_cli_SendToSam_state
);
4066 status
= dcerpc_netr_NetrLogonSendToSam_recv(subreq
, state
, &result
);
4067 TALLOC_FREE(subreq
);
4068 if (tevent_req_nterror(req
, status
)) {
4069 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4073 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
4074 &state
->rep_auth
.cred
,
4077 if (tevent_req_nterror(req
, status
)) {
4078 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4082 *state
->creds
= state
->tmp_creds
;
4083 status
= netlogon_creds_cli_store(state
->context
,
4085 TALLOC_FREE(state
->creds
);
4087 if (tevent_req_nterror(req
, status
)) {
4088 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4093 * Creds must be stored before we send back application errors
4094 * e.g. NT_STATUS_NOT_IMPLEMENTED
4096 if (tevent_req_nterror(req
, result
)) {
4097 netlogon_creds_cli_SendToSam_cleanup(req
, result
);
4101 tevent_req_done(req
);
4104 NTSTATUS
netlogon_creds_cli_SendToSam_recv(struct tevent_req
*req
)
4108 if (tevent_req_is_nterror(req
, &status
)) {
4109 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
4110 tevent_req_received(req
);
4114 tevent_req_received(req
);
4115 return NT_STATUS_OK
;
4118 NTSTATUS
netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context
*context
,
4119 struct dcerpc_binding_handle
*b
,
4120 struct netr_SendToSamBase
*message
)
4122 TALLOC_CTX
*frame
= talloc_stackframe();
4123 struct tevent_context
*ev
;
4124 struct tevent_req
*req
;
4125 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
4127 ev
= samba_tevent_context_init(frame
);
4131 req
= netlogon_creds_cli_SendToSam_send(frame
, ev
, context
, b
, message
);
4135 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4138 status
= netlogon_creds_cli_SendToSam_recv(req
);
4144 struct netlogon_creds_cli_LogonGetDomainInfo_state
{
4145 struct tevent_context
*ev
;
4146 struct netlogon_creds_cli_context
*context
;
4147 struct dcerpc_binding_handle
*binding_handle
;
4149 char *srv_name_slash
;
4150 enum dcerpc_AuthType auth_type
;
4151 enum dcerpc_AuthLevel auth_level
;
4154 union netr_WorkstationInfo
*query
;
4155 union netr_DomainInfo
*info
;
4157 struct netlogon_creds_CredentialState
*creds
;
4158 struct netlogon_creds_CredentialState tmp_creds
;
4159 struct netr_Authenticator req_auth
;
4160 struct netr_Authenticator rep_auth
;
4163 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
4165 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
);
4167 struct tevent_req
*netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX
*mem_ctx
,
4168 struct tevent_context
*ev
,
4169 struct netlogon_creds_cli_context
*context
,
4170 struct dcerpc_binding_handle
*b
,
4172 union netr_WorkstationInfo
*query
)
4174 struct tevent_req
*req
;
4175 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
;
4176 struct tevent_req
*subreq
;
4178 req
= tevent_req_create(mem_ctx
, &state
,
4179 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4185 state
->context
= context
;
4186 state
->binding_handle
= b
;
4188 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
4189 context
->server
.computer
);
4190 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
4191 return tevent_req_post(req
, ev
);
4194 state
->level
= level
;
4195 state
->query
= query
;
4196 state
->info
= talloc_zero(state
, union netr_DomainInfo
);
4197 if (tevent_req_nomem(state
->info
, req
)) {
4198 return tevent_req_post(req
, ev
);
4201 dcerpc_binding_handle_auth_info(state
->binding_handle
,
4203 &state
->auth_level
);
4205 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
4207 if (tevent_req_nomem(subreq
, req
)) {
4208 return tevent_req_post(req
, ev
);
4211 tevent_req_set_callback(subreq
,
4212 netlogon_creds_cli_LogonGetDomainInfo_locked
,
4218 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
4221 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4222 tevent_req_data(req
,
4223 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4225 if (state
->creds
== NULL
) {
4229 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
4230 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
4231 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
4232 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
4233 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
4234 TALLOC_FREE(state
->creds
);
4238 netlogon_creds_cli_delete(state
->context
, state
->creds
);
4241 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
);
4243 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
)
4245 struct tevent_req
*req
=
4246 tevent_req_callback_data(subreq
,
4248 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4249 tevent_req_data(req
,
4250 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4253 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
4255 TALLOC_FREE(subreq
);
4256 if (tevent_req_nterror(req
, status
)) {
4260 status
= netlogon_creds_cli_check_transport(state
->auth_type
,
4263 DCERPC_AUTH_LEVEL_NONE
);
4264 if (tevent_req_nterror(req
, status
)) {
4269 * we defer all callbacks in order to cleanup
4270 * the database record.
4272 tevent_req_defer_callback(req
, state
->ev
);
4274 state
->tmp_creds
= *state
->creds
;
4275 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
4277 if (tevent_req_nterror(req
, status
)) {
4280 ZERO_STRUCT(state
->rep_auth
);
4282 subreq
= dcerpc_netr_LogonGetDomainInfo_send(state
, state
->ev
,
4283 state
->binding_handle
,
4284 state
->srv_name_slash
,
4285 state
->tmp_creds
.computer_name
,
4291 if (tevent_req_nomem(subreq
, req
)) {
4292 status
= NT_STATUS_NO_MEMORY
;
4293 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4297 tevent_req_set_callback(subreq
,
4298 netlogon_creds_cli_LogonGetDomainInfo_done
,
4302 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
)
4304 struct tevent_req
*req
=
4305 tevent_req_callback_data(subreq
,
4307 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4308 tevent_req_data(req
,
4309 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4314 * We use state->dns_names as the memory context, as this is
4315 * the only in/out variable and it has been overwritten by the
4316 * out parameter from the server.
4318 * We need to preserve the return value until the caller can use it.
4320 status
= dcerpc_netr_LogonGetDomainInfo_recv(subreq
, state
->info
, &result
);
4321 TALLOC_FREE(subreq
);
4322 if (tevent_req_nterror(req
, status
)) {
4323 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4327 status
= netlogon_creds_client_verify(&state
->tmp_creds
,
4328 &state
->rep_auth
.cred
,
4331 if (tevent_req_nterror(req
, status
)) {
4332 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4336 if (tevent_req_nterror(req
, result
)) {
4337 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, result
);
4341 *state
->creds
= state
->tmp_creds
;
4342 status
= netlogon_creds_cli_store(state
->context
,
4344 if (tevent_req_nterror(req
, status
)) {
4345 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4349 tevent_req_done(req
);
4352 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req
*req
,
4353 TALLOC_CTX
*mem_ctx
,
4354 union netr_DomainInfo
**info
)
4356 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4357 tevent_req_data(req
,
4358 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4361 if (tevent_req_is_nterror(req
, &status
)) {
4362 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4363 tevent_req_received(req
);
4367 *info
= talloc_move(mem_ctx
, &state
->info
);
4369 tevent_req_received(req
);
4370 return NT_STATUS_OK
;
4373 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo(
4374 struct netlogon_creds_cli_context
*context
,
4375 struct dcerpc_binding_handle
*b
,
4376 TALLOC_CTX
*mem_ctx
,
4378 union netr_WorkstationInfo
*query
,
4379 union netr_DomainInfo
**info
)
4381 TALLOC_CTX
*frame
= talloc_stackframe();
4382 struct tevent_context
*ev
;
4383 struct tevent_req
*req
;
4384 NTSTATUS status
= NT_STATUS_OK
;
4386 ev
= samba_tevent_context_init(frame
);
4390 req
= netlogon_creds_cli_LogonGetDomainInfo_send(frame
, ev
, context
, b
,
4395 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4398 status
= netlogon_creds_cli_LogonGetDomainInfo_recv(req
,