CVE-2020-1472(ZeroLogon): libcli/auth: make use of netlogon_creds_random_challenge...
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob12cb3149ff607feeba4837a11157d56d2129aef5
1 /*
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/>.
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include <tevent.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 {
46 struct {
47 const char *computer;
48 const char *account;
49 uint32_t proposed_flags;
50 uint32_t required_flags;
51 enum netr_SchannelType type;
52 enum dcerpc_AuthLevel auth_level;
53 } client;
55 struct {
56 const char *computer;
57 const char *netbios_domain;
58 const char *dns_domain;
59 uint32_t cached_flags;
60 bool try_validation6;
61 bool try_logon_ex;
62 bool try_logon_with;
63 } server;
65 struct {
66 const char *key_name;
67 TDB_DATA key_data;
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;
72 } db;
75 struct netlogon_creds_cli_locked_state {
76 struct netlogon_creds_cli_context *context;
77 bool is_glocked;
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) {
87 return 0;
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));
99 return 0;
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,
112 TALLOC_CTX *mem_ctx,
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;
118 char *p = NULL;
120 *_context = NULL;
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;
163 * TODO:
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, '.');
172 if (p != NULL) {
173 server_netbios_name_len = p-server_computer;
174 } else {
175 server_netbios_name_len = strlen(server_computer);
178 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
179 client_computer,
180 client_account,
181 (int)server_netbios_name_len,
182 server_computer,
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);
198 *_context = context;
199 return NT_STATUS_OK;
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);
211 return NT_STATUS_OK;
214 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
216 char *fname;
217 struct db_context *global_db;
218 int hash_size, tdb_flags;
220 if (netlogon_creds_cli_global_db != NULL) {
221 return NT_STATUS_OK;
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 if (fname == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
230 tdb_flags = lpcfg_tdb_flags(
231 lp_ctx,
232 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
234 global_db = dbwrap_local_open(
235 NULL,
236 fname,
237 hash_size,
238 tdb_flags,
239 O_RDWR|O_CREAT,
240 0600,
241 DBWRAP_LOCK_ORDER_2,
242 DBWRAP_FLAG_NONE);
243 if (global_db == NULL) {
244 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
245 fname, strerror(errno)));
246 talloc_free(fname);
247 return NT_STATUS_NO_MEMORY;
249 TALLOC_FREE(fname);
251 netlogon_creds_cli_global_db = global_db;
252 return NT_STATUS_OK;
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,
267 TALLOC_CTX *mem_ctx,
268 struct netlogon_creds_cli_context **_context)
270 TALLOC_CTX *frame = talloc_stackframe();
271 NTSTATUS status;
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;
283 *_context = NULL;
285 if (msg_ctx == NULL) {
286 TALLOC_FREE(frame);
287 return NT_STATUS_INVALID_PARAMETER_MIX;
290 client_computer = lpcfg_netbios_name(lp_ctx);
291 if (strlen(client_computer) > 15) {
292 TALLOC_FREE(frame);
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,
304 reject_md5_servers);
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,
314 require_strong_key);
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,
322 "client schannel",
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;
349 switch (type) {
350 case SEC_CHAN_WKSTA:
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;
359 break;
361 case SEC_CHAN_DOMAIN:
362 break;
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;
372 break;
374 case SEC_CHAN_BDC:
375 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
376 require_sign_or_seal = true;
377 require_strong_key = true;
378 break;
380 case SEC_CHAN_RODC:
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;
386 break;
388 default:
389 TALLOC_FREE(frame);
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;
400 } else {
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;
421 } else {
422 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
425 status = netlogon_creds_cli_context_common(client_computer,
426 client_account,
427 type,
428 auth_level,
429 proposed_flags,
430 required_flags,
431 server_computer,
432 server_netbios_domain,
434 mem_ctx,
435 &context);
436 if (!NT_STATUS_IS_OK(status)) {
437 TALLOC_FREE(frame);
438 return status;
441 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
442 if (context->db.g_ctx == NULL) {
443 TALLOC_FREE(context);
444 TALLOC_FREE(frame);
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);
451 TALLOC_FREE(frame);
452 return NT_STATUS_NO_MEMORY;
455 context->db.ctx = netlogon_creds_cli_global_db;
456 *_context = context;
457 TALLOC_FREE(frame);
458 return NT_STATUS_OK;
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;
467 NTSTATUS status;
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,
476 CRED_SPECIFIED);
477 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
478 CRED_SPECIFIED);
479 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
480 CRED_SPECIFIED);
482 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
483 if (!NT_STATUS_IS_OK(status)) {
484 TALLOC_FREE(cli_creds);
485 return status;
487 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
489 *pcli_creds = cli_creds;
490 return NT_STATUS_OK;
493 char *netlogon_creds_cli_debug_string(
494 const struct netlogon_creds_cli_context *context,
495 TALLOC_CTX *mem_ctx)
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 {
508 TALLOC_CTX *mem_ctx;
509 struct netlogon_creds_CredentialState *creds;
510 uint32_t required_flags;
511 NTSTATUS status;
514 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
515 void *private_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;
520 DATA_BLOB blob;
521 uint32_t tmp_flags;
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;
527 return;
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);
538 return;
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;
550 return;
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,
561 TALLOC_CTX *mem_ctx,
562 struct netlogon_creds_CredentialState **_creds)
564 NTSTATUS status;
565 struct netlogon_creds_CredentialState *creds;
567 *_creds = NULL;
569 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
570 if (!NT_STATUS_IS_OK(status)) {
571 return status;
575 * mark it as invalid for step operations.
577 creds->sequence = 0;
578 creds->seed = (struct netr_Credential) {{0}};
579 creds->client = (struct netr_Credential) {{0}};
580 creds->server = (struct netr_Credential) {{0}};
582 *_creds = creds;
583 return NT_STATUS_OK;
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;
591 DATA_BLOB blob1;
592 DATA_BLOB blob2;
593 NTSTATUS status;
594 enum ndr_err_code ndr_err;
595 int cmp;
597 status = netlogon_creds_cli_get(context, frame, &creds2);
598 if (!NT_STATUS_IS_OK(status)) {
599 TALLOC_FREE(frame);
600 return false;
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)) {
606 TALLOC_FREE(frame);
607 return false;
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)) {
613 TALLOC_FREE(frame);
614 return false;
617 cmp = data_blob_cmp(&blob1, &blob2);
619 TALLOC_FREE(frame);
621 return (cmp == 0);
624 static NTSTATUS netlogon_creds_cli_store_internal(
625 struct netlogon_creds_cli_context *context,
626 struct netlogon_creds_CredentialState *creds)
628 NTSTATUS status;
629 enum ndr_err_code ndr_err;
630 DATA_BLOB blob;
631 TDB_DATA data;
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);
641 return status;
644 data.dptr = blob.data;
645 data.dsize = blob.length;
647 status = dbwrap_store(context->db.ctx,
648 context->db.key_data,
649 data, TDB_REPLACE);
650 TALLOC_FREE(data.dptr);
651 if (!NT_STATUS_IS_OK(status)) {
652 return status;
655 return NT_STATUS_OK;
658 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
659 struct netlogon_creds_CredentialState *creds)
661 NTSTATUS status;
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);
678 return status;
681 static NTSTATUS netlogon_creds_cli_delete_internal(
682 struct netlogon_creds_cli_context *context)
684 NTSTATUS status;
685 status = dbwrap_delete(context->db.ctx, context->db.key_data);
686 return status;
689 NTSTATUS netlogon_creds_cli_delete_lck(
690 struct netlogon_creds_cli_context *context)
692 NTSTATUS status;
694 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
695 return NT_STATUS_NOT_LOCKED;
698 status = netlogon_creds_cli_delete_internal(context);
699 return status;
702 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
703 struct netlogon_creds_CredentialState *creds)
705 NTSTATUS status;
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);
722 return status;
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);
743 if (req == NULL) {
744 return NULL;
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) {
764 NTSTATUS status;
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);
772 return req;
775 subreq = g_lock_lock_send(state, ev,
776 context->db.g_ctx,
777 string_term_tdb_data(context->db.key_name),
778 G_LOCK_WRITE);
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);
784 return req;
787 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
789 struct tevent_req *req =
790 tevent_req_callback_data(subreq,
791 struct tevent_req);
792 struct netlogon_creds_cli_lock_state *state =
793 tevent_req_data(req,
794 struct netlogon_creds_cli_lock_state);
795 NTSTATUS status;
797 status = g_lock_lock_recv(subreq);
798 TALLOC_FREE(subreq);
799 if (tevent_req_nterror(req, status)) {
800 return;
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)) {
807 return;
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,
820 NTSTATUS status;
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,
826 &fstate);
827 if (!NT_STATUS_IS_OK(status)) {
828 return 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;
836 return NT_STATUS_OK;
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
843 * chain.
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
852 * by computer name.
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;
885 return NT_STATUS_OK;
888 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
889 TALLOC_CTX *mem_ctx,
890 struct netlogon_creds_CredentialState **creds)
892 struct netlogon_creds_cli_lock_state *state =
893 tevent_req_data(req,
894 struct netlogon_creds_cli_lock_state);
895 NTSTATUS status;
897 if (tevent_req_is_nterror(req, &status)) {
898 tevent_req_received(req);
899 return status;
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);
906 return NT_STATUS_OK;
909 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
910 TALLOC_CTX *mem_ctx,
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);
919 if (ev == NULL) {
920 goto fail;
922 req = netlogon_creds_cli_lock_send(frame, ev, context);
923 if (req == NULL) {
924 goto fail;
926 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
927 goto fail;
929 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
930 fail:
931 TALLOC_FREE(frame);
932 return status;
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);
959 if (req == NULL) {
960 return NULL;
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);
969 switch (type) {
970 case NETLOGON_CREDS_CLI_LCK_SHARED:
971 gtype = G_LOCK_READ;
972 break;
973 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
974 gtype = G_LOCK_WRITE;
975 break;
976 default:
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;
986 state->type = type;
988 subreq = g_lock_lock_send(state, ev,
989 context->db.g_ctx,
990 string_term_tdb_data(context->db.key_name),
991 gtype);
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);
997 return 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);
1006 NTSTATUS status;
1008 status = g_lock_lock_recv(subreq);
1009 TALLOC_FREE(subreq);
1010 if (tevent_req_nterror(req, status)) {
1011 return;
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;
1024 NTSTATUS status;
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;
1033 return 0;
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);
1042 NTSTATUS status;
1044 if (tevent_req_is_nterror(req, &status)) {
1045 return 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);
1062 if (ev == NULL) {
1063 goto fail;
1065 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1066 if (req == NULL) {
1067 goto fail;
1069 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1070 goto fail;
1072 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1073 fail:
1074 TALLOC_FREE(frame);
1075 return status;
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;
1093 uint32_t rid;
1094 bool try_auth3;
1095 bool try_auth2;
1096 bool require_auth2;
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;
1110 NTSTATUS status;
1112 req = tevent_req_create(mem_ctx, &state,
1113 struct netlogon_creds_cli_auth_state);
1114 if (req == NULL) {
1115 return NULL;
1118 state->ev = ev;
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);
1166 return req;
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)) {
1189 return;
1191 tevent_req_set_callback(subreq,
1192 netlogon_creds_cli_auth_challenge_done,
1193 req);
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,
1202 struct tevent_req);
1203 struct netlogon_creds_cli_auth_state *state =
1204 tevent_req_data(req,
1205 struct netlogon_creds_cli_auth_state);
1206 NTSTATUS status;
1207 NTSTATUS result;
1209 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1210 TALLOC_FREE(subreq);
1211 if (tevent_req_nterror(req, status)) {
1212 return;
1214 if (tevent_req_nterror(req, result)) {
1215 return;
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)) {
1234 return;
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,
1247 &state->rid);
1248 if (tevent_req_nomem(subreq, req)) {
1249 return;
1251 } else if (state->try_auth2) {
1252 state->rid = 0;
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)) {
1264 return;
1266 } else {
1267 state->rid = 0;
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)) {
1278 return;
1281 tevent_req_set_callback(subreq,
1282 netlogon_creds_cli_auth_srvauth_done,
1283 req);
1286 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1288 struct tevent_req *req =
1289 tevent_req_callback_data(subreq,
1290 struct tevent_req);
1291 struct netlogon_creds_cli_auth_state *state =
1292 tevent_req_data(req,
1293 struct netlogon_creds_cli_auth_state);
1294 NTSTATUS status;
1295 NTSTATUS result;
1296 bool ok;
1297 enum ndr_err_code ndr_err;
1298 DATA_BLOB blob;
1299 TDB_DATA data;
1300 uint32_t tmp_flags;
1302 if (state->try_auth3) {
1303 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1304 &result);
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);
1309 return;
1311 if (tevent_req_nterror(req, status)) {
1312 return;
1314 } else if (state->try_auth2) {
1315 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1316 &result);
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);
1323 return;
1325 netlogon_creds_cli_auth_challenge_start(req);
1326 return;
1328 if (tevent_req_nterror(req, status)) {
1329 return;
1331 } else {
1332 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1333 &result);
1334 TALLOC_FREE(subreq);
1335 if (tevent_req_nterror(req, status)) {
1336 return;
1340 if (!NT_STATUS_IS_OK(result) &&
1341 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1343 tevent_req_nterror(req, result);
1344 return;
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);
1352 return;
1354 tevent_req_nterror(req, result);
1355 return;
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);
1369 return;
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);
1378 return;
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);
1387 return;
1390 ok = netlogon_creds_client_check(state->creds,
1391 &state->server_credential);
1392 if (!ok) {
1393 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1394 return;
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);
1402 return;
1405 data.dptr = blob.data;
1406 data.dsize = blob.length;
1408 status = dbwrap_store(state->context->db.ctx,
1409 state->context->db.key_data,
1410 data, TDB_REPLACE);
1411 if (tevent_req_nterror(req, status)) {
1412 return;
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);
1424 NTSTATUS status;
1426 *idx_nt_hashes = 0;
1428 if (tevent_req_is_nterror(req, &status)) {
1429 tevent_req_received(req);
1430 return status;
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;
1449 *idx_nt_hashes = 0;
1451 ev = samba_tevent_context_init(frame);
1452 if (ev == NULL) {
1453 goto fail;
1455 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1456 num_nt_hashes, nt_hashes);
1457 if (req == NULL) {
1458 goto fail;
1460 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1461 goto fail;
1463 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1464 fail:
1465 TALLOC_FREE(frame);
1466 return status;
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,
1484 NTSTATUS status);
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;
1497 NTSTATUS status;
1499 req = tevent_req_create(mem_ctx, &state,
1500 struct netlogon_creds_cli_check_state);
1501 if (req == NULL) {
1502 return NULL;
1505 state->ev = ev;
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,
1515 &state->creds);
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:
1537 break;
1538 default:
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,
1550 &state->req_auth);
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,
1560 &state->req_auth,
1561 &state->rep_auth,
1563 &state->caps);
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,
1570 req);
1572 return req;
1575 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1576 NTSTATUS status)
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) {
1583 return;
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);
1592 return;
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,
1603 struct tevent_req);
1604 struct netlogon_creds_cli_check_state *state =
1605 tevent_req_data(req,
1606 struct netlogon_creds_cli_check_state);
1607 NTSTATUS status;
1608 NTSTATUS result;
1609 bool ok;
1611 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1612 &result);
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);
1629 return;
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);
1644 return;
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
1658 * gets out of sync.
1660 netlogon_creds_cli_check_cleanup(req, status);
1661 tevent_req_done(req);
1662 return;
1664 if (tevent_req_nterror(req, status)) {
1665 netlogon_creds_cli_check_cleanup(req, status);
1666 return;
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);
1684 return;
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);
1697 return;
1700 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1701 if (!ok) {
1702 status = NT_STATUS_ACCESS_DENIED;
1703 tevent_req_nterror(req, status);
1704 netlogon_creds_cli_check_cleanup(req, status);
1705 return;
1708 if (tevent_req_nterror(req, result)) {
1709 netlogon_creds_cli_check_cleanup(req, result);
1710 return;
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);
1717 return;
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);
1732 return;
1735 status = netlogon_creds_cli_store_internal(state->context,
1736 state->creds);
1737 if (tevent_req_nterror(req, status)) {
1738 return;
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);
1749 NTSTATUS status;
1751 if (tevent_req_is_nterror(req, &status)) {
1752 netlogon_creds_cli_check_cleanup(req, status);
1753 tevent_req_received(req);
1754 return status;
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);
1775 if (ev == NULL) {
1776 goto fail;
1778 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1779 if (req == NULL) {
1780 goto fail;
1782 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1783 goto fail;
1785 status = netlogon_creds_cli_check_recv(req, capabilities);
1786 fail:
1787 TALLOC_FREE(frame);
1788 return status;
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,
1812 NTSTATUS status);
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;
1825 bool ok;
1827 req = tevent_req_create(mem_ctx, &state,
1828 struct netlogon_creds_cli_ServerPasswordSet_state);
1829 if (req == NULL) {
1830 return NULL;
1833 state->ev = ev;
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,
1851 new_password);
1852 if (!ok) {
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;
1861 uint8_t *p;
1863 if (len > 500) {
1864 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1865 return tevent_req_post(req, ev);
1867 ofs -= 12;
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,
1887 &state->auth_type,
1888 &state->auth_level);
1890 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1891 state->context);
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,
1898 req);
1900 return req;
1903 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1904 NTSTATUS status)
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) {
1911 return;
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);
1923 return;
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,
1936 struct tevent_req);
1937 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1938 tevent_req_data(req,
1939 struct netlogon_creds_cli_ServerPasswordSet_state);
1940 NTSTATUS status;
1942 status = netlogon_creds_cli_lock_recv(subreq, state,
1943 &state->creds);
1944 TALLOC_FREE(subreq);
1945 if (tevent_req_nterror(req, status)) {
1946 return;
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:
1953 break;
1954 default:
1955 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1956 return;
1958 } else {
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
1966 * happened.
1968 * This relies on netlogon_creds_cli_check*
1969 * being called before, as first request after
1970 * the DCERPC bind.
1972 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1973 return;
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,
1988 &state->req_auth);
1989 if (tevent_req_nterror(req, status)) {
1990 return;
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,
1999 516);
2000 if (tevent_req_nterror(req, status)) {
2001 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2002 return;
2004 } else {
2005 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2006 state->samr_crypt_password.data,
2007 516);
2008 if (tevent_req_nterror(req, status)) {
2009 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2010 return;
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,
2025 &state->req_auth,
2026 &state->rep_auth,
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);
2031 return;
2033 } else {
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);
2038 return;
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,
2047 &state->req_auth,
2048 &state->rep_auth,
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);
2053 return;
2057 tevent_req_set_callback(subreq,
2058 netlogon_creds_cli_ServerPasswordSet_done,
2059 req);
2062 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2064 struct tevent_req *req =
2065 tevent_req_callback_data(subreq,
2066 struct tevent_req);
2067 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2068 tevent_req_data(req,
2069 struct netlogon_creds_cli_ServerPasswordSet_state);
2070 NTSTATUS status;
2071 NTSTATUS result;
2072 bool ok;
2074 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2075 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2076 &result);
2077 TALLOC_FREE(subreq);
2078 if (tevent_req_nterror(req, status)) {
2079 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2080 return;
2082 } else {
2083 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2084 &result);
2085 TALLOC_FREE(subreq);
2086 if (tevent_req_nterror(req, status)) {
2087 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2088 return;
2092 ok = netlogon_creds_client_check(&state->tmp_creds,
2093 &state->rep_auth.cred);
2094 if (!ok) {
2095 status = NT_STATUS_ACCESS_DENIED;
2096 tevent_req_nterror(req, status);
2097 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2098 return;
2101 if (tevent_req_nterror(req, result)) {
2102 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2103 return;
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,
2111 state->creds);
2112 TALLOC_FREE(state->creds);
2113 if (tevent_req_nterror(req, status)) {
2114 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2115 return;
2118 tevent_req_done(req);
2121 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2123 NTSTATUS status;
2125 if (tevent_req_is_nterror(req, &status)) {
2126 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2127 tevent_req_received(req);
2128 return status;
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);
2147 if (ev == NULL) {
2148 goto fail;
2150 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2151 new_password,
2152 new_version);
2153 if (req == NULL) {
2154 goto fail;
2156 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2157 goto fail;
2159 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2160 fail:
2161 TALLOC_FREE(frame);
2162 return status;
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;
2175 uint32_t flags;
2177 uint16_t validation_level;
2178 union netr_Validation *validation;
2179 uint8_t authoritative;
2182 * do we need encryption at the application layer?
2184 bool user_encrypt;
2185 bool try_logon_ex;
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,
2215 NTSTATUS status);
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,
2223 uint32_t flags)
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);
2230 if (req == NULL) {
2231 return NULL;
2234 state->ev = ev;
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;
2255 break;
2257 case NetlogonNetworkInformation:
2258 case NetlogonNetworkTransitiveInformation:
2259 break;
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);
2277 return req;
2280 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2281 NTSTATUS status)
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) {
2288 return;
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);
2321 return;
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;
2336 NTSTATUS status;
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;
2361 } else {
2362 state->validation_level = 3;
2363 state->user_encrypt = true;
2366 state->logon = netlogon_creds_shallow_copy_logon(state,
2367 state->logon_level,
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);
2372 return;
2375 if (state->user_encrypt) {
2376 status = netlogon_creds_cli_get(state->context,
2377 state,
2378 &state->ro_creds);
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);
2383 return;
2386 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2387 state->logon_level,
2388 state->logon);
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);
2393 return;
2397 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2398 state->binding_handle,
2399 state->srv_name_slash,
2400 state->context->client.computer,
2401 state->logon_level,
2402 state->logon,
2403 state->validation_level,
2404 state->validation,
2405 &state->authoritative,
2406 &state->flags);
2407 if (tevent_req_nomem(subreq, req)) {
2408 status = NT_STATUS_NO_MEMORY;
2409 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2410 return;
2412 tevent_req_set_callback(subreq,
2413 netlogon_creds_cli_LogonSamLogon_done,
2414 req);
2415 return;
2418 if (state->lk_creds == NULL) {
2419 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2420 state->context);
2421 if (tevent_req_nomem(subreq, req)) {
2422 status = NT_STATUS_NO_MEMORY;
2423 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2424 return;
2426 tevent_req_set_callback(subreq,
2427 netlogon_creds_cli_LogonSamLogon_done,
2428 req);
2429 return;
2432 state->tmp_creds = *state->lk_creds;
2433 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2434 &state->req_auth);
2435 if (tevent_req_nterror(req, status)) {
2436 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2437 return;
2439 ZERO_STRUCT(state->rep_auth);
2441 state->logon = netlogon_creds_shallow_copy_logon(state,
2442 state->logon_level,
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);
2447 return;
2450 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2451 state->logon_level,
2452 state->logon);
2453 if (tevent_req_nterror(req, status)) {
2454 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2455 return;
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,
2465 &state->req_auth,
2466 &state->rep_auth,
2467 state->logon_level,
2468 state->logon,
2469 state->validation_level,
2470 state->validation,
2471 &state->authoritative,
2472 &state->flags);
2473 if (tevent_req_nomem(subreq, req)) {
2474 status = NT_STATUS_NO_MEMORY;
2475 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2476 return;
2478 } else {
2479 state->flags = 0;
2481 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2482 state->binding_handle,
2483 state->srv_name_slash,
2484 state->context->client.computer,
2485 &state->req_auth,
2486 &state->rep_auth,
2487 state->logon_level,
2488 state->logon,
2489 state->validation_level,
2490 state->validation,
2491 &state->authoritative);
2492 if (tevent_req_nomem(subreq, req)) {
2493 status = NT_STATUS_NO_MEMORY;
2494 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2495 return;
2499 tevent_req_set_callback(subreq,
2500 netlogon_creds_cli_LogonSamLogon_done,
2501 req);
2504 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2506 struct tevent_req *req =
2507 tevent_req_callback_data(subreq,
2508 struct tevent_req);
2509 struct netlogon_creds_cli_LogonSamLogon_state *state =
2510 tevent_req_data(req,
2511 struct netlogon_creds_cli_LogonSamLogon_state);
2512 NTSTATUS status;
2513 NTSTATUS result;
2514 bool ok;
2516 if (state->try_logon_ex) {
2517 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2518 state->validation,
2519 &result);
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);
2525 return;
2527 if (tevent_req_nterror(req, status)) {
2528 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2529 return;
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);
2539 return;
2542 if (tevent_req_nterror(req, result)) {
2543 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2544 return;
2547 if (state->ro_creds == NULL) {
2548 tevent_req_done(req);
2549 return;
2552 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2553 if (!ok) {
2555 * We got a race, lets retry with on authenticator
2556 * protection.
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);
2563 return;
2566 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2567 state->validation_level,
2568 state->validation);
2569 if (tevent_req_nterror(req, status)) {
2570 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 return;
2574 tevent_req_done(req);
2575 return;
2578 if (state->lk_creds == NULL) {
2579 status = netlogon_creds_cli_lock_recv(subreq, state,
2580 &state->lk_creds);
2581 TALLOC_FREE(subreq);
2582 if (tevent_req_nterror(req, status)) {
2583 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2584 return;
2587 netlogon_creds_cli_LogonSamLogon_start(req);
2588 return;
2591 if (state->context->server.try_logon_with) {
2592 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2593 state->validation,
2594 &result);
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);
2599 return;
2601 if (tevent_req_nterror(req, status)) {
2602 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2603 return;
2605 } else {
2606 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2607 state->validation,
2608 &result);
2609 TALLOC_FREE(subreq);
2610 if (tevent_req_nterror(req, status)) {
2611 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2612 return;
2616 ok = netlogon_creds_client_check(&state->tmp_creds,
2617 &state->rep_auth.cred);
2618 if (!ok) {
2619 status = NT_STATUS_ACCESS_DENIED;
2620 tevent_req_nterror(req, status);
2621 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2622 return;
2625 *state->lk_creds = state->tmp_creds;
2626 status = netlogon_creds_cli_store(state->context,
2627 state->lk_creds);
2628 TALLOC_FREE(state->lk_creds);
2630 if (tevent_req_nterror(req, status)) {
2631 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2632 return;
2635 if (tevent_req_nterror(req, result)) {
2636 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2637 return;
2640 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2641 state->validation_level,
2642 state->validation);
2643 if (tevent_req_nterror(req, status)) {
2644 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2645 return;
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,
2656 uint32_t *flags)
2658 struct netlogon_creds_cli_LogonSamLogon_state *state =
2659 tevent_req_data(req,
2660 struct netlogon_creds_cli_LogonSamLogon_state);
2661 NTSTATUS status;
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);
2669 return status;
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,
2689 uint32_t *flags)
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);
2697 if (ev == NULL) {
2698 goto fail;
2700 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2701 logon_level, logon,
2702 *flags);
2703 if (req == NULL) {
2704 goto fail;
2706 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2707 goto fail;
2709 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2710 validation_level,
2711 validation,
2712 authoritative,
2713 flags);
2714 fail:
2715 TALLOC_FREE(frame);
2716 return status;
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;
2729 uint32_t dns_ttl;
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,
2739 NTSTATUS status);
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,
2747 uint32_t dns_ttl,
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);
2756 if (req == NULL) {
2757 return NULL;
2760 state->ev = ev;
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,
2775 &state->auth_type,
2776 &state->auth_level);
2778 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2779 state->context);
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,
2786 req);
2788 return req;
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2792 NTSTATUS status)
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) {
2799 return;
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);
2808 return;
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,
2821 struct tevent_req);
2822 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2823 tevent_req_data(req,
2824 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2825 NTSTATUS status;
2827 status = netlogon_creds_cli_lock_recv(subreq, state,
2828 &state->creds);
2829 TALLOC_FREE(subreq);
2830 if (tevent_req_nterror(req, status)) {
2831 return;
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:
2838 break;
2839 default:
2840 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2841 return;
2843 } else {
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
2851 * happened.
2853 * This relies on netlogon_creds_cli_check*
2854 * being called before, as first request after
2855 * the DCERPC bind.
2857 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2858 return;
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,
2870 &state->req_auth);
2871 if (tevent_req_nterror(req, status)) {
2872 return;
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,
2880 &state->req_auth,
2881 &state->rep_auth,
2882 state->site_name,
2883 state->dns_ttl,
2884 state->dns_names);
2885 if (tevent_req_nomem(subreq, req)) {
2886 status = NT_STATUS_NO_MEMORY;
2887 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2888 return;
2891 tevent_req_set_callback(subreq,
2892 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2893 req);
2896 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2898 struct tevent_req *req =
2899 tevent_req_callback_data(subreq,
2900 struct tevent_req);
2901 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2902 tevent_req_data(req,
2903 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2904 NTSTATUS status;
2905 NTSTATUS result;
2906 bool ok;
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,
2916 &result);
2917 TALLOC_FREE(subreq);
2918 if (tevent_req_nterror(req, status)) {
2919 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2920 return;
2923 ok = netlogon_creds_client_check(&state->tmp_creds,
2924 &state->rep_auth.cred);
2925 if (!ok) {
2926 status = NT_STATUS_ACCESS_DENIED;
2927 tevent_req_nterror(req, status);
2928 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2929 return;
2932 *state->creds = state->tmp_creds;
2933 status = netlogon_creds_cli_store(state->context,
2934 state->creds);
2935 TALLOC_FREE(state->creds);
2937 if (tevent_req_nterror(req, status)) {
2938 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2939 return;
2942 if (tevent_req_nterror(req, result)) {
2943 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2944 return;
2947 tevent_req_done(req);
2950 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2952 NTSTATUS status;
2954 if (tevent_req_is_nterror(req, &status)) {
2955 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2956 tevent_req_received(req);
2957 return status;
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,
2968 uint32_t dns_ttl,
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);
2977 if (ev == NULL) {
2978 goto fail;
2980 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2981 site_name,
2982 dns_ttl,
2983 dns_names);
2984 if (req == NULL) {
2985 goto fail;
2987 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2988 goto fail;
2990 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2991 fail:
2992 TALLOC_FREE(frame);
2993 return status;
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,
3016 NTSTATUS status);
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);
3030 if (req == NULL) {
3031 return NULL;
3034 state->ev = ev;
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,
3045 &state->auth_type,
3046 &state->auth_level);
3048 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3049 state->context);
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,
3056 req);
3058 return req;
3061 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3062 NTSTATUS status)
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) {
3069 return;
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);
3078 return;
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,
3091 struct tevent_req);
3092 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3093 tevent_req_data(req,
3094 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3095 NTSTATUS status;
3097 status = netlogon_creds_cli_lock_recv(subreq, state,
3098 &state->creds);
3099 TALLOC_FREE(subreq);
3100 if (tevent_req_nterror(req, status)) {
3101 return;
3104 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3105 switch (state->auth_level) {
3106 case DCERPC_AUTH_LEVEL_PRIVACY:
3107 break;
3108 default:
3109 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3110 return;
3112 } else {
3113 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3114 return;
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,
3125 &state->req_auth);
3126 if (tevent_req_nterror(req, status)) {
3127 return;
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,
3137 &state->req_auth,
3138 &state->rep_auth,
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);
3145 return;
3148 tevent_req_set_callback(subreq,
3149 netlogon_creds_cli_ServerGetTrustInfo_done,
3150 req);
3153 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3155 struct tevent_req *req =
3156 tevent_req_callback_data(subreq,
3157 struct tevent_req);
3158 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3159 tevent_req_data(req,
3160 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3161 NTSTATUS status;
3162 NTSTATUS result;
3163 const struct samr_Password zero = {};
3164 int cmp;
3165 bool ok;
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);
3178 return;
3181 ok = netlogon_creds_client_check(&state->tmp_creds,
3182 &state->rep_auth.cred);
3183 if (!ok) {
3184 status = NT_STATUS_ACCESS_DENIED;
3185 tevent_req_nterror(req, status);
3186 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3187 return;
3190 cmp = memcmp(state->new_owf_password.hash,
3191 zero.hash, sizeof(zero.hash));
3192 if (cmp != 0) {
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);
3197 return;
3200 cmp = memcmp(state->old_owf_password.hash,
3201 zero.hash, sizeof(zero.hash));
3202 if (cmp != 0) {
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);
3207 return;
3211 *state->creds = state->tmp_creds;
3212 status = netlogon_creds_cli_store(state->context,
3213 state->creds);
3214 TALLOC_FREE(state->creds);
3215 if (tevent_req_nterror(req, status)) {
3216 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3217 return;
3220 if (tevent_req_nterror(req, result)) {
3221 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3222 return;
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);
3237 NTSTATUS status;
3239 if (tevent_req_is_nterror(req, &status)) {
3240 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3241 tevent_req_received(req);
3242 return status;
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);
3273 if (ev == NULL) {
3274 goto fail;
3276 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3277 if (req == NULL) {
3278 goto fail;
3280 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3281 goto fail;
3283 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3284 mem_ctx,
3285 new_owf_password,
3286 old_owf_password,
3287 trust_info);
3288 fail:
3289 TALLOC_FREE(frame);
3290 return status;
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;
3302 uint32_t flags;
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,
3312 NTSTATUS status);
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);
3326 if (req == NULL) {
3327 return NULL;
3330 state->ev = ev;
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);
3340 state->flags = 0;
3342 dcerpc_binding_handle_auth_info(state->binding_handle,
3343 &state->auth_type,
3344 &state->auth_level);
3346 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3347 state->context);
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,
3354 req);
3356 return req;
3359 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3360 NTSTATUS status)
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) {
3367 return;
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);
3376 return;
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,
3389 struct tevent_req);
3390 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3391 tevent_req_data(req,
3392 struct netlogon_creds_cli_GetForestTrustInformation_state);
3393 NTSTATUS status;
3395 status = netlogon_creds_cli_lock_recv(subreq, state,
3396 &state->creds);
3397 TALLOC_FREE(subreq);
3398 if (tevent_req_nterror(req, status)) {
3399 return;
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:
3406 break;
3407 default:
3408 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3409 return;
3411 } else {
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
3419 * happened.
3421 * This relies on netlogon_creds_cli_check*
3422 * being called before, as first request after
3423 * the DCERPC bind.
3425 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3426 return;
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,
3438 &state->req_auth);
3439 if (tevent_req_nterror(req, status)) {
3440 return;
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,
3448 &state->req_auth,
3449 &state->rep_auth,
3450 state->flags,
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);
3455 return;
3458 tevent_req_set_callback(subreq,
3459 netlogon_creds_cli_GetForestTrustInformation_done,
3460 req);
3463 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3465 struct tevent_req *req =
3466 tevent_req_callback_data(subreq,
3467 struct tevent_req);
3468 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3469 tevent_req_data(req,
3470 struct netlogon_creds_cli_GetForestTrustInformation_state);
3471 NTSTATUS status;
3472 NTSTATUS result;
3473 bool ok;
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);
3486 return;
3489 ok = netlogon_creds_client_check(&state->tmp_creds,
3490 &state->rep_auth.cred);
3491 if (!ok) {
3492 status = NT_STATUS_ACCESS_DENIED;
3493 tevent_req_nterror(req, status);
3494 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3495 return;
3498 *state->creds = state->tmp_creds;
3499 status = netlogon_creds_cli_store(state->context,
3500 state->creds);
3501 TALLOC_FREE(state->creds);
3503 if (tevent_req_nterror(req, status)) {
3504 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3505 return;
3508 if (tevent_req_nterror(req, result)) {
3509 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3510 return;
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);
3523 NTSTATUS status;
3525 if (tevent_req_is_nterror(req, &status)) {
3526 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3527 tevent_req_received(req);
3528 return status;
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);
3549 if (ev == NULL) {
3550 goto fail;
3552 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3553 if (req == NULL) {
3554 goto fail;
3556 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3557 goto fail;
3559 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3560 mem_ctx,
3561 forest_trust_info);
3562 fail:
3563 TALLOC_FREE(frame);
3564 return status;
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;
3575 DATA_BLOB opaque;
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,
3584 NTSTATUS status);
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);
3600 if (req == NULL) {
3601 return NULL;
3604 state->ev = ev;
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,
3623 &state->auth_type,
3624 &state->auth_level);
3626 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3627 state->context);
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,
3634 req);
3636 return req;
3639 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3640 NTSTATUS status)
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) {
3647 return;
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);
3656 return;
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,
3669 struct tevent_req);
3670 struct netlogon_creds_cli_SendToSam_state *state =
3671 tevent_req_data(req,
3672 struct netlogon_creds_cli_SendToSam_state);
3673 NTSTATUS status;
3675 status = netlogon_creds_cli_lock_recv(subreq, state,
3676 &state->creds);
3677 TALLOC_FREE(subreq);
3678 if (tevent_req_nterror(req, status)) {
3679 return;
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:
3686 break;
3687 default:
3688 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3689 return;
3691 } else {
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
3699 * happened.
3701 * This relies on netlogon_creds_cli_check*
3702 * being called before, as first request after
3703 * the DCERPC bind.
3705 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3706 return;
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,
3718 &state->req_auth);
3719 if (tevent_req_nterror(req, status)) {
3720 return;
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,
3726 state->opaque.data,
3727 state->opaque.length);
3728 if (tevent_req_nterror(req, status)) {
3729 netlogon_creds_cli_SendToSam_cleanup(req, status);
3730 return;
3732 } else {
3733 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3734 state->opaque.data,
3735 state->opaque.length);
3736 if (tevent_req_nterror(req, status)) {
3737 netlogon_creds_cli_SendToSam_cleanup(req, status);
3738 return;
3742 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3743 state->binding_handle,
3744 state->srv_name_slash,
3745 state->tmp_creds.computer_name,
3746 &state->req_auth,
3747 &state->rep_auth,
3748 state->opaque.data,
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);
3753 return;
3756 tevent_req_set_callback(subreq,
3757 netlogon_creds_cli_SendToSam_done,
3758 req);
3761 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3763 struct tevent_req *req =
3764 tevent_req_callback_data(subreq,
3765 struct tevent_req);
3766 struct netlogon_creds_cli_SendToSam_state *state =
3767 tevent_req_data(req,
3768 struct netlogon_creds_cli_SendToSam_state);
3769 NTSTATUS status;
3770 NTSTATUS result;
3771 bool ok;
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);
3777 return;
3780 ok = netlogon_creds_client_check(&state->tmp_creds,
3781 &state->rep_auth.cred);
3782 if (!ok) {
3783 status = NT_STATUS_ACCESS_DENIED;
3784 tevent_req_nterror(req, status);
3785 netlogon_creds_cli_SendToSam_cleanup(req, status);
3786 return;
3789 *state->creds = state->tmp_creds;
3790 status = netlogon_creds_cli_store(state->context,
3791 state->creds);
3792 TALLOC_FREE(state->creds);
3794 if (tevent_req_nterror(req, status)) {
3795 netlogon_creds_cli_SendToSam_cleanup(req, status);
3796 return;
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);
3805 return;
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);
3821 if (ev == NULL) {
3822 goto fail;
3824 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3825 if (req == NULL) {
3826 goto fail;
3828 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3829 goto fail;
3832 /* Ignore the result */
3833 fail:
3834 TALLOC_FREE(frame);
3835 return status;
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;
3847 uint32_t 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,
3858 NTSTATUS status);
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,
3865 uint32_t level,
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);
3874 if (req == NULL) {
3875 return NULL;
3878 state->ev = ev;
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,
3896 &state->auth_type,
3897 &state->auth_level);
3899 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3900 state->context);
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,
3907 req);
3909 return req;
3912 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3913 NTSTATUS status)
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) {
3920 return;
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);
3929 return;
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,
3941 struct tevent_req);
3942 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
3943 tevent_req_data(req,
3944 struct netlogon_creds_cli_LogonGetDomainInfo_state);
3945 NTSTATUS status;
3947 status = netlogon_creds_cli_lock_recv(subreq, state,
3948 &state->creds);
3949 TALLOC_FREE(subreq);
3950 if (tevent_req_nterror(req, status)) {
3951 return;
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:
3958 break;
3959 default:
3960 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3961 return;
3963 } else {
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
3971 * happened.
3973 * This relies on netlogon_creds_cli_check*
3974 * being called before, as first request after
3975 * the DCERPC bind.
3977 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3978 return;
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,
3990 &state->req_auth);
3991 if (tevent_req_nterror(req, status)) {
3992 return;
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,
4000 &state->req_auth,
4001 &state->rep_auth,
4002 state->level,
4003 state->query,
4004 state->info);
4005 if (tevent_req_nomem(subreq, req)) {
4006 status = NT_STATUS_NO_MEMORY;
4007 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4008 return;
4011 tevent_req_set_callback(subreq,
4012 netlogon_creds_cli_LogonGetDomainInfo_done,
4013 req);
4016 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4018 struct tevent_req *req =
4019 tevent_req_callback_data(subreq,
4020 struct tevent_req);
4021 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4022 tevent_req_data(req,
4023 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4024 NTSTATUS status;
4025 NTSTATUS result;
4026 bool ok;
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);
4039 return;
4042 ok = netlogon_creds_client_check(&state->tmp_creds,
4043 &state->rep_auth.cred);
4044 if (!ok) {
4045 status = NT_STATUS_ACCESS_DENIED;
4046 tevent_req_nterror(req, status);
4047 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4048 return;
4051 if (tevent_req_nterror(req, result)) {
4052 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4053 return;
4056 *state->creds = state->tmp_creds;
4057 status = netlogon_creds_cli_store(state->context,
4058 state->creds);
4059 if (tevent_req_nterror(req, status)) {
4060 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4061 return;
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);
4074 NTSTATUS status;
4076 if (tevent_req_is_nterror(req, &status)) {
4077 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4078 tevent_req_received(req);
4079 return status;
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,
4092 uint32_t level,
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);
4102 if (ev == NULL) {
4103 goto fail;
4105 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4106 level, query);
4107 if (req == NULL) {
4108 goto fail;
4110 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4111 goto fail;
4113 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4114 mem_ctx,
4115 info);
4116 fail:
4117 TALLOC_FREE(frame);
4118 return status;