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"
43 struct netlogon_creds_cli_locked_state
;
45 struct netlogon_creds_cli_context
{
49 uint32_t proposed_flags
;
50 uint32_t required_flags
;
51 enum netr_SchannelType type
;
52 enum dcerpc_AuthLevel auth_level
;
57 const char *netbios_domain
;
58 const char *dns_domain
;
59 uint32_t cached_flags
;
68 struct db_context
*ctx
;
69 struct g_lock_ctx
*g_ctx
;
70 struct netlogon_creds_cli_locked_state
*locked_state
;
71 enum netlogon_creds_cli_lck_type lock
;
75 struct netlogon_creds_cli_locked_state
{
76 struct netlogon_creds_cli_context
*context
;
78 struct netlogon_creds_CredentialState
*creds
;
81 static int netlogon_creds_cli_locked_state_destructor(
82 struct netlogon_creds_cli_locked_state
*state
)
84 struct netlogon_creds_cli_context
*context
= state
->context
;
86 if (context
== NULL
) {
90 if (context
->db
.locked_state
== state
) {
91 context
->db
.locked_state
= NULL
;
94 if (state
->is_glocked
) {
95 g_lock_unlock(context
->db
.g_ctx
,
96 string_term_tdb_data(context
->db
.key_name
));
102 static NTSTATUS
netlogon_creds_cli_context_common(
103 const char *client_computer
,
104 const char *client_account
,
105 enum netr_SchannelType type
,
106 enum dcerpc_AuthLevel auth_level
,
107 uint32_t proposed_flags
,
108 uint32_t required_flags
,
109 const char *server_computer
,
110 const char *server_netbios_domain
,
111 const char *server_dns_domain
,
113 struct netlogon_creds_cli_context
**_context
)
115 struct netlogon_creds_cli_context
*context
= NULL
;
116 char *_key_name
= NULL
;
117 size_t server_netbios_name_len
;
122 context
= talloc_zero(mem_ctx
, struct netlogon_creds_cli_context
);
123 if (context
== NULL
) {
124 return NT_STATUS_NO_MEMORY
;
127 context
->client
.computer
= talloc_strdup(context
, client_computer
);
128 if (context
->client
.computer
== NULL
) {
129 TALLOC_FREE(context
);
130 return NT_STATUS_NO_MEMORY
;
133 context
->client
.account
= talloc_strdup(context
, client_account
);
134 if (context
->client
.account
== NULL
) {
135 TALLOC_FREE(context
);
136 return NT_STATUS_NO_MEMORY
;
139 context
->client
.proposed_flags
= proposed_flags
;
140 context
->client
.required_flags
= required_flags
;
141 context
->client
.type
= type
;
142 context
->client
.auth_level
= auth_level
;
144 context
->server
.computer
= talloc_strdup(context
, server_computer
);
145 if (context
->server
.computer
== NULL
) {
146 TALLOC_FREE(context
);
147 return NT_STATUS_NO_MEMORY
;
150 context
->server
.netbios_domain
= talloc_strdup(context
, server_netbios_domain
);
151 if (context
->server
.netbios_domain
== NULL
) {
152 TALLOC_FREE(context
);
153 return NT_STATUS_NO_MEMORY
;
156 context
->server
.dns_domain
= talloc_strdup(context
, server_dns_domain
);
157 if (context
->server
.dns_domain
== NULL
) {
158 TALLOC_FREE(context
);
159 return NT_STATUS_NO_MEMORY
;
164 * Force the callers to provide a unique
165 * value for server_computer and use this directly.
167 * For now we have to deal with
168 * "HOSTNAME" vs. "hostname.example.com".
171 p
= strchr(server_computer
, '.');
173 server_netbios_name_len
= p
-server_computer
;
175 server_netbios_name_len
= strlen(server_computer
);
178 _key_name
= talloc_asprintf(context
, "CLI[%s/%s]/SRV[%.*s/%s]",
181 (int)server_netbios_name_len
,
183 server_netbios_domain
);
184 if (_key_name
== NULL
) {
185 TALLOC_FREE(context
);
186 return NT_STATUS_NO_MEMORY
;
189 context
->db
.key_name
= talloc_strdup_upper(context
, _key_name
);
190 TALLOC_FREE(_key_name
);
191 if (context
->db
.key_name
== NULL
) {
192 TALLOC_FREE(context
);
193 return NT_STATUS_NO_MEMORY
;
196 context
->db
.key_data
= string_term_tdb_data(context
->db
.key_name
);
202 static struct db_context
*netlogon_creds_cli_global_db
;
204 NTSTATUS
netlogon_creds_cli_set_global_db(struct db_context
**db
)
206 if (netlogon_creds_cli_global_db
!= NULL
) {
207 return NT_STATUS_INVALID_PARAMETER_MIX
;
210 netlogon_creds_cli_global_db
= talloc_move(NULL
, db
);
214 NTSTATUS
netlogon_creds_cli_open_global_db(struct loadparm_context
*lp_ctx
)
217 struct db_context
*global_db
;
218 int hash_size
, tdb_flags
;
220 if (netlogon_creds_cli_global_db
!= NULL
) {
224 fname
= lpcfg_private_db_path(NULL
, lp_ctx
, "netlogon_creds_cli");
226 return NT_STATUS_NO_MEMORY
;
229 hash_size
= lpcfg_tdb_hash_size(lp_ctx
, fname
);
230 tdb_flags
= lpcfg_tdb_flags(
232 TDB_CLEAR_IF_FIRST
|TDB_INCOMPATIBLE_HASH
);
234 global_db
= dbwrap_local_open(
243 if (global_db
== NULL
) {
244 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
245 fname
, strerror(errno
)));
247 return NT_STATUS_NO_MEMORY
;
251 netlogon_creds_cli_global_db
= global_db
;
255 void netlogon_creds_cli_close_global_db(void)
257 TALLOC_FREE(netlogon_creds_cli_global_db
);
260 NTSTATUS
netlogon_creds_cli_context_global(struct loadparm_context
*lp_ctx
,
261 struct messaging_context
*msg_ctx
,
262 const char *client_account
,
263 enum netr_SchannelType type
,
264 const char *server_computer
,
265 const char *server_netbios_domain
,
266 const char *server_dns_domain
,
268 struct netlogon_creds_cli_context
**_context
)
270 TALLOC_CTX
*frame
= talloc_stackframe();
272 struct netlogon_creds_cli_context
*context
= NULL
;
273 const char *client_computer
;
274 uint32_t proposed_flags
;
275 uint32_t required_flags
= 0;
276 bool reject_md5_servers
= false;
277 bool require_strong_key
= false;
278 int require_sign_or_seal
= true;
279 bool seal_secure_channel
= true;
280 enum dcerpc_AuthLevel auth_level
= DCERPC_AUTH_LEVEL_NONE
;
281 bool neutralize_nt4_emulation
= false;
285 if (msg_ctx
== NULL
) {
287 return NT_STATUS_INVALID_PARAMETER_MIX
;
290 client_computer
= lpcfg_netbios_name(lp_ctx
);
291 if (strlen(client_computer
) > 15) {
293 return NT_STATUS_INVALID_PARAMETER_MIX
;
297 * allow overwrite per domain
298 * reject md5 servers:<netbios_domain>
300 reject_md5_servers
= lpcfg_reject_md5_servers(lp_ctx
);
301 reject_md5_servers
= lpcfg_parm_bool(lp_ctx
, NULL
,
302 "reject md5 servers",
303 server_netbios_domain
,
307 * allow overwrite per domain
308 * require strong key:<netbios_domain>
310 require_strong_key
= lpcfg_require_strong_key(lp_ctx
);
311 require_strong_key
= lpcfg_parm_bool(lp_ctx
, NULL
,
312 "require strong key",
313 server_netbios_domain
,
317 * allow overwrite per domain
318 * client schannel:<netbios_domain>
320 require_sign_or_seal
= lpcfg_client_schannel(lp_ctx
);
321 require_sign_or_seal
= lpcfg_parm_int(lp_ctx
, NULL
,
323 server_netbios_domain
,
324 require_sign_or_seal
);
327 * allow overwrite per domain
328 * winbind sealed pipes:<netbios_domain>
330 seal_secure_channel
= lpcfg_winbind_sealed_pipes(lp_ctx
);
331 seal_secure_channel
= lpcfg_parm_bool(lp_ctx
, NULL
,
332 "winbind sealed pipes",
333 server_netbios_domain
,
334 seal_secure_channel
);
337 * allow overwrite per domain
338 * neutralize nt4 emulation:<netbios_domain>
340 neutralize_nt4_emulation
= lpcfg_neutralize_nt4_emulation(lp_ctx
);
341 neutralize_nt4_emulation
= lpcfg_parm_bool(lp_ctx
, NULL
,
342 "neutralize nt4 emulation",
343 server_netbios_domain
,
344 neutralize_nt4_emulation
);
346 proposed_flags
= NETLOGON_NEG_AUTH2_ADS_FLAGS
;
347 proposed_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
351 if (lpcfg_security(lp_ctx
) == SEC_ADS
) {
353 * AD domains should be secure
355 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
356 require_sign_or_seal
= true;
357 require_strong_key
= true;
361 case SEC_CHAN_DOMAIN
:
364 case SEC_CHAN_DNS_DOMAIN
:
366 * AD domains should be secure
368 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
369 require_sign_or_seal
= true;
370 require_strong_key
= true;
371 neutralize_nt4_emulation
= true;
375 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
376 require_sign_or_seal
= true;
377 require_strong_key
= true;
381 required_flags
|= NETLOGON_NEG_RODC_PASSTHROUGH
;
382 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
383 require_sign_or_seal
= true;
384 require_strong_key
= true;
385 neutralize_nt4_emulation
= true;
390 return NT_STATUS_INVALID_PARAMETER
;
393 if (neutralize_nt4_emulation
) {
394 proposed_flags
|= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION
;
397 if (require_sign_or_seal
) {
398 required_flags
|= NETLOGON_NEG_ARCFOUR
;
399 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
401 proposed_flags
&= ~NETLOGON_NEG_AUTHENTICATED_RPC
;
404 if (reject_md5_servers
) {
405 required_flags
|= NETLOGON_NEG_ARCFOUR
;
406 required_flags
|= NETLOGON_NEG_PASSWORD_SET2
;
407 required_flags
|= NETLOGON_NEG_SUPPORTS_AES
;
408 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
411 if (require_strong_key
) {
412 required_flags
|= NETLOGON_NEG_ARCFOUR
;
413 required_flags
|= NETLOGON_NEG_STRONG_KEYS
;
414 required_flags
|= NETLOGON_NEG_AUTHENTICATED_RPC
;
417 proposed_flags
|= required_flags
;
419 if (seal_secure_channel
) {
420 auth_level
= DCERPC_AUTH_LEVEL_PRIVACY
;
422 auth_level
= DCERPC_AUTH_LEVEL_INTEGRITY
;
425 status
= netlogon_creds_cli_context_common(client_computer
,
432 server_netbios_domain
,
436 if (!NT_STATUS_IS_OK(status
)) {
441 context
->db
.g_ctx
= g_lock_ctx_init(context
, msg_ctx
);
442 if (context
->db
.g_ctx
== NULL
) {
443 TALLOC_FREE(context
);
445 return NT_STATUS_NO_MEMORY
;
448 status
= netlogon_creds_cli_open_global_db(lp_ctx
);
449 if (!NT_STATUS_IS_OK(status
)) {
450 TALLOC_FREE(context
);
452 return NT_STATUS_NO_MEMORY
;
455 context
->db
.ctx
= netlogon_creds_cli_global_db
;
461 NTSTATUS
netlogon_creds_bind_cli_credentials(
462 struct netlogon_creds_cli_context
*context
, TALLOC_CTX
*mem_ctx
,
463 struct cli_credentials
**pcli_creds
)
465 struct cli_credentials
*cli_creds
;
466 struct netlogon_creds_CredentialState
*ncreds
;
469 cli_creds
= cli_credentials_init(mem_ctx
);
470 if (cli_creds
== NULL
) {
471 return NT_STATUS_NO_MEMORY
;
473 cli_credentials_set_secure_channel_type(cli_creds
,
474 context
->client
.type
);
475 cli_credentials_set_username(cli_creds
, context
->client
.account
,
477 cli_credentials_set_domain(cli_creds
, context
->server
.netbios_domain
,
479 cli_credentials_set_realm(cli_creds
, context
->server
.dns_domain
,
482 status
= netlogon_creds_cli_get(context
, cli_creds
, &ncreds
);
483 if (!NT_STATUS_IS_OK(status
)) {
484 TALLOC_FREE(cli_creds
);
487 cli_credentials_set_netlogon_creds(cli_creds
, ncreds
);
489 *pcli_creds
= cli_creds
;
493 char *netlogon_creds_cli_debug_string(
494 const struct netlogon_creds_cli_context
*context
,
497 return talloc_asprintf(mem_ctx
, "netlogon_creds_cli:%s",
498 context
->db
.key_name
);
501 enum dcerpc_AuthLevel
netlogon_creds_cli_auth_level(
502 struct netlogon_creds_cli_context
*context
)
504 return context
->client
.auth_level
;
507 struct netlogon_creds_cli_fetch_state
{
509 struct netlogon_creds_CredentialState
*creds
;
510 uint32_t required_flags
;
514 static void netlogon_creds_cli_fetch_parser(TDB_DATA key
, TDB_DATA data
,
517 struct netlogon_creds_cli_fetch_state
*state
=
518 (struct netlogon_creds_cli_fetch_state
*)private_data
;
519 enum ndr_err_code ndr_err
;
523 state
->creds
= talloc_zero(state
->mem_ctx
,
524 struct netlogon_creds_CredentialState
);
525 if (state
->creds
== NULL
) {
526 state
->status
= NT_STATUS_NO_MEMORY
;
530 blob
.data
= data
.dptr
;
531 blob
.length
= data
.dsize
;
533 ndr_err
= ndr_pull_struct_blob(&blob
, state
->creds
, state
->creds
,
534 (ndr_pull_flags_fn_t
)ndr_pull_netlogon_creds_CredentialState
);
535 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
536 TALLOC_FREE(state
->creds
);
537 state
->status
= ndr_map_error2ntstatus(ndr_err
);
541 if (DEBUGLEVEL
>= 10) {
542 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, state
->creds
);
545 tmp_flags
= state
->creds
->negotiate_flags
;
546 tmp_flags
&= state
->required_flags
;
547 if (tmp_flags
!= state
->required_flags
) {
548 TALLOC_FREE(state
->creds
);
549 state
->status
= NT_STATUS_DOWNGRADE_DETECTED
;
553 state
->status
= NT_STATUS_OK
;
556 static NTSTATUS
netlogon_creds_cli_get_internal(
557 struct netlogon_creds_cli_context
*context
,
558 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
);
560 NTSTATUS
netlogon_creds_cli_get(struct netlogon_creds_cli_context
*context
,
562 struct netlogon_creds_CredentialState
**_creds
)
565 struct netlogon_creds_CredentialState
*creds
;
569 status
= netlogon_creds_cli_get_internal(context
, mem_ctx
, &creds
);
570 if (!NT_STATUS_IS_OK(status
)) {
575 * mark it as invalid for step operations.
578 creds
->seed
= (struct netr_Credential
) {{0}};
579 creds
->client
= (struct netr_Credential
) {{0}};
580 creds
->server
= (struct netr_Credential
) {{0}};
586 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context
*context
,
587 const struct netlogon_creds_CredentialState
*creds1
)
589 TALLOC_CTX
*frame
= talloc_stackframe();
590 struct netlogon_creds_CredentialState
*creds2
;
594 enum ndr_err_code ndr_err
;
597 status
= netlogon_creds_cli_get(context
, frame
, &creds2
);
598 if (!NT_STATUS_IS_OK(status
)) {
603 ndr_err
= ndr_push_struct_blob(&blob1
, frame
, creds1
,
604 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
605 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
610 ndr_err
= ndr_push_struct_blob(&blob2
, frame
, creds2
,
611 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
612 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
617 cmp
= data_blob_cmp(&blob1
, &blob2
);
624 static NTSTATUS
netlogon_creds_cli_store_internal(
625 struct netlogon_creds_cli_context
*context
,
626 struct netlogon_creds_CredentialState
*creds
)
629 enum ndr_err_code ndr_err
;
633 if (DEBUGLEVEL
>= 10) {
634 NDR_PRINT_DEBUG(netlogon_creds_CredentialState
, creds
);
637 ndr_err
= ndr_push_struct_blob(&blob
, creds
, creds
,
638 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
639 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
640 status
= ndr_map_error2ntstatus(ndr_err
);
644 data
.dptr
= blob
.data
;
645 data
.dsize
= blob
.length
;
647 status
= dbwrap_store(context
->db
.ctx
,
648 context
->db
.key_data
,
650 TALLOC_FREE(data
.dptr
);
651 if (!NT_STATUS_IS_OK(status
)) {
658 NTSTATUS
netlogon_creds_cli_store(struct netlogon_creds_cli_context
*context
,
659 struct netlogon_creds_CredentialState
*creds
)
663 if (context
->db
.locked_state
== NULL
) {
665 * this was not the result of netlogon_creds_cli_lock*()
667 return NT_STATUS_INVALID_PAGE_PROTECTION
;
670 if (context
->db
.locked_state
->creds
!= creds
) {
672 * this was not the result of netlogon_creds_cli_lock*()
674 return NT_STATUS_INVALID_PAGE_PROTECTION
;
677 status
= netlogon_creds_cli_store_internal(context
, creds
);
681 static NTSTATUS
netlogon_creds_cli_delete_internal(
682 struct netlogon_creds_cli_context
*context
)
685 status
= dbwrap_delete(context
->db
.ctx
, context
->db
.key_data
);
689 NTSTATUS
netlogon_creds_cli_delete_lck(
690 struct netlogon_creds_cli_context
*context
)
694 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
695 return NT_STATUS_NOT_LOCKED
;
698 status
= netlogon_creds_cli_delete_internal(context
);
702 NTSTATUS
netlogon_creds_cli_delete(struct netlogon_creds_cli_context
*context
,
703 struct netlogon_creds_CredentialState
*creds
)
707 if (context
->db
.locked_state
== NULL
) {
709 * this was not the result of netlogon_creds_cli_lock*()
711 return NT_STATUS_INVALID_PAGE_PROTECTION
;
714 if (context
->db
.locked_state
->creds
!= creds
) {
716 * this was not the result of netlogon_creds_cli_lock*()
718 return NT_STATUS_INVALID_PAGE_PROTECTION
;
721 status
= netlogon_creds_cli_delete_internal(context
);
725 struct netlogon_creds_cli_lock_state
{
726 struct netlogon_creds_cli_locked_state
*locked_state
;
727 struct netlogon_creds_CredentialState
*creds
;
730 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
);
732 struct tevent_req
*netlogon_creds_cli_lock_send(TALLOC_CTX
*mem_ctx
,
733 struct tevent_context
*ev
,
734 struct netlogon_creds_cli_context
*context
)
736 struct tevent_req
*req
;
737 struct netlogon_creds_cli_lock_state
*state
;
738 struct netlogon_creds_cli_locked_state
*locked_state
;
739 struct tevent_req
*subreq
;
741 req
= tevent_req_create(mem_ctx
, &state
,
742 struct netlogon_creds_cli_lock_state
);
747 if (context
->db
.locked_state
!= NULL
) {
748 tevent_req_nterror(req
, NT_STATUS_LOCK_NOT_GRANTED
);
749 return tevent_req_post(req
, ev
);
752 locked_state
= talloc_zero(state
, struct netlogon_creds_cli_locked_state
);
753 if (tevent_req_nomem(locked_state
, req
)) {
754 return tevent_req_post(req
, ev
);
756 talloc_set_destructor(locked_state
,
757 netlogon_creds_cli_locked_state_destructor
);
758 locked_state
->context
= context
;
760 context
->db
.locked_state
= locked_state
;
761 state
->locked_state
= locked_state
;
763 if (context
->db
.g_ctx
== NULL
) {
766 status
= netlogon_creds_cli_get_internal(
767 context
, state
, &state
->creds
);
768 if (tevent_req_nterror(req
, status
)) {
769 return tevent_req_post(req
, ev
);
775 subreq
= g_lock_lock_send(state
, ev
,
777 string_term_tdb_data(context
->db
.key_name
),
779 if (tevent_req_nomem(subreq
, req
)) {
780 return tevent_req_post(req
, ev
);
782 tevent_req_set_callback(subreq
, netlogon_creds_cli_lock_done
, req
);
787 static void netlogon_creds_cli_lock_done(struct tevent_req
*subreq
)
789 struct tevent_req
*req
=
790 tevent_req_callback_data(subreq
,
792 struct netlogon_creds_cli_lock_state
*state
=
794 struct netlogon_creds_cli_lock_state
);
797 status
= g_lock_lock_recv(subreq
);
799 if (tevent_req_nterror(req
, status
)) {
802 state
->locked_state
->is_glocked
= true;
804 status
= netlogon_creds_cli_get_internal(state
->locked_state
->context
,
805 state
, &state
->creds
);
806 if (tevent_req_nterror(req
, status
)) {
809 tevent_req_done(req
);
812 static NTSTATUS
netlogon_creds_cli_get_internal(
813 struct netlogon_creds_cli_context
*context
,
814 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_CredentialState
**pcreds
)
816 struct netlogon_creds_cli_fetch_state fstate
= {
817 .status
= NT_STATUS_INTERNAL_ERROR
,
818 .required_flags
= context
->client
.required_flags
,
822 fstate
.mem_ctx
= mem_ctx
;
823 status
= dbwrap_parse_record(context
->db
.ctx
,
824 context
->db
.key_data
,
825 netlogon_creds_cli_fetch_parser
,
827 if (!NT_STATUS_IS_OK(status
)) {
830 if (!NT_STATUS_IS_OK(fstate
.status
)) {
831 return fstate
.status
;
834 if (context
->server
.cached_flags
== fstate
.creds
->negotiate_flags
) {
835 *pcreds
= fstate
.creds
;
840 * It is really important to try SamLogonEx here,
841 * because multiple processes can talk to the same
842 * domain controller, without using the credential
845 * With a normal SamLogon call, we must keep the
846 * credentials chain updated and intact between all
847 * users of the machine account (which would imply
848 * cross-node communication for every NTLM logon).
850 * The credentials chain is not per NETLOGON pipe
851 * connection, but globally on the server/client pair
854 * It's also important to use NetlogonValidationSamInfo4 (6),
855 * because it relies on the rpc transport encryption
856 * and avoids using the global netlogon schannel
857 * session key to en/decrypt secret information
858 * like the user_session_key for network logons.
860 * [MS-APDS] 3.1.5.2 NTLM Network Logon
861 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
862 * NETLOGON_NEG_AUTHENTICATED_RPC set together
863 * are the indication that the server supports
864 * NetlogonValidationSamInfo4 (6). And it must only
865 * be used if "SealSecureChannel" is used.
867 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
868 * check is done in netlogon_creds_cli_LogonSamLogon*().
871 context
->server
.cached_flags
= fstate
.creds
->negotiate_flags
;
872 context
->server
.try_validation6
= true;
873 context
->server
.try_logon_ex
= true;
874 context
->server
.try_logon_with
= true;
876 if (!(context
->server
.cached_flags
& NETLOGON_NEG_AUTHENTICATED_RPC
)) {
877 context
->server
.try_validation6
= false;
878 context
->server
.try_logon_ex
= false;
880 if (!(context
->server
.cached_flags
& NETLOGON_NEG_CROSS_FOREST_TRUSTS
)) {
881 context
->server
.try_validation6
= false;
884 *pcreds
= fstate
.creds
;
888 NTSTATUS
netlogon_creds_cli_lock_recv(struct tevent_req
*req
,
890 struct netlogon_creds_CredentialState
**creds
)
892 struct netlogon_creds_cli_lock_state
*state
=
894 struct netlogon_creds_cli_lock_state
);
897 if (tevent_req_is_nterror(req
, &status
)) {
898 tevent_req_received(req
);
902 talloc_steal(state
->creds
, state
->locked_state
);
903 state
->locked_state
->creds
= state
->creds
;
904 *creds
= talloc_move(mem_ctx
, &state
->creds
);
905 tevent_req_received(req
);
909 NTSTATUS
netlogon_creds_cli_lock(struct netlogon_creds_cli_context
*context
,
911 struct netlogon_creds_CredentialState
**creds
)
913 TALLOC_CTX
*frame
= talloc_stackframe();
914 struct tevent_context
*ev
;
915 struct tevent_req
*req
;
916 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
918 ev
= samba_tevent_context_init(frame
);
922 req
= netlogon_creds_cli_lock_send(frame
, ev
, context
);
926 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
929 status
= netlogon_creds_cli_lock_recv(req
, mem_ctx
, creds
);
935 struct netlogon_creds_cli_lck
{
936 struct netlogon_creds_cli_context
*context
;
939 struct netlogon_creds_cli_lck_state
{
940 struct netlogon_creds_cli_lck
*lck
;
941 enum netlogon_creds_cli_lck_type type
;
944 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
);
945 static int netlogon_creds_cli_lck_destructor(
946 struct netlogon_creds_cli_lck
*lck
);
948 struct tevent_req
*netlogon_creds_cli_lck_send(
949 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
950 struct netlogon_creds_cli_context
*context
,
951 enum netlogon_creds_cli_lck_type type
)
953 struct tevent_req
*req
, *subreq
;
954 struct netlogon_creds_cli_lck_state
*state
;
955 enum g_lock_type gtype
;
957 req
= tevent_req_create(mem_ctx
, &state
,
958 struct netlogon_creds_cli_lck_state
);
963 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_NONE
) {
964 DBG_DEBUG("context already locked\n");
965 tevent_req_nterror(req
, NT_STATUS_INVALID_LOCK_SEQUENCE
);
966 return tevent_req_post(req
, ev
);
970 case NETLOGON_CREDS_CLI_LCK_SHARED
:
973 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
:
974 gtype
= G_LOCK_WRITE
;
977 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
978 return tevent_req_post(req
, ev
);
981 state
->lck
= talloc(state
, struct netlogon_creds_cli_lck
);
982 if (tevent_req_nomem(state
->lck
, req
)) {
983 return tevent_req_post(req
, ev
);
985 state
->lck
->context
= context
;
988 subreq
= g_lock_lock_send(state
, ev
,
990 string_term_tdb_data(context
->db
.key_name
),
992 if (tevent_req_nomem(subreq
, req
)) {
993 return tevent_req_post(req
, ev
);
995 tevent_req_set_callback(subreq
, netlogon_creds_cli_lck_locked
, req
);
1000 static void netlogon_creds_cli_lck_locked(struct tevent_req
*subreq
)
1002 struct tevent_req
*req
= tevent_req_callback_data(
1003 subreq
, struct tevent_req
);
1004 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1005 req
, struct netlogon_creds_cli_lck_state
);
1008 status
= g_lock_lock_recv(subreq
);
1009 TALLOC_FREE(subreq
);
1010 if (tevent_req_nterror(req
, status
)) {
1014 state
->lck
->context
->db
.lock
= state
->type
;
1015 talloc_set_destructor(state
->lck
, netlogon_creds_cli_lck_destructor
);
1017 tevent_req_done(req
);
1020 static int netlogon_creds_cli_lck_destructor(
1021 struct netlogon_creds_cli_lck
*lck
)
1023 struct netlogon_creds_cli_context
*ctx
= lck
->context
;
1026 status
= g_lock_unlock(ctx
->db
.g_ctx
,
1027 string_term_tdb_data(ctx
->db
.key_name
));
1028 if (!NT_STATUS_IS_OK(status
)) {
1029 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status
));
1030 smb_panic("g_lock_unlock failed");
1032 ctx
->db
.lock
= NETLOGON_CREDS_CLI_LCK_NONE
;
1036 NTSTATUS
netlogon_creds_cli_lck_recv(
1037 struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1038 struct netlogon_creds_cli_lck
**lck
)
1040 struct netlogon_creds_cli_lck_state
*state
= tevent_req_data(
1041 req
, struct netlogon_creds_cli_lck_state
);
1044 if (tevent_req_is_nterror(req
, &status
)) {
1047 *lck
= talloc_move(mem_ctx
, &state
->lck
);
1048 return NT_STATUS_OK
;
1051 NTSTATUS
netlogon_creds_cli_lck(
1052 struct netlogon_creds_cli_context
*context
,
1053 enum netlogon_creds_cli_lck_type type
,
1054 TALLOC_CTX
*mem_ctx
, struct netlogon_creds_cli_lck
**lck
)
1056 TALLOC_CTX
*frame
= talloc_stackframe();
1057 struct tevent_context
*ev
;
1058 struct tevent_req
*req
;
1059 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1061 ev
= samba_tevent_context_init(frame
);
1065 req
= netlogon_creds_cli_lck_send(frame
, ev
, context
, type
);
1069 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1072 status
= netlogon_creds_cli_lck_recv(req
, mem_ctx
, lck
);
1078 struct netlogon_creds_cli_auth_state
{
1079 struct tevent_context
*ev
;
1080 struct netlogon_creds_cli_context
*context
;
1081 struct dcerpc_binding_handle
*binding_handle
;
1082 uint8_t num_nt_hashes
;
1083 uint8_t idx_nt_hashes
;
1084 const struct samr_Password
* const *nt_hashes
;
1085 const struct samr_Password
*used_nt_hash
;
1086 char *srv_name_slash
;
1087 uint32_t current_flags
;
1088 struct netr_Credential client_challenge
;
1089 struct netr_Credential server_challenge
;
1090 struct netlogon_creds_CredentialState
*creds
;
1091 struct netr_Credential client_credential
;
1092 struct netr_Credential server_credential
;
1099 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
);
1101 struct tevent_req
*netlogon_creds_cli_auth_send(TALLOC_CTX
*mem_ctx
,
1102 struct tevent_context
*ev
,
1103 struct netlogon_creds_cli_context
*context
,
1104 struct dcerpc_binding_handle
*b
,
1105 uint8_t num_nt_hashes
,
1106 const struct samr_Password
* const *nt_hashes
)
1108 struct tevent_req
*req
;
1109 struct netlogon_creds_cli_auth_state
*state
;
1112 req
= tevent_req_create(mem_ctx
, &state
,
1113 struct netlogon_creds_cli_auth_state
);
1119 state
->context
= context
;
1120 state
->binding_handle
= b
;
1121 if (num_nt_hashes
< 1) {
1122 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1123 return tevent_req_post(req
, ev
);
1125 if (num_nt_hashes
> 4) {
1126 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1127 return tevent_req_post(req
, ev
);
1130 state
->num_nt_hashes
= num_nt_hashes
;
1131 state
->idx_nt_hashes
= 0;
1132 state
->nt_hashes
= nt_hashes
;
1134 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1135 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1136 return tevent_req_post(req
, ev
);
1139 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1140 context
->server
.computer
);
1141 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1142 return tevent_req_post(req
, ev
);
1145 state
->try_auth3
= true;
1146 state
->try_auth2
= true;
1148 if (context
->client
.required_flags
!= 0) {
1149 state
->require_auth2
= true;
1152 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1153 state
->current_flags
= context
->client
.proposed_flags
;
1155 status
= dbwrap_purge(state
->context
->db
.ctx
,
1156 state
->context
->db
.key_data
);
1157 if (tevent_req_nterror(req
, status
)) {
1158 return tevent_req_post(req
, ev
);
1161 netlogon_creds_cli_auth_challenge_start(req
);
1162 if (!tevent_req_is_in_progress(req
)) {
1163 return tevent_req_post(req
, ev
);
1169 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
);
1171 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req
*req
)
1173 struct netlogon_creds_cli_auth_state
*state
=
1174 tevent_req_data(req
,
1175 struct netlogon_creds_cli_auth_state
);
1176 struct tevent_req
*subreq
;
1178 TALLOC_FREE(state
->creds
);
1180 netlogon_creds_random_challenge(&state
->client_challenge
);
1182 subreq
= dcerpc_netr_ServerReqChallenge_send(state
, state
->ev
,
1183 state
->binding_handle
,
1184 state
->srv_name_slash
,
1185 state
->context
->client
.computer
,
1186 &state
->client_challenge
,
1187 &state
->server_challenge
);
1188 if (tevent_req_nomem(subreq
, req
)) {
1191 tevent_req_set_callback(subreq
,
1192 netlogon_creds_cli_auth_challenge_done
,
1196 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
);
1198 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req
*subreq
)
1200 struct tevent_req
*req
=
1201 tevent_req_callback_data(subreq
,
1203 struct netlogon_creds_cli_auth_state
*state
=
1204 tevent_req_data(req
,
1205 struct netlogon_creds_cli_auth_state
);
1209 status
= dcerpc_netr_ServerReqChallenge_recv(subreq
, state
, &result
);
1210 TALLOC_FREE(subreq
);
1211 if (tevent_req_nterror(req
, status
)) {
1214 if (tevent_req_nterror(req
, result
)) {
1218 if (!state
->try_auth3
&& !state
->try_auth2
) {
1219 state
->current_flags
= 0;
1222 /* Calculate the session key and client credentials */
1224 state
->creds
= netlogon_creds_client_init(state
,
1225 state
->context
->client
.account
,
1226 state
->context
->client
.computer
,
1227 state
->context
->client
.type
,
1228 &state
->client_challenge
,
1229 &state
->server_challenge
,
1230 state
->used_nt_hash
,
1231 &state
->client_credential
,
1232 state
->current_flags
);
1233 if (tevent_req_nomem(state
->creds
, req
)) {
1237 if (state
->try_auth3
) {
1238 subreq
= dcerpc_netr_ServerAuthenticate3_send(state
, state
->ev
,
1239 state
->binding_handle
,
1240 state
->srv_name_slash
,
1241 state
->context
->client
.account
,
1242 state
->context
->client
.type
,
1243 state
->context
->client
.computer
,
1244 &state
->client_credential
,
1245 &state
->server_credential
,
1246 &state
->creds
->negotiate_flags
,
1248 if (tevent_req_nomem(subreq
, req
)) {
1251 } else if (state
->try_auth2
) {
1254 subreq
= dcerpc_netr_ServerAuthenticate2_send(state
, state
->ev
,
1255 state
->binding_handle
,
1256 state
->srv_name_slash
,
1257 state
->context
->client
.account
,
1258 state
->context
->client
.type
,
1259 state
->context
->client
.computer
,
1260 &state
->client_credential
,
1261 &state
->server_credential
,
1262 &state
->creds
->negotiate_flags
);
1263 if (tevent_req_nomem(subreq
, req
)) {
1269 subreq
= dcerpc_netr_ServerAuthenticate_send(state
, state
->ev
,
1270 state
->binding_handle
,
1271 state
->srv_name_slash
,
1272 state
->context
->client
.account
,
1273 state
->context
->client
.type
,
1274 state
->context
->client
.computer
,
1275 &state
->client_credential
,
1276 &state
->server_credential
);
1277 if (tevent_req_nomem(subreq
, req
)) {
1281 tevent_req_set_callback(subreq
,
1282 netlogon_creds_cli_auth_srvauth_done
,
1286 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req
*subreq
)
1288 struct tevent_req
*req
=
1289 tevent_req_callback_data(subreq
,
1291 struct netlogon_creds_cli_auth_state
*state
=
1292 tevent_req_data(req
,
1293 struct netlogon_creds_cli_auth_state
);
1297 enum ndr_err_code ndr_err
;
1302 if (state
->try_auth3
) {
1303 status
= dcerpc_netr_ServerAuthenticate3_recv(subreq
, state
,
1305 TALLOC_FREE(subreq
);
1306 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1307 state
->try_auth3
= false;
1308 netlogon_creds_cli_auth_challenge_start(req
);
1311 if (tevent_req_nterror(req
, status
)) {
1314 } else if (state
->try_auth2
) {
1315 status
= dcerpc_netr_ServerAuthenticate2_recv(subreq
, state
,
1317 TALLOC_FREE(subreq
);
1318 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1319 state
->try_auth2
= false;
1320 if (state
->require_auth2
) {
1321 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1322 tevent_req_nterror(req
, status
);
1325 netlogon_creds_cli_auth_challenge_start(req
);
1328 if (tevent_req_nterror(req
, status
)) {
1332 status
= dcerpc_netr_ServerAuthenticate_recv(subreq
, state
,
1334 TALLOC_FREE(subreq
);
1335 if (tevent_req_nterror(req
, status
)) {
1340 if (!NT_STATUS_IS_OK(result
) &&
1341 !NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
))
1343 tevent_req_nterror(req
, result
);
1347 tmp_flags
= state
->creds
->negotiate_flags
;
1348 tmp_flags
&= state
->context
->client
.required_flags
;
1349 if (tmp_flags
!= state
->context
->client
.required_flags
) {
1350 if (NT_STATUS_IS_OK(result
)) {
1351 tevent_req_nterror(req
, NT_STATUS_DOWNGRADE_DETECTED
);
1354 tevent_req_nterror(req
, result
);
1358 if (NT_STATUS_EQUAL(result
, NT_STATUS_ACCESS_DENIED
)) {
1360 tmp_flags
= state
->context
->client
.proposed_flags
;
1361 if ((state
->current_flags
== tmp_flags
) &&
1362 (state
->creds
->negotiate_flags
!= tmp_flags
))
1365 * lets retry with the negotiated flags
1367 state
->current_flags
= state
->creds
->negotiate_flags
;
1368 netlogon_creds_cli_auth_challenge_start(req
);
1372 state
->idx_nt_hashes
+= 1;
1373 if (state
->idx_nt_hashes
>= state
->num_nt_hashes
) {
1375 * we already retried, giving up...
1377 tevent_req_nterror(req
, result
);
1382 * lets retry with the old nt hash.
1384 state
->used_nt_hash
= state
->nt_hashes
[state
->idx_nt_hashes
];
1385 state
->current_flags
= state
->context
->client
.proposed_flags
;
1386 netlogon_creds_cli_auth_challenge_start(req
);
1390 ok
= netlogon_creds_client_check(state
->creds
,
1391 &state
->server_credential
);
1393 tevent_req_nterror(req
, NT_STATUS_ACCESS_DENIED
);
1397 ndr_err
= ndr_push_struct_blob(&blob
, state
, state
->creds
,
1398 (ndr_push_flags_fn_t
)ndr_push_netlogon_creds_CredentialState
);
1399 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1400 status
= ndr_map_error2ntstatus(ndr_err
);
1401 tevent_req_nterror(req
, status
);
1405 data
.dptr
= blob
.data
;
1406 data
.dsize
= blob
.length
;
1408 status
= dbwrap_store(state
->context
->db
.ctx
,
1409 state
->context
->db
.key_data
,
1411 if (tevent_req_nterror(req
, status
)) {
1415 tevent_req_done(req
);
1418 NTSTATUS
netlogon_creds_cli_auth_recv(struct tevent_req
*req
,
1419 uint8_t *idx_nt_hashes
)
1421 struct netlogon_creds_cli_auth_state
*state
=
1422 tevent_req_data(req
,
1423 struct netlogon_creds_cli_auth_state
);
1428 if (tevent_req_is_nterror(req
, &status
)) {
1429 tevent_req_received(req
);
1433 *idx_nt_hashes
= state
->idx_nt_hashes
;
1434 tevent_req_received(req
);
1435 return NT_STATUS_OK
;
1438 NTSTATUS
netlogon_creds_cli_auth(struct netlogon_creds_cli_context
*context
,
1439 struct dcerpc_binding_handle
*b
,
1440 uint8_t num_nt_hashes
,
1441 const struct samr_Password
* const *nt_hashes
,
1442 uint8_t *idx_nt_hashes
)
1444 TALLOC_CTX
*frame
= talloc_stackframe();
1445 struct tevent_context
*ev
;
1446 struct tevent_req
*req
;
1447 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1451 ev
= samba_tevent_context_init(frame
);
1455 req
= netlogon_creds_cli_auth_send(frame
, ev
, context
, b
,
1456 num_nt_hashes
, nt_hashes
);
1460 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1463 status
= netlogon_creds_cli_auth_recv(req
, idx_nt_hashes
);
1469 struct netlogon_creds_cli_check_state
{
1470 struct tevent_context
*ev
;
1471 struct netlogon_creds_cli_context
*context
;
1472 struct dcerpc_binding_handle
*binding_handle
;
1474 char *srv_name_slash
;
1476 union netr_Capabilities caps
;
1478 struct netlogon_creds_CredentialState
*creds
;
1479 struct netr_Authenticator req_auth
;
1480 struct netr_Authenticator rep_auth
;
1483 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1485 static void netlogon_creds_cli_check_caps(struct tevent_req
*subreq
);
1487 struct tevent_req
*netlogon_creds_cli_check_send(TALLOC_CTX
*mem_ctx
,
1488 struct tevent_context
*ev
,
1489 struct netlogon_creds_cli_context
*context
,
1490 struct dcerpc_binding_handle
*b
)
1492 struct tevent_req
*req
;
1493 struct netlogon_creds_cli_check_state
*state
;
1494 struct tevent_req
*subreq
;
1495 enum dcerpc_AuthType auth_type
;
1496 enum dcerpc_AuthLevel auth_level
;
1499 req
= tevent_req_create(mem_ctx
, &state
,
1500 struct netlogon_creds_cli_check_state
);
1506 state
->context
= context
;
1507 state
->binding_handle
= b
;
1509 if (context
->db
.lock
!= NETLOGON_CREDS_CLI_LCK_EXCLUSIVE
) {
1510 tevent_req_nterror(req
, NT_STATUS_NOT_LOCKED
);
1511 return tevent_req_post(req
, ev
);
1514 status
= netlogon_creds_cli_get_internal(context
, state
,
1516 if (tevent_req_nterror(req
, status
)) {
1517 return tevent_req_post(req
, ev
);
1520 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1521 context
->server
.computer
);
1522 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1523 return tevent_req_post(req
, ev
);
1526 dcerpc_binding_handle_auth_info(state
->binding_handle
,
1527 &auth_type
, &auth_level
);
1529 if (auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
1530 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1531 return tevent_req_post(req
, ev
);
1534 switch (auth_level
) {
1535 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1536 case DCERPC_AUTH_LEVEL_PRIVACY
:
1539 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1540 return tevent_req_post(req
, ev
);
1544 * we defer all callbacks in order to cleanup
1545 * the database record.
1547 tevent_req_defer_callback(req
, state
->ev
);
1549 status
= netlogon_creds_client_authenticator(state
->creds
,
1551 if (tevent_req_nterror(req
, status
)) {
1552 return tevent_req_post(req
, ev
);
1554 ZERO_STRUCT(state
->rep_auth
);
1556 subreq
= dcerpc_netr_LogonGetCapabilities_send(state
, state
->ev
,
1557 state
->binding_handle
,
1558 state
->srv_name_slash
,
1559 state
->context
->client
.computer
,
1564 if (tevent_req_nomem(subreq
, req
)) {
1565 return tevent_req_post(req
, ev
);
1568 tevent_req_set_callback(subreq
,
1569 netlogon_creds_cli_check_caps
,
1575 static void netlogon_creds_cli_check_cleanup(struct tevent_req
*req
,
1578 struct netlogon_creds_cli_check_state
*state
=
1579 tevent_req_data(req
,
1580 struct netlogon_creds_cli_check_state
);
1582 if (state
->creds
== NULL
) {
1586 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
1587 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
1588 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
1589 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
1590 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
1591 TALLOC_FREE(state
->creds
);
1595 netlogon_creds_cli_delete_lck(state
->context
);
1596 TALLOC_FREE(state
->creds
);
1599 static void netlogon_creds_cli_check_caps(struct tevent_req
*subreq
)
1601 struct tevent_req
*req
=
1602 tevent_req_callback_data(subreq
,
1604 struct netlogon_creds_cli_check_state
*state
=
1605 tevent_req_data(req
,
1606 struct netlogon_creds_cli_check_state
);
1611 status
= dcerpc_netr_LogonGetCapabilities_recv(subreq
, state
,
1613 TALLOC_FREE(subreq
);
1614 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1616 * Note that the negotiated flags are already checked
1617 * for our required flags after the ServerAuthenticate3/2 call.
1619 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1621 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1623 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1624 * already, we expect this to work!
1626 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1627 tevent_req_nterror(req
, status
);
1628 netlogon_creds_cli_check_cleanup(req
, status
);
1632 if (negotiated
& NETLOGON_NEG_STRONG_KEYS
) {
1634 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1635 * we expect this to work at least as far as the
1636 * NOT_SUPPORTED error handled below!
1638 * NT 4.0 and Old Samba servers are not
1639 * allowed without "require strong key = no"
1641 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1642 tevent_req_nterror(req
, status
);
1643 netlogon_creds_cli_check_cleanup(req
, status
);
1648 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1649 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1650 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1652 * This is needed against NT 4.0 and old Samba servers.
1654 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1655 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1656 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1657 * with the next request as the sequence number processing
1660 netlogon_creds_cli_check_cleanup(req
, status
);
1661 tevent_req_done(req
);
1664 if (tevent_req_nterror(req
, status
)) {
1665 netlogon_creds_cli_check_cleanup(req
, status
);
1669 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_IMPLEMENTED
)) {
1671 * Note that the negotiated flags are already checked
1672 * for our required flags after the ServerAuthenticate3/2 call.
1674 uint32_t negotiated
= state
->creds
->negotiate_flags
;
1676 if (negotiated
& NETLOGON_NEG_SUPPORTS_AES
) {
1678 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1679 * already, we expect this to work!
1681 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1682 tevent_req_nterror(req
, status
);
1683 netlogon_creds_cli_check_cleanup(req
, status
);
1688 * This is ok, the server does not support
1689 * NETLOGON_NEG_SUPPORTS_AES.
1691 * netr_LogonGetCapabilities() was
1692 * netr_LogonDummyRoutine1() before
1693 * NETLOGON_NEG_SUPPORTS_AES was invented.
1695 netlogon_creds_cli_check_cleanup(req
, result
);
1696 tevent_req_done(req
);
1700 ok
= netlogon_creds_client_check(state
->creds
, &state
->rep_auth
.cred
);
1702 status
= NT_STATUS_ACCESS_DENIED
;
1703 tevent_req_nterror(req
, status
);
1704 netlogon_creds_cli_check_cleanup(req
, status
);
1708 if (tevent_req_nterror(req
, result
)) {
1709 netlogon_creds_cli_check_cleanup(req
, result
);
1713 if (state
->caps
.server_capabilities
!= state
->creds
->negotiate_flags
) {
1714 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1715 tevent_req_nterror(req
, status
);
1716 netlogon_creds_cli_check_cleanup(req
, status
);
1721 * This is the key check that makes this check secure. If we
1722 * get OK here (rather than NOT_SUPPORTED), then the server
1723 * did support AES. If the server only proposed STRONG_KEYS
1724 * and not AES, then it should have failed with
1725 * NOT_IMPLEMENTED. We always send AES as a client, so the
1726 * server should always have returned it.
1728 if (!(state
->caps
.server_capabilities
& NETLOGON_NEG_SUPPORTS_AES
)) {
1729 status
= NT_STATUS_DOWNGRADE_DETECTED
;
1730 tevent_req_nterror(req
, status
);
1731 netlogon_creds_cli_check_cleanup(req
, status
);
1735 status
= netlogon_creds_cli_store_internal(state
->context
,
1737 if (tevent_req_nterror(req
, status
)) {
1741 tevent_req_done(req
);
1744 NTSTATUS
netlogon_creds_cli_check_recv(struct tevent_req
*req
,
1745 union netr_Capabilities
*capabilities
)
1747 struct netlogon_creds_cli_check_state
*state
= tevent_req_data(
1748 req
, struct netlogon_creds_cli_check_state
);
1751 if (tevent_req_is_nterror(req
, &status
)) {
1752 netlogon_creds_cli_check_cleanup(req
, status
);
1753 tevent_req_received(req
);
1757 if (capabilities
!= NULL
) {
1758 *capabilities
= state
->caps
;
1761 tevent_req_received(req
);
1762 return NT_STATUS_OK
;
1765 NTSTATUS
netlogon_creds_cli_check(struct netlogon_creds_cli_context
*context
,
1766 struct dcerpc_binding_handle
*b
,
1767 union netr_Capabilities
*capabilities
)
1769 TALLOC_CTX
*frame
= talloc_stackframe();
1770 struct tevent_context
*ev
;
1771 struct tevent_req
*req
;
1772 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1774 ev
= samba_tevent_context_init(frame
);
1778 req
= netlogon_creds_cli_check_send(frame
, ev
, context
, b
);
1782 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
1785 status
= netlogon_creds_cli_check_recv(req
, capabilities
);
1791 struct netlogon_creds_cli_ServerPasswordSet_state
{
1792 struct tevent_context
*ev
;
1793 struct netlogon_creds_cli_context
*context
;
1794 struct dcerpc_binding_handle
*binding_handle
;
1795 uint32_t old_timeout
;
1797 char *srv_name_slash
;
1798 enum dcerpc_AuthType auth_type
;
1799 enum dcerpc_AuthLevel auth_level
;
1801 struct samr_CryptPassword samr_crypt_password
;
1802 struct netr_CryptPassword netr_crypt_password
;
1803 struct samr_Password samr_password
;
1805 struct netlogon_creds_CredentialState
*creds
;
1806 struct netlogon_creds_CredentialState tmp_creds
;
1807 struct netr_Authenticator req_auth
;
1808 struct netr_Authenticator rep_auth
;
1811 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
1813 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
);
1815 struct tevent_req
*netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX
*mem_ctx
,
1816 struct tevent_context
*ev
,
1817 struct netlogon_creds_cli_context
*context
,
1818 struct dcerpc_binding_handle
*b
,
1819 const DATA_BLOB
*new_password
,
1820 const uint32_t *new_version
)
1822 struct tevent_req
*req
;
1823 struct netlogon_creds_cli_ServerPasswordSet_state
*state
;
1824 struct tevent_req
*subreq
;
1827 req
= tevent_req_create(mem_ctx
, &state
,
1828 struct netlogon_creds_cli_ServerPasswordSet_state
);
1834 state
->context
= context
;
1835 state
->binding_handle
= b
;
1837 if (new_password
->length
< 14) {
1838 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1839 return tevent_req_post(req
, ev
);
1843 * netr_ServerPasswordSet
1845 mdfour(state
->samr_password
.hash
, new_password
->data
, new_password
->length
);
1848 * netr_ServerPasswordSet2
1850 ok
= set_pw_in_buffer(state
->samr_crypt_password
.data
,
1853 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1854 return tevent_req_post(req
, ev
);
1857 if (new_version
!= NULL
) {
1858 struct NL_PASSWORD_VERSION version
;
1859 uint32_t len
= IVAL(state
->samr_crypt_password
.data
, 512);
1860 uint32_t ofs
= 512 - len
;
1864 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1865 return tevent_req_post(req
, ev
);
1869 version
.ReservedField
= 0;
1870 version
.PasswordVersionNumber
= *new_version
;
1871 version
.PasswordVersionPresent
=
1872 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT
;
1874 p
= state
->samr_crypt_password
.data
+ ofs
;
1875 SIVAL(p
, 0, version
.ReservedField
);
1876 SIVAL(p
, 4, version
.PasswordVersionNumber
);
1877 SIVAL(p
, 8, version
.PasswordVersionPresent
);
1880 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
1881 context
->server
.computer
);
1882 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
1883 return tevent_req_post(req
, ev
);
1886 dcerpc_binding_handle_auth_info(state
->binding_handle
,
1888 &state
->auth_level
);
1890 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
1892 if (tevent_req_nomem(subreq
, req
)) {
1893 return tevent_req_post(req
, ev
);
1896 tevent_req_set_callback(subreq
,
1897 netlogon_creds_cli_ServerPasswordSet_locked
,
1903 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req
*req
,
1906 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
1907 tevent_req_data(req
,
1908 struct netlogon_creds_cli_ServerPasswordSet_state
);
1910 if (state
->creds
== NULL
) {
1914 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
1915 state
->old_timeout
);
1917 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
1918 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
1919 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
1920 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
1921 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
1922 TALLOC_FREE(state
->creds
);
1926 netlogon_creds_cli_delete(state
->context
, state
->creds
);
1927 TALLOC_FREE(state
->creds
);
1930 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
);
1932 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req
*subreq
)
1934 struct tevent_req
*req
=
1935 tevent_req_callback_data(subreq
,
1937 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
1938 tevent_req_data(req
,
1939 struct netlogon_creds_cli_ServerPasswordSet_state
);
1942 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
1944 TALLOC_FREE(subreq
);
1945 if (tevent_req_nterror(req
, status
)) {
1949 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
1950 switch (state
->auth_level
) {
1951 case DCERPC_AUTH_LEVEL_INTEGRITY
:
1952 case DCERPC_AUTH_LEVEL_PRIVACY
:
1955 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1959 uint32_t tmp
= state
->creds
->negotiate_flags
;
1961 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
1963 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1964 * it should be used, which means
1965 * we had a chance to verify no downgrade
1968 * This relies on netlogon_creds_cli_check*
1969 * being called before, as first request after
1972 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
1977 state
->old_timeout
= dcerpc_binding_handle_set_timeout(
1978 state
->binding_handle
, 600000);
1981 * we defer all callbacks in order to cleanup
1982 * the database record.
1984 tevent_req_defer_callback(req
, state
->ev
);
1986 state
->tmp_creds
= *state
->creds
;
1987 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
1989 if (tevent_req_nterror(req
, status
)) {
1992 ZERO_STRUCT(state
->rep_auth
);
1994 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
1996 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
1997 status
= netlogon_creds_aes_encrypt(&state
->tmp_creds
,
1998 state
->samr_crypt_password
.data
,
2000 if (tevent_req_nterror(req
, status
)) {
2001 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2005 status
= netlogon_creds_arcfour_crypt(&state
->tmp_creds
,
2006 state
->samr_crypt_password
.data
,
2008 if (tevent_req_nterror(req
, status
)) {
2009 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2014 memcpy(state
->netr_crypt_password
.data
,
2015 state
->samr_crypt_password
.data
, 512);
2016 state
->netr_crypt_password
.length
=
2017 IVAL(state
->samr_crypt_password
.data
, 512);
2019 subreq
= dcerpc_netr_ServerPasswordSet2_send(state
, state
->ev
,
2020 state
->binding_handle
,
2021 state
->srv_name_slash
,
2022 state
->tmp_creds
.account_name
,
2023 state
->tmp_creds
.secure_channel_type
,
2024 state
->tmp_creds
.computer_name
,
2027 &state
->netr_crypt_password
);
2028 if (tevent_req_nomem(subreq
, req
)) {
2029 status
= NT_STATUS_NO_MEMORY
;
2030 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2034 status
= netlogon_creds_des_encrypt(&state
->tmp_creds
,
2035 &state
->samr_password
);
2036 if (tevent_req_nterror(req
, status
)) {
2037 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2041 subreq
= dcerpc_netr_ServerPasswordSet_send(state
, state
->ev
,
2042 state
->binding_handle
,
2043 state
->srv_name_slash
,
2044 state
->tmp_creds
.account_name
,
2045 state
->tmp_creds
.secure_channel_type
,
2046 state
->tmp_creds
.computer_name
,
2049 &state
->samr_password
);
2050 if (tevent_req_nomem(subreq
, req
)) {
2051 status
= NT_STATUS_NO_MEMORY
;
2052 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2057 tevent_req_set_callback(subreq
,
2058 netlogon_creds_cli_ServerPasswordSet_done
,
2062 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req
*subreq
)
2064 struct tevent_req
*req
=
2065 tevent_req_callback_data(subreq
,
2067 struct netlogon_creds_cli_ServerPasswordSet_state
*state
=
2068 tevent_req_data(req
,
2069 struct netlogon_creds_cli_ServerPasswordSet_state
);
2074 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_PASSWORD_SET2
) {
2075 status
= dcerpc_netr_ServerPasswordSet2_recv(subreq
, state
,
2077 TALLOC_FREE(subreq
);
2078 if (tevent_req_nterror(req
, status
)) {
2079 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2083 status
= dcerpc_netr_ServerPasswordSet_recv(subreq
, state
,
2085 TALLOC_FREE(subreq
);
2086 if (tevent_req_nterror(req
, status
)) {
2087 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2092 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
2093 &state
->rep_auth
.cred
);
2095 status
= NT_STATUS_ACCESS_DENIED
;
2096 tevent_req_nterror(req
, status
);
2097 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2101 if (tevent_req_nterror(req
, result
)) {
2102 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, result
);
2106 dcerpc_binding_handle_set_timeout(state
->binding_handle
,
2107 state
->old_timeout
);
2109 *state
->creds
= state
->tmp_creds
;
2110 status
= netlogon_creds_cli_store(state
->context
,
2112 TALLOC_FREE(state
->creds
);
2113 if (tevent_req_nterror(req
, status
)) {
2114 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2118 tevent_req_done(req
);
2121 NTSTATUS
netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req
*req
)
2125 if (tevent_req_is_nterror(req
, &status
)) {
2126 netlogon_creds_cli_ServerPasswordSet_cleanup(req
, status
);
2127 tevent_req_received(req
);
2131 tevent_req_received(req
);
2132 return NT_STATUS_OK
;
2135 NTSTATUS
netlogon_creds_cli_ServerPasswordSet(
2136 struct netlogon_creds_cli_context
*context
,
2137 struct dcerpc_binding_handle
*b
,
2138 const DATA_BLOB
*new_password
,
2139 const uint32_t *new_version
)
2141 TALLOC_CTX
*frame
= talloc_stackframe();
2142 struct tevent_context
*ev
;
2143 struct tevent_req
*req
;
2144 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2146 ev
= samba_tevent_context_init(frame
);
2150 req
= netlogon_creds_cli_ServerPasswordSet_send(frame
, ev
, context
, b
,
2156 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2159 status
= netlogon_creds_cli_ServerPasswordSet_recv(req
);
2165 struct netlogon_creds_cli_LogonSamLogon_state
{
2166 struct tevent_context
*ev
;
2167 struct netlogon_creds_cli_context
*context
;
2168 struct dcerpc_binding_handle
*binding_handle
;
2170 char *srv_name_slash
;
2172 enum netr_LogonInfoClass logon_level
;
2173 const union netr_LogonLevel
*const_logon
;
2174 union netr_LogonLevel
*logon
;
2177 uint16_t validation_level
;
2178 union netr_Validation
*validation
;
2179 uint8_t authoritative
;
2182 * do we need encryption at the application layer?
2186 bool try_validation6
;
2189 * the read only credentials before we started the operation
2190 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2192 struct netlogon_creds_CredentialState
*ro_creds
;
2195 * The (locked) credentials used for the credential chain
2196 * used for netr_LogonSamLogonWithFlags() or
2197 * netr_LogonSamLogonWith().
2199 struct netlogon_creds_CredentialState
*lk_creds
;
2202 * While we have locked the global credentials (lk_creds above)
2203 * we operate an a temporary copy, because a server
2204 * may not support netr_LogonSamLogonWithFlags() and
2205 * didn't process our netr_Authenticator, so we need to
2206 * restart from lk_creds.
2208 struct netlogon_creds_CredentialState tmp_creds
;
2209 struct netr_Authenticator req_auth
;
2210 struct netr_Authenticator rep_auth
;
2213 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
);
2214 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2217 struct tevent_req
*netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX
*mem_ctx
,
2218 struct tevent_context
*ev
,
2219 struct netlogon_creds_cli_context
*context
,
2220 struct dcerpc_binding_handle
*b
,
2221 enum netr_LogonInfoClass logon_level
,
2222 const union netr_LogonLevel
*logon
,
2225 struct tevent_req
*req
;
2226 struct netlogon_creds_cli_LogonSamLogon_state
*state
;
2228 req
= tevent_req_create(mem_ctx
, &state
,
2229 struct netlogon_creds_cli_LogonSamLogon_state
);
2235 state
->context
= context
;
2236 state
->binding_handle
= b
;
2238 state
->logon_level
= logon_level
;
2239 state
->const_logon
= logon
;
2240 state
->flags
= flags
;
2242 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2243 context
->server
.computer
);
2244 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2245 return tevent_req_post(req
, ev
);
2248 switch (logon_level
) {
2249 case NetlogonInteractiveInformation
:
2250 case NetlogonInteractiveTransitiveInformation
:
2251 case NetlogonServiceInformation
:
2252 case NetlogonServiceTransitiveInformation
:
2253 case NetlogonGenericInformation
:
2254 state
->user_encrypt
= true;
2257 case NetlogonNetworkInformation
:
2258 case NetlogonNetworkTransitiveInformation
:
2262 state
->validation
= talloc_zero(state
, union netr_Validation
);
2263 if (tevent_req_nomem(state
->validation
, req
)) {
2264 return tevent_req_post(req
, ev
);
2267 netlogon_creds_cli_LogonSamLogon_start(req
);
2268 if (!tevent_req_is_in_progress(req
)) {
2269 return tevent_req_post(req
, ev
);
2273 * we defer all callbacks in order to cleanup
2274 * the database record.
2276 tevent_req_defer_callback(req
, state
->ev
);
2280 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req
*req
,
2283 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2284 tevent_req_data(req
,
2285 struct netlogon_creds_cli_LogonSamLogon_state
);
2287 if (state
->lk_creds
== NULL
) {
2291 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2293 * This is a hack to recover from a bug in old
2294 * Samba servers, when LogonSamLogonEx() fails:
2296 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2298 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2300 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2301 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2302 * If the sign/seal check fails.
2304 * In that case we need to cleanup the netlogon session.
2306 * It's the job of the caller to disconnect the current
2307 * connection, if netlogon_creds_cli_LogonSamLogon()
2308 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2310 if (!state
->context
->server
.try_logon_with
) {
2311 status
= NT_STATUS_NETWORK_ACCESS_DENIED
;
2315 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2316 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2317 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2318 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2319 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2320 TALLOC_FREE(state
->lk_creds
);
2324 netlogon_creds_cli_delete(state
->context
, state
->lk_creds
);
2325 TALLOC_FREE(state
->lk_creds
);
2328 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
);
2330 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req
*req
)
2332 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2333 tevent_req_data(req
,
2334 struct netlogon_creds_cli_LogonSamLogon_state
);
2335 struct tevent_req
*subreq
;
2337 enum dcerpc_AuthType auth_type
;
2338 enum dcerpc_AuthLevel auth_level
;
2340 TALLOC_FREE(state
->ro_creds
);
2341 TALLOC_FREE(state
->logon
);
2342 ZERO_STRUCTP(state
->validation
);
2344 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2345 &auth_type
, &auth_level
);
2347 state
->try_logon_ex
= state
->context
->server
.try_logon_ex
;
2348 state
->try_validation6
= state
->context
->server
.try_validation6
;
2350 if (auth_type
!= DCERPC_AUTH_TYPE_SCHANNEL
) {
2351 state
->try_logon_ex
= false;
2354 if (auth_level
!= DCERPC_AUTH_LEVEL_PRIVACY
) {
2355 state
->try_validation6
= false;
2358 if (state
->try_logon_ex
) {
2359 if (state
->try_validation6
) {
2360 state
->validation_level
= 6;
2362 state
->validation_level
= 3;
2363 state
->user_encrypt
= true;
2366 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2368 state
->const_logon
);
2369 if (tevent_req_nomem(state
->logon
, req
)) {
2370 status
= NT_STATUS_NO_MEMORY
;
2371 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2375 if (state
->user_encrypt
) {
2376 status
= netlogon_creds_cli_get(state
->context
,
2379 if (!NT_STATUS_IS_OK(status
)) {
2380 status
= NT_STATUS_ACCESS_DENIED
;
2381 tevent_req_nterror(req
, status
);
2382 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2386 status
= netlogon_creds_encrypt_samlogon_logon(state
->ro_creds
,
2389 if (!NT_STATUS_IS_OK(status
)) {
2390 status
= NT_STATUS_ACCESS_DENIED
;
2391 tevent_req_nterror(req
, status
);
2392 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2397 subreq
= dcerpc_netr_LogonSamLogonEx_send(state
, state
->ev
,
2398 state
->binding_handle
,
2399 state
->srv_name_slash
,
2400 state
->context
->client
.computer
,
2403 state
->validation_level
,
2405 &state
->authoritative
,
2407 if (tevent_req_nomem(subreq
, req
)) {
2408 status
= NT_STATUS_NO_MEMORY
;
2409 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2412 tevent_req_set_callback(subreq
,
2413 netlogon_creds_cli_LogonSamLogon_done
,
2418 if (state
->lk_creds
== NULL
) {
2419 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2421 if (tevent_req_nomem(subreq
, req
)) {
2422 status
= NT_STATUS_NO_MEMORY
;
2423 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2426 tevent_req_set_callback(subreq
,
2427 netlogon_creds_cli_LogonSamLogon_done
,
2432 state
->tmp_creds
= *state
->lk_creds
;
2433 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2435 if (tevent_req_nterror(req
, status
)) {
2436 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2439 ZERO_STRUCT(state
->rep_auth
);
2441 state
->logon
= netlogon_creds_shallow_copy_logon(state
,
2443 state
->const_logon
);
2444 if (tevent_req_nomem(state
->logon
, req
)) {
2445 status
= NT_STATUS_NO_MEMORY
;
2446 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2450 status
= netlogon_creds_encrypt_samlogon_logon(&state
->tmp_creds
,
2453 if (tevent_req_nterror(req
, status
)) {
2454 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2458 state
->validation_level
= 3;
2460 if (state
->context
->server
.try_logon_with
) {
2461 subreq
= dcerpc_netr_LogonSamLogonWithFlags_send(state
, state
->ev
,
2462 state
->binding_handle
,
2463 state
->srv_name_slash
,
2464 state
->context
->client
.computer
,
2469 state
->validation_level
,
2471 &state
->authoritative
,
2473 if (tevent_req_nomem(subreq
, req
)) {
2474 status
= NT_STATUS_NO_MEMORY
;
2475 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2481 subreq
= dcerpc_netr_LogonSamLogon_send(state
, state
->ev
,
2482 state
->binding_handle
,
2483 state
->srv_name_slash
,
2484 state
->context
->client
.computer
,
2489 state
->validation_level
,
2491 &state
->authoritative
);
2492 if (tevent_req_nomem(subreq
, req
)) {
2493 status
= NT_STATUS_NO_MEMORY
;
2494 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2499 tevent_req_set_callback(subreq
,
2500 netlogon_creds_cli_LogonSamLogon_done
,
2504 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req
*subreq
)
2506 struct tevent_req
*req
=
2507 tevent_req_callback_data(subreq
,
2509 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2510 tevent_req_data(req
,
2511 struct netlogon_creds_cli_LogonSamLogon_state
);
2516 if (state
->try_logon_ex
) {
2517 status
= dcerpc_netr_LogonSamLogonEx_recv(subreq
,
2520 TALLOC_FREE(subreq
);
2521 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2522 state
->context
->server
.try_validation6
= false;
2523 state
->context
->server
.try_logon_ex
= false;
2524 netlogon_creds_cli_LogonSamLogon_start(req
);
2527 if (tevent_req_nterror(req
, status
)) {
2528 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2532 if ((state
->validation_level
== 6) &&
2533 (NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_INFO_CLASS
) ||
2534 NT_STATUS_EQUAL(result
, NT_STATUS_INVALID_PARAMETER
) ||
2535 NT_STATUS_EQUAL(result
, NT_STATUS_BUFFER_TOO_SMALL
)))
2537 state
->context
->server
.try_validation6
= false;
2538 netlogon_creds_cli_LogonSamLogon_start(req
);
2542 if (tevent_req_nterror(req
, result
)) {
2543 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2547 if (state
->ro_creds
== NULL
) {
2548 tevent_req_done(req
);
2552 ok
= netlogon_creds_cli_validate(state
->context
, state
->ro_creds
);
2555 * We got a race, lets retry with on authenticator
2558 * netlogon_creds_cli_LogonSamLogon_start()
2559 * will TALLOC_FREE(state->ro_creds);
2561 state
->try_logon_ex
= false;
2562 netlogon_creds_cli_LogonSamLogon_start(req
);
2566 status
= netlogon_creds_decrypt_samlogon_validation(state
->ro_creds
,
2567 state
->validation_level
,
2569 if (tevent_req_nterror(req
, status
)) {
2570 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2574 tevent_req_done(req
);
2578 if (state
->lk_creds
== NULL
) {
2579 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2581 TALLOC_FREE(subreq
);
2582 if (tevent_req_nterror(req
, status
)) {
2583 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2587 netlogon_creds_cli_LogonSamLogon_start(req
);
2591 if (state
->context
->server
.try_logon_with
) {
2592 status
= dcerpc_netr_LogonSamLogonWithFlags_recv(subreq
,
2595 TALLOC_FREE(subreq
);
2596 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
2597 state
->context
->server
.try_logon_with
= false;
2598 netlogon_creds_cli_LogonSamLogon_start(req
);
2601 if (tevent_req_nterror(req
, status
)) {
2602 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2606 status
= dcerpc_netr_LogonSamLogon_recv(subreq
,
2609 TALLOC_FREE(subreq
);
2610 if (tevent_req_nterror(req
, status
)) {
2611 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2616 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
2617 &state
->rep_auth
.cred
);
2619 status
= NT_STATUS_ACCESS_DENIED
;
2620 tevent_req_nterror(req
, status
);
2621 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2625 *state
->lk_creds
= state
->tmp_creds
;
2626 status
= netlogon_creds_cli_store(state
->context
,
2628 TALLOC_FREE(state
->lk_creds
);
2630 if (tevent_req_nterror(req
, status
)) {
2631 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2635 if (tevent_req_nterror(req
, result
)) {
2636 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2640 status
= netlogon_creds_decrypt_samlogon_validation(&state
->tmp_creds
,
2641 state
->validation_level
,
2643 if (tevent_req_nterror(req
, status
)) {
2644 netlogon_creds_cli_LogonSamLogon_cleanup(req
, result
);
2648 tevent_req_done(req
);
2651 NTSTATUS
netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req
*req
,
2652 TALLOC_CTX
*mem_ctx
,
2653 uint16_t *validation_level
,
2654 union netr_Validation
**validation
,
2655 uint8_t *authoritative
,
2658 struct netlogon_creds_cli_LogonSamLogon_state
*state
=
2659 tevent_req_data(req
,
2660 struct netlogon_creds_cli_LogonSamLogon_state
);
2663 /* authoritative is also returned on error */
2664 *authoritative
= state
->authoritative
;
2666 if (tevent_req_is_nterror(req
, &status
)) {
2667 netlogon_creds_cli_LogonSamLogon_cleanup(req
, status
);
2668 tevent_req_received(req
);
2672 *validation_level
= state
->validation_level
;
2673 *validation
= talloc_move(mem_ctx
, &state
->validation
);
2674 *flags
= state
->flags
;
2676 tevent_req_received(req
);
2677 return NT_STATUS_OK
;
2680 NTSTATUS
netlogon_creds_cli_LogonSamLogon(
2681 struct netlogon_creds_cli_context
*context
,
2682 struct dcerpc_binding_handle
*b
,
2683 enum netr_LogonInfoClass logon_level
,
2684 const union netr_LogonLevel
*logon
,
2685 TALLOC_CTX
*mem_ctx
,
2686 uint16_t *validation_level
,
2687 union netr_Validation
**validation
,
2688 uint8_t *authoritative
,
2691 TALLOC_CTX
*frame
= talloc_stackframe();
2692 struct tevent_context
*ev
;
2693 struct tevent_req
*req
;
2694 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2696 ev
= samba_tevent_context_init(frame
);
2700 req
= netlogon_creds_cli_LogonSamLogon_send(frame
, ev
, context
, b
,
2706 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2709 status
= netlogon_creds_cli_LogonSamLogon_recv(req
, mem_ctx
,
2719 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
{
2720 struct tevent_context
*ev
;
2721 struct netlogon_creds_cli_context
*context
;
2722 struct dcerpc_binding_handle
*binding_handle
;
2724 char *srv_name_slash
;
2725 enum dcerpc_AuthType auth_type
;
2726 enum dcerpc_AuthLevel auth_level
;
2728 const char *site_name
;
2730 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
;
2732 struct netlogon_creds_CredentialState
*creds
;
2733 struct netlogon_creds_CredentialState tmp_creds
;
2734 struct netr_Authenticator req_auth
;
2735 struct netr_Authenticator rep_auth
;
2738 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
2740 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
);
2742 struct tevent_req
*netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX
*mem_ctx
,
2743 struct tevent_context
*ev
,
2744 struct netlogon_creds_cli_context
*context
,
2745 struct dcerpc_binding_handle
*b
,
2746 const char *site_name
,
2748 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
2750 struct tevent_req
*req
;
2751 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
;
2752 struct tevent_req
*subreq
;
2754 req
= tevent_req_create(mem_ctx
, &state
,
2755 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2761 state
->context
= context
;
2762 state
->binding_handle
= b
;
2764 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
2765 context
->server
.computer
);
2766 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
2767 return tevent_req_post(req
, ev
);
2770 state
->site_name
= site_name
;
2771 state
->dns_ttl
= dns_ttl
;
2772 state
->dns_names
= dns_names
;
2774 dcerpc_binding_handle_auth_info(state
->binding_handle
,
2776 &state
->auth_level
);
2778 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
2780 if (tevent_req_nomem(subreq
, req
)) {
2781 return tevent_req_post(req
, ev
);
2784 tevent_req_set_callback(subreq
,
2785 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked
,
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req
*req
,
2794 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
2795 tevent_req_data(req
,
2796 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2798 if (state
->creds
== NULL
) {
2802 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
2803 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
2804 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
2805 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
2806 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
2807 TALLOC_FREE(state
->creds
);
2811 netlogon_creds_cli_delete(state
->context
, state
->creds
);
2812 TALLOC_FREE(state
->creds
);
2815 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
);
2817 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req
*subreq
)
2819 struct tevent_req
*req
=
2820 tevent_req_callback_data(subreq
,
2822 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
2823 tevent_req_data(req
,
2824 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2827 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
2829 TALLOC_FREE(subreq
);
2830 if (tevent_req_nterror(req
, status
)) {
2834 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
2835 switch (state
->auth_level
) {
2836 case DCERPC_AUTH_LEVEL_INTEGRITY
:
2837 case DCERPC_AUTH_LEVEL_PRIVACY
:
2840 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2844 uint32_t tmp
= state
->creds
->negotiate_flags
;
2846 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
2848 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2849 * it should be used, which means
2850 * we had a chance to verify no downgrade
2853 * This relies on netlogon_creds_cli_check*
2854 * being called before, as first request after
2857 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
2863 * we defer all callbacks in order to cleanup
2864 * the database record.
2866 tevent_req_defer_callback(req
, state
->ev
);
2868 state
->tmp_creds
= *state
->creds
;
2869 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
2871 if (tevent_req_nterror(req
, status
)) {
2874 ZERO_STRUCT(state
->rep_auth
);
2876 subreq
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state
, state
->ev
,
2877 state
->binding_handle
,
2878 state
->srv_name_slash
,
2879 state
->tmp_creds
.computer_name
,
2885 if (tevent_req_nomem(subreq
, req
)) {
2886 status
= NT_STATUS_NO_MEMORY
;
2887 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
2891 tevent_req_set_callback(subreq
,
2892 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done
,
2896 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req
*subreq
)
2898 struct tevent_req
*req
=
2899 tevent_req_callback_data(subreq
,
2901 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
*state
=
2902 tevent_req_data(req
,
2903 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state
);
2909 * We use state->dns_names as the memory context, as this is
2910 * the only in/out variable and it has been overwritten by the
2911 * out parameter from the server.
2913 * We need to preserve the return value until the caller can use it.
2915 status
= dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq
, state
->dns_names
,
2917 TALLOC_FREE(subreq
);
2918 if (tevent_req_nterror(req
, status
)) {
2919 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
2923 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
2924 &state
->rep_auth
.cred
);
2926 status
= NT_STATUS_ACCESS_DENIED
;
2927 tevent_req_nterror(req
, status
);
2928 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
2932 *state
->creds
= state
->tmp_creds
;
2933 status
= netlogon_creds_cli_store(state
->context
,
2935 TALLOC_FREE(state
->creds
);
2937 if (tevent_req_nterror(req
, status
)) {
2938 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
2942 if (tevent_req_nterror(req
, result
)) {
2943 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, result
);
2947 tevent_req_done(req
);
2950 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req
*req
)
2954 if (tevent_req_is_nterror(req
, &status
)) {
2955 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req
, status
);
2956 tevent_req_received(req
);
2960 tevent_req_received(req
);
2961 return NT_STATUS_OK
;
2964 NTSTATUS
netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2965 struct netlogon_creds_cli_context
*context
,
2966 struct dcerpc_binding_handle
*b
,
2967 const char *site_name
,
2969 struct NL_DNS_NAME_INFO_ARRAY
*dns_names
)
2971 TALLOC_CTX
*frame
= talloc_stackframe();
2972 struct tevent_context
*ev
;
2973 struct tevent_req
*req
;
2974 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
2976 ev
= samba_tevent_context_init(frame
);
2980 req
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame
, ev
, context
, b
,
2987 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
2990 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req
);
2996 struct netlogon_creds_cli_ServerGetTrustInfo_state
{
2997 struct tevent_context
*ev
;
2998 struct netlogon_creds_cli_context
*context
;
2999 struct dcerpc_binding_handle
*binding_handle
;
3001 char *srv_name_slash
;
3002 enum dcerpc_AuthType auth_type
;
3003 enum dcerpc_AuthLevel auth_level
;
3005 struct samr_Password new_owf_password
;
3006 struct samr_Password old_owf_password
;
3007 struct netr_TrustInfo
*trust_info
;
3009 struct netlogon_creds_CredentialState
*creds
;
3010 struct netlogon_creds_CredentialState tmp_creds
;
3011 struct netr_Authenticator req_auth
;
3012 struct netr_Authenticator rep_auth
;
3015 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3017 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
);
3019 struct tevent_req
*netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX
*mem_ctx
,
3020 struct tevent_context
*ev
,
3021 struct netlogon_creds_cli_context
*context
,
3022 struct dcerpc_binding_handle
*b
)
3024 struct tevent_req
*req
;
3025 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
;
3026 struct tevent_req
*subreq
;
3028 req
= tevent_req_create(mem_ctx
, &state
,
3029 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3035 state
->context
= context
;
3036 state
->binding_handle
= b
;
3038 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3039 context
->server
.computer
);
3040 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3041 return tevent_req_post(req
, ev
);
3044 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3046 &state
->auth_level
);
3048 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3050 if (tevent_req_nomem(subreq
, req
)) {
3051 return tevent_req_post(req
, ev
);
3054 tevent_req_set_callback(subreq
,
3055 netlogon_creds_cli_ServerGetTrustInfo_locked
,
3061 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req
*req
,
3064 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3065 tevent_req_data(req
,
3066 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3068 if (state
->creds
== NULL
) {
3072 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3073 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3074 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3075 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3076 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3077 TALLOC_FREE(state
->creds
);
3081 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3082 TALLOC_FREE(state
->creds
);
3085 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
);
3087 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req
*subreq
)
3089 struct tevent_req
*req
=
3090 tevent_req_callback_data(subreq
,
3092 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3093 tevent_req_data(req
,
3094 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3097 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3099 TALLOC_FREE(subreq
);
3100 if (tevent_req_nterror(req
, status
)) {
3104 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3105 switch (state
->auth_level
) {
3106 case DCERPC_AUTH_LEVEL_PRIVACY
:
3109 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3113 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3118 * we defer all callbacks in order to cleanup
3119 * the database record.
3121 tevent_req_defer_callback(req
, state
->ev
);
3123 state
->tmp_creds
= *state
->creds
;
3124 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3126 if (tevent_req_nterror(req
, status
)) {
3129 ZERO_STRUCT(state
->rep_auth
);
3131 subreq
= dcerpc_netr_ServerGetTrustInfo_send(state
, state
->ev
,
3132 state
->binding_handle
,
3133 state
->srv_name_slash
,
3134 state
->tmp_creds
.account_name
,
3135 state
->tmp_creds
.secure_channel_type
,
3136 state
->tmp_creds
.computer_name
,
3139 &state
->new_owf_password
,
3140 &state
->old_owf_password
,
3141 &state
->trust_info
);
3142 if (tevent_req_nomem(subreq
, req
)) {
3143 status
= NT_STATUS_NO_MEMORY
;
3144 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3148 tevent_req_set_callback(subreq
,
3149 netlogon_creds_cli_ServerGetTrustInfo_done
,
3153 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req
*subreq
)
3155 struct tevent_req
*req
=
3156 tevent_req_callback_data(subreq
,
3158 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3159 tevent_req_data(req
,
3160 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3163 const struct samr_Password zero
= {};
3168 * We use state->dns_names as the memory context, as this is
3169 * the only in/out variable and it has been overwritten by the
3170 * out parameter from the server.
3172 * We need to preserve the return value until the caller can use it.
3174 status
= dcerpc_netr_ServerGetTrustInfo_recv(subreq
, state
, &result
);
3175 TALLOC_FREE(subreq
);
3176 if (tevent_req_nterror(req
, status
)) {
3177 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3181 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3182 &state
->rep_auth
.cred
);
3184 status
= NT_STATUS_ACCESS_DENIED
;
3185 tevent_req_nterror(req
, status
);
3186 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3190 cmp
= memcmp(state
->new_owf_password
.hash
,
3191 zero
.hash
, sizeof(zero
.hash
));
3193 status
= netlogon_creds_des_decrypt(&state
->tmp_creds
,
3194 &state
->new_owf_password
);
3195 if (tevent_req_nterror(req
, status
)) {
3196 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3200 cmp
= memcmp(state
->old_owf_password
.hash
,
3201 zero
.hash
, sizeof(zero
.hash
));
3203 status
= netlogon_creds_des_decrypt(&state
->tmp_creds
,
3204 &state
->old_owf_password
);
3205 if (tevent_req_nterror(req
, status
)) {
3206 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3211 *state
->creds
= state
->tmp_creds
;
3212 status
= netlogon_creds_cli_store(state
->context
,
3214 TALLOC_FREE(state
->creds
);
3215 if (tevent_req_nterror(req
, status
)) {
3216 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3220 if (tevent_req_nterror(req
, result
)) {
3221 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, result
);
3225 tevent_req_done(req
);
3228 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req
*req
,
3229 TALLOC_CTX
*mem_ctx
,
3230 struct samr_Password
*new_owf_password
,
3231 struct samr_Password
*old_owf_password
,
3232 struct netr_TrustInfo
**trust_info
)
3234 struct netlogon_creds_cli_ServerGetTrustInfo_state
*state
=
3235 tevent_req_data(req
,
3236 struct netlogon_creds_cli_ServerGetTrustInfo_state
);
3239 if (tevent_req_is_nterror(req
, &status
)) {
3240 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req
, status
);
3241 tevent_req_received(req
);
3245 if (new_owf_password
!= NULL
) {
3246 *new_owf_password
= state
->new_owf_password
;
3248 if (old_owf_password
!= NULL
) {
3249 *old_owf_password
= state
->old_owf_password
;
3251 if (trust_info
!= NULL
) {
3252 *trust_info
= talloc_move(mem_ctx
, &state
->trust_info
);
3255 tevent_req_received(req
);
3256 return NT_STATUS_OK
;
3259 NTSTATUS
netlogon_creds_cli_ServerGetTrustInfo(
3260 struct netlogon_creds_cli_context
*context
,
3261 struct dcerpc_binding_handle
*b
,
3262 TALLOC_CTX
*mem_ctx
,
3263 struct samr_Password
*new_owf_password
,
3264 struct samr_Password
*old_owf_password
,
3265 struct netr_TrustInfo
**trust_info
)
3267 TALLOC_CTX
*frame
= talloc_stackframe();
3268 struct tevent_context
*ev
;
3269 struct tevent_req
*req
;
3270 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3272 ev
= samba_tevent_context_init(frame
);
3276 req
= netlogon_creds_cli_ServerGetTrustInfo_send(frame
, ev
, context
, b
);
3280 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3283 status
= netlogon_creds_cli_ServerGetTrustInfo_recv(req
,
3293 struct netlogon_creds_cli_GetForestTrustInformation_state
{
3294 struct tevent_context
*ev
;
3295 struct netlogon_creds_cli_context
*context
;
3296 struct dcerpc_binding_handle
*binding_handle
;
3298 char *srv_name_slash
;
3299 enum dcerpc_AuthType auth_type
;
3300 enum dcerpc_AuthLevel auth_level
;
3303 struct lsa_ForestTrustInformation
*forest_trust_info
;
3305 struct netlogon_creds_CredentialState
*creds
;
3306 struct netlogon_creds_CredentialState tmp_creds
;
3307 struct netr_Authenticator req_auth
;
3308 struct netr_Authenticator rep_auth
;
3311 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3313 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
);
3315 struct tevent_req
*netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX
*mem_ctx
,
3316 struct tevent_context
*ev
,
3317 struct netlogon_creds_cli_context
*context
,
3318 struct dcerpc_binding_handle
*b
)
3320 struct tevent_req
*req
;
3321 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
;
3322 struct tevent_req
*subreq
;
3324 req
= tevent_req_create(mem_ctx
, &state
,
3325 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3331 state
->context
= context
;
3332 state
->binding_handle
= b
;
3334 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3335 context
->server
.computer
);
3336 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3337 return tevent_req_post(req
, ev
);
3342 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3344 &state
->auth_level
);
3346 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3348 if (tevent_req_nomem(subreq
, req
)) {
3349 return tevent_req_post(req
, ev
);
3352 tevent_req_set_callback(subreq
,
3353 netlogon_creds_cli_GetForestTrustInformation_locked
,
3359 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req
*req
,
3362 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3363 tevent_req_data(req
,
3364 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3366 if (state
->creds
== NULL
) {
3370 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3371 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3372 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3373 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3374 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3375 TALLOC_FREE(state
->creds
);
3379 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3380 TALLOC_FREE(state
->creds
);
3383 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
);
3385 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req
*subreq
)
3387 struct tevent_req
*req
=
3388 tevent_req_callback_data(subreq
,
3390 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3391 tevent_req_data(req
,
3392 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3395 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3397 TALLOC_FREE(subreq
);
3398 if (tevent_req_nterror(req
, status
)) {
3402 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3403 switch (state
->auth_level
) {
3404 case DCERPC_AUTH_LEVEL_INTEGRITY
:
3405 case DCERPC_AUTH_LEVEL_PRIVACY
:
3408 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3412 uint32_t tmp
= state
->creds
->negotiate_flags
;
3414 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
3416 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3417 * it should be used, which means
3418 * we had a chance to verify no downgrade
3421 * This relies on netlogon_creds_cli_check*
3422 * being called before, as first request after
3425 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3431 * we defer all callbacks in order to cleanup
3432 * the database record.
3434 tevent_req_defer_callback(req
, state
->ev
);
3436 state
->tmp_creds
= *state
->creds
;
3437 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3439 if (tevent_req_nterror(req
, status
)) {
3442 ZERO_STRUCT(state
->rep_auth
);
3444 subreq
= dcerpc_netr_GetForestTrustInformation_send(state
, state
->ev
,
3445 state
->binding_handle
,
3446 state
->srv_name_slash
,
3447 state
->tmp_creds
.computer_name
,
3451 &state
->forest_trust_info
);
3452 if (tevent_req_nomem(subreq
, req
)) {
3453 status
= NT_STATUS_NO_MEMORY
;
3454 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3458 tevent_req_set_callback(subreq
,
3459 netlogon_creds_cli_GetForestTrustInformation_done
,
3463 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req
*subreq
)
3465 struct tevent_req
*req
=
3466 tevent_req_callback_data(subreq
,
3468 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3469 tevent_req_data(req
,
3470 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3476 * We use state->dns_names as the memory context, as this is
3477 * the only in/out variable and it has been overwritten by the
3478 * out parameter from the server.
3480 * We need to preserve the return value until the caller can use it.
3482 status
= dcerpc_netr_GetForestTrustInformation_recv(subreq
, state
, &result
);
3483 TALLOC_FREE(subreq
);
3484 if (tevent_req_nterror(req
, status
)) {
3485 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3489 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3490 &state
->rep_auth
.cred
);
3492 status
= NT_STATUS_ACCESS_DENIED
;
3493 tevent_req_nterror(req
, status
);
3494 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3498 *state
->creds
= state
->tmp_creds
;
3499 status
= netlogon_creds_cli_store(state
->context
,
3501 TALLOC_FREE(state
->creds
);
3503 if (tevent_req_nterror(req
, status
)) {
3504 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3508 if (tevent_req_nterror(req
, result
)) {
3509 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, result
);
3513 tevent_req_done(req
);
3516 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req
*req
,
3517 TALLOC_CTX
*mem_ctx
,
3518 struct lsa_ForestTrustInformation
**forest_trust_info
)
3520 struct netlogon_creds_cli_GetForestTrustInformation_state
*state
=
3521 tevent_req_data(req
,
3522 struct netlogon_creds_cli_GetForestTrustInformation_state
);
3525 if (tevent_req_is_nterror(req
, &status
)) {
3526 netlogon_creds_cli_GetForestTrustInformation_cleanup(req
, status
);
3527 tevent_req_received(req
);
3531 *forest_trust_info
= talloc_move(mem_ctx
, &state
->forest_trust_info
);
3533 tevent_req_received(req
);
3534 return NT_STATUS_OK
;
3537 NTSTATUS
netlogon_creds_cli_GetForestTrustInformation(
3538 struct netlogon_creds_cli_context
*context
,
3539 struct dcerpc_binding_handle
*b
,
3540 TALLOC_CTX
*mem_ctx
,
3541 struct lsa_ForestTrustInformation
**forest_trust_info
)
3543 TALLOC_CTX
*frame
= talloc_stackframe();
3544 struct tevent_context
*ev
;
3545 struct tevent_req
*req
;
3546 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
3548 ev
= samba_tevent_context_init(frame
);
3552 req
= netlogon_creds_cli_GetForestTrustInformation_send(frame
, ev
, context
, b
);
3556 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3559 status
= netlogon_creds_cli_GetForestTrustInformation_recv(req
,
3566 struct netlogon_creds_cli_SendToSam_state
{
3567 struct tevent_context
*ev
;
3568 struct netlogon_creds_cli_context
*context
;
3569 struct dcerpc_binding_handle
*binding_handle
;
3571 char *srv_name_slash
;
3572 enum dcerpc_AuthType auth_type
;
3573 enum dcerpc_AuthLevel auth_level
;
3577 struct netlogon_creds_CredentialState
*creds
;
3578 struct netlogon_creds_CredentialState tmp_creds
;
3579 struct netr_Authenticator req_auth
;
3580 struct netr_Authenticator rep_auth
;
3583 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3585 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
);
3587 struct tevent_req
*netlogon_creds_cli_SendToSam_send(TALLOC_CTX
*mem_ctx
,
3588 struct tevent_context
*ev
,
3589 struct netlogon_creds_cli_context
*context
,
3590 struct dcerpc_binding_handle
*b
,
3591 struct netr_SendToSamBase
*message
)
3593 struct tevent_req
*req
;
3594 struct netlogon_creds_cli_SendToSam_state
*state
;
3595 struct tevent_req
*subreq
;
3596 enum ndr_err_code ndr_err
;
3598 req
= tevent_req_create(mem_ctx
, &state
,
3599 struct netlogon_creds_cli_SendToSam_state
);
3605 state
->context
= context
;
3606 state
->binding_handle
= b
;
3608 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3609 context
->server
.computer
);
3610 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3611 return tevent_req_post(req
, ev
);
3614 ndr_err
= ndr_push_struct_blob(&state
->opaque
, mem_ctx
, message
,
3615 (ndr_push_flags_fn_t
)ndr_push_netr_SendToSamBase
);
3616 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
3617 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
3618 tevent_req_nterror(req
, status
);
3619 return tevent_req_post(req
, ev
);
3622 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3624 &state
->auth_level
);
3626 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3628 if (tevent_req_nomem(subreq
, req
)) {
3629 return tevent_req_post(req
, ev
);
3632 tevent_req_set_callback(subreq
,
3633 netlogon_creds_cli_SendToSam_locked
,
3639 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req
*req
,
3642 struct netlogon_creds_cli_SendToSam_state
*state
=
3643 tevent_req_data(req
,
3644 struct netlogon_creds_cli_SendToSam_state
);
3646 if (state
->creds
== NULL
) {
3650 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3651 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3652 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3653 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3654 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3655 TALLOC_FREE(state
->creds
);
3659 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3660 TALLOC_FREE(state
->creds
);
3663 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
);
3665 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req
*subreq
)
3667 struct tevent_req
*req
=
3668 tevent_req_callback_data(subreq
,
3670 struct netlogon_creds_cli_SendToSam_state
*state
=
3671 tevent_req_data(req
,
3672 struct netlogon_creds_cli_SendToSam_state
);
3675 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3677 TALLOC_FREE(subreq
);
3678 if (tevent_req_nterror(req
, status
)) {
3682 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3683 switch (state
->auth_level
) {
3684 case DCERPC_AUTH_LEVEL_INTEGRITY
:
3685 case DCERPC_AUTH_LEVEL_PRIVACY
:
3688 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3692 uint32_t tmp
= state
->creds
->negotiate_flags
;
3694 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
3696 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3697 * it should be used, which means
3698 * we had a chance to verify no downgrade
3701 * This relies on netlogon_creds_cli_check*
3702 * being called before, as first request after
3705 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3711 * we defer all callbacks in order to cleanup
3712 * the database record.
3714 tevent_req_defer_callback(req
, state
->ev
);
3716 state
->tmp_creds
= *state
->creds
;
3717 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3719 if (tevent_req_nterror(req
, status
)) {
3722 ZERO_STRUCT(state
->rep_auth
);
3724 if (state
->tmp_creds
.negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
3725 status
= netlogon_creds_aes_encrypt(&state
->tmp_creds
,
3727 state
->opaque
.length
);
3728 if (tevent_req_nterror(req
, status
)) {
3729 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3733 status
= netlogon_creds_arcfour_crypt(&state
->tmp_creds
,
3735 state
->opaque
.length
);
3736 if (tevent_req_nterror(req
, status
)) {
3737 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3742 subreq
= dcerpc_netr_NetrLogonSendToSam_send(state
, state
->ev
,
3743 state
->binding_handle
,
3744 state
->srv_name_slash
,
3745 state
->tmp_creds
.computer_name
,
3749 state
->opaque
.length
);
3750 if (tevent_req_nomem(subreq
, req
)) {
3751 status
= NT_STATUS_NO_MEMORY
;
3752 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3756 tevent_req_set_callback(subreq
,
3757 netlogon_creds_cli_SendToSam_done
,
3761 static void netlogon_creds_cli_SendToSam_done(struct tevent_req
*subreq
)
3763 struct tevent_req
*req
=
3764 tevent_req_callback_data(subreq
,
3766 struct netlogon_creds_cli_SendToSam_state
*state
=
3767 tevent_req_data(req
,
3768 struct netlogon_creds_cli_SendToSam_state
);
3773 status
= dcerpc_netr_NetrLogonSendToSam_recv(subreq
, state
, &result
);
3774 TALLOC_FREE(subreq
);
3775 if (tevent_req_nterror(req
, status
)) {
3776 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3780 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
3781 &state
->rep_auth
.cred
);
3783 status
= NT_STATUS_ACCESS_DENIED
;
3784 tevent_req_nterror(req
, status
);
3785 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3789 *state
->creds
= state
->tmp_creds
;
3790 status
= netlogon_creds_cli_store(state
->context
,
3792 TALLOC_FREE(state
->creds
);
3794 if (tevent_req_nterror(req
, status
)) {
3795 netlogon_creds_cli_SendToSam_cleanup(req
, status
);
3800 * Creds must be stored before we send back application errors
3801 * e.g. NT_STATUS_NOT_IMPLEMENTED
3803 if (tevent_req_nterror(req
, result
)) {
3804 netlogon_creds_cli_SendToSam_cleanup(req
, result
);
3808 tevent_req_done(req
);
3811 NTSTATUS
netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context
*context
,
3812 struct dcerpc_binding_handle
*b
,
3813 struct netr_SendToSamBase
*message
)
3815 TALLOC_CTX
*frame
= talloc_stackframe();
3816 struct tevent_context
*ev
;
3817 struct tevent_req
*req
;
3818 NTSTATUS status
= NT_STATUS_OK
;
3820 ev
= samba_tevent_context_init(frame
);
3824 req
= netlogon_creds_cli_SendToSam_send(frame
, ev
, context
, b
, message
);
3828 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
3832 /* Ignore the result */
3838 struct netlogon_creds_cli_LogonGetDomainInfo_state
{
3839 struct tevent_context
*ev
;
3840 struct netlogon_creds_cli_context
*context
;
3841 struct dcerpc_binding_handle
*binding_handle
;
3843 char *srv_name_slash
;
3844 enum dcerpc_AuthType auth_type
;
3845 enum dcerpc_AuthLevel auth_level
;
3848 union netr_WorkstationInfo
*query
;
3849 union netr_DomainInfo
*info
;
3851 struct netlogon_creds_CredentialState
*creds
;
3852 struct netlogon_creds_CredentialState tmp_creds
;
3853 struct netr_Authenticator req_auth
;
3854 struct netr_Authenticator rep_auth
;
3857 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
3859 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
);
3861 struct tevent_req
*netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX
*mem_ctx
,
3862 struct tevent_context
*ev
,
3863 struct netlogon_creds_cli_context
*context
,
3864 struct dcerpc_binding_handle
*b
,
3866 union netr_WorkstationInfo
*query
)
3868 struct tevent_req
*req
;
3869 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
;
3870 struct tevent_req
*subreq
;
3872 req
= tevent_req_create(mem_ctx
, &state
,
3873 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
3879 state
->context
= context
;
3880 state
->binding_handle
= b
;
3882 state
->srv_name_slash
= talloc_asprintf(state
, "\\\\%s",
3883 context
->server
.computer
);
3884 if (tevent_req_nomem(state
->srv_name_slash
, req
)) {
3885 return tevent_req_post(req
, ev
);
3888 state
->level
= level
;
3889 state
->query
= query
;
3890 state
->info
= talloc_zero(state
, union netr_DomainInfo
);
3891 if (tevent_req_nomem(state
->info
, req
)) {
3892 return tevent_req_post(req
, ev
);
3895 dcerpc_binding_handle_auth_info(state
->binding_handle
,
3897 &state
->auth_level
);
3899 subreq
= netlogon_creds_cli_lock_send(state
, state
->ev
,
3901 if (tevent_req_nomem(subreq
, req
)) {
3902 return tevent_req_post(req
, ev
);
3905 tevent_req_set_callback(subreq
,
3906 netlogon_creds_cli_LogonGetDomainInfo_locked
,
3912 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req
*req
,
3915 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
3916 tevent_req_data(req
,
3917 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
3919 if (state
->creds
== NULL
) {
3923 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
) &&
3924 !NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) &&
3925 !NT_STATUS_EQUAL(status
, NT_STATUS_DOWNGRADE_DETECTED
) &&
3926 !NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) &&
3927 !NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
)) {
3928 TALLOC_FREE(state
->creds
);
3932 netlogon_creds_cli_delete(state
->context
, state
->creds
);
3935 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
);
3937 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req
*subreq
)
3939 struct tevent_req
*req
=
3940 tevent_req_callback_data(subreq
,
3942 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
3943 tevent_req_data(req
,
3944 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
3947 status
= netlogon_creds_cli_lock_recv(subreq
, state
,
3949 TALLOC_FREE(subreq
);
3950 if (tevent_req_nterror(req
, status
)) {
3954 if (state
->auth_type
== DCERPC_AUTH_TYPE_SCHANNEL
) {
3955 switch (state
->auth_level
) {
3956 case DCERPC_AUTH_LEVEL_INTEGRITY
:
3957 case DCERPC_AUTH_LEVEL_PRIVACY
:
3960 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3964 uint32_t tmp
= state
->creds
->negotiate_flags
;
3966 if (tmp
& NETLOGON_NEG_AUTHENTICATED_RPC
) {
3968 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3969 * it should be used, which means
3970 * we had a chance to verify no downgrade
3973 * This relies on netlogon_creds_cli_check*
3974 * being called before, as first request after
3977 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER_MIX
);
3983 * we defer all callbacks in order to cleanup
3984 * the database record.
3986 tevent_req_defer_callback(req
, state
->ev
);
3988 state
->tmp_creds
= *state
->creds
;
3989 status
= netlogon_creds_client_authenticator(&state
->tmp_creds
,
3991 if (tevent_req_nterror(req
, status
)) {
3994 ZERO_STRUCT(state
->rep_auth
);
3996 subreq
= dcerpc_netr_LogonGetDomainInfo_send(state
, state
->ev
,
3997 state
->binding_handle
,
3998 state
->srv_name_slash
,
3999 state
->tmp_creds
.computer_name
,
4005 if (tevent_req_nomem(subreq
, req
)) {
4006 status
= NT_STATUS_NO_MEMORY
;
4007 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4011 tevent_req_set_callback(subreq
,
4012 netlogon_creds_cli_LogonGetDomainInfo_done
,
4016 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req
*subreq
)
4018 struct tevent_req
*req
=
4019 tevent_req_callback_data(subreq
,
4021 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4022 tevent_req_data(req
,
4023 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4029 * We use state->dns_names as the memory context, as this is
4030 * the only in/out variable and it has been overwritten by the
4031 * out parameter from the server.
4033 * We need to preserve the return value until the caller can use it.
4035 status
= dcerpc_netr_LogonGetDomainInfo_recv(subreq
, state
->info
, &result
);
4036 TALLOC_FREE(subreq
);
4037 if (tevent_req_nterror(req
, status
)) {
4038 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4042 ok
= netlogon_creds_client_check(&state
->tmp_creds
,
4043 &state
->rep_auth
.cred
);
4045 status
= NT_STATUS_ACCESS_DENIED
;
4046 tevent_req_nterror(req
, status
);
4047 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4051 if (tevent_req_nterror(req
, result
)) {
4052 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, result
);
4056 *state
->creds
= state
->tmp_creds
;
4057 status
= netlogon_creds_cli_store(state
->context
,
4059 if (tevent_req_nterror(req
, status
)) {
4060 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4064 tevent_req_done(req
);
4067 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req
*req
,
4068 TALLOC_CTX
*mem_ctx
,
4069 union netr_DomainInfo
**info
)
4071 struct netlogon_creds_cli_LogonGetDomainInfo_state
*state
=
4072 tevent_req_data(req
,
4073 struct netlogon_creds_cli_LogonGetDomainInfo_state
);
4076 if (tevent_req_is_nterror(req
, &status
)) {
4077 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req
, status
);
4078 tevent_req_received(req
);
4082 *info
= talloc_move(mem_ctx
, &state
->info
);
4084 tevent_req_received(req
);
4085 return NT_STATUS_OK
;
4088 NTSTATUS
netlogon_creds_cli_LogonGetDomainInfo(
4089 struct netlogon_creds_cli_context
*context
,
4090 struct dcerpc_binding_handle
*b
,
4091 TALLOC_CTX
*mem_ctx
,
4093 union netr_WorkstationInfo
*query
,
4094 union netr_DomainInfo
**info
)
4096 TALLOC_CTX
*frame
= talloc_stackframe();
4097 struct tevent_context
*ev
;
4098 struct tevent_req
*req
;
4099 NTSTATUS status
= NT_STATUS_OK
;
4101 ev
= samba_tevent_context_init(frame
);
4105 req
= netlogon_creds_cli_LogonGetDomainInfo_send(frame
, ev
, context
, b
,
4110 if (!tevent_req_poll_ntstatus(req
, ev
, &status
)) {
4113 status
= netlogon_creds_cli_LogonGetDomainInfo_recv(req
,