ctdb-scripts: Improve update and listing code
[samba4-gss.git] / libcli / auth / netlogon_creds_cli.c
blob2ac5eefc6e7b8690cb2e2cf1138e6b75be80bbe6
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"
42 #include "lib/param/loadparm.h"
44 struct netlogon_creds_cli_locked_state;
46 struct netlogon_creds_cli_context {
47 struct {
48 const char *computer;
49 const char *account;
50 uint32_t proposed_flags;
51 uint32_t required_flags;
52 enum netr_SchannelType type;
53 enum dcerpc_AuthLevel auth_level;
54 } client;
56 struct {
57 const char *computer;
58 const char *netbios_domain;
59 const char *dns_domain;
60 uint32_t cached_flags;
61 bool try_validation6;
62 bool try_logon_ex;
63 bool try_logon_with;
64 } server;
66 struct {
67 const char *key_name;
68 TDB_DATA key_data;
69 struct db_context *ctx;
70 struct g_lock_ctx *g_ctx;
71 struct netlogon_creds_cli_locked_state *locked_state;
72 enum netlogon_creds_cli_lck_type lock;
73 } db;
76 struct netlogon_creds_cli_locked_state {
77 struct netlogon_creds_cli_context *context;
78 bool is_glocked;
79 struct netlogon_creds_CredentialState *creds;
82 static int netlogon_creds_cli_locked_state_destructor(
83 struct netlogon_creds_cli_locked_state *state)
85 struct netlogon_creds_cli_context *context = state->context;
87 if (context == NULL) {
88 return 0;
91 if (context->db.locked_state == state) {
92 context->db.locked_state = NULL;
95 if (state->is_glocked) {
96 g_lock_unlock(context->db.g_ctx,
97 string_term_tdb_data(context->db.key_name));
100 return 0;
103 static NTSTATUS netlogon_creds_cli_context_common(
104 const char *client_computer,
105 const char *client_account,
106 enum netr_SchannelType type,
107 enum dcerpc_AuthLevel auth_level,
108 uint32_t proposed_flags,
109 uint32_t required_flags,
110 const char *server_computer,
111 const char *server_netbios_domain,
112 const char *server_dns_domain,
113 TALLOC_CTX *mem_ctx,
114 struct netlogon_creds_cli_context **_context)
116 struct netlogon_creds_cli_context *context = NULL;
117 char *_key_name = NULL;
118 size_t server_netbios_name_len;
119 char *p = NULL;
121 *_context = NULL;
123 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
124 if (context == NULL) {
125 return NT_STATUS_NO_MEMORY;
128 context->client.computer = talloc_strdup(context, client_computer);
129 if (context->client.computer == NULL) {
130 TALLOC_FREE(context);
131 return NT_STATUS_NO_MEMORY;
134 context->client.account = talloc_strdup(context, client_account);
135 if (context->client.account == NULL) {
136 TALLOC_FREE(context);
137 return NT_STATUS_NO_MEMORY;
140 context->client.proposed_flags = proposed_flags;
141 context->client.required_flags = required_flags;
142 context->client.type = type;
143 context->client.auth_level = auth_level;
145 context->server.computer = talloc_strdup(context, server_computer);
146 if (context->server.computer == NULL) {
147 TALLOC_FREE(context);
148 return NT_STATUS_NO_MEMORY;
151 context->server.netbios_domain = talloc_strdup(context, server_netbios_domain);
152 if (context->server.netbios_domain == NULL) {
153 TALLOC_FREE(context);
154 return NT_STATUS_NO_MEMORY;
157 context->server.dns_domain = talloc_strdup(context, server_dns_domain);
158 if (context->server.dns_domain == NULL) {
159 TALLOC_FREE(context);
160 return NT_STATUS_NO_MEMORY;
164 * TODO:
165 * Force the callers to provide a unique
166 * value for server_computer and use this directly.
168 * For now we have to deal with
169 * "HOSTNAME" vs. "hostname.example.com".
172 p = strchr(server_computer, '.');
173 if (p != NULL) {
174 server_netbios_name_len = p-server_computer;
175 } else {
176 server_netbios_name_len = strlen(server_computer);
179 _key_name = talloc_asprintf(context, "CLI[%s/%s]/SRV[%.*s/%s]",
180 client_computer,
181 client_account,
182 (int)server_netbios_name_len,
183 server_computer,
184 server_netbios_domain);
185 if (_key_name == NULL) {
186 TALLOC_FREE(context);
187 return NT_STATUS_NO_MEMORY;
190 context->db.key_name = talloc_strdup_upper(context, _key_name);
191 TALLOC_FREE(_key_name);
192 if (context->db.key_name == NULL) {
193 TALLOC_FREE(context);
194 return NT_STATUS_NO_MEMORY;
197 context->db.key_data = string_term_tdb_data(context->db.key_name);
199 *_context = context;
200 return NT_STATUS_OK;
203 static struct db_context *netlogon_creds_cli_global_db;
205 NTSTATUS netlogon_creds_cli_set_global_db(struct loadparm_context *lp_ctx,
206 struct db_context **db)
208 netlogon_creds_cli_warn_options(lp_ctx);
210 if (netlogon_creds_cli_global_db != NULL) {
211 return NT_STATUS_INVALID_PARAMETER_MIX;
214 netlogon_creds_cli_global_db = talloc_move(NULL, db);
215 return NT_STATUS_OK;
218 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
220 char *fname;
221 struct db_context *global_db;
222 int hash_size, tdb_flags;
224 netlogon_creds_cli_warn_options(lp_ctx);
226 if (netlogon_creds_cli_global_db != NULL) {
227 return NT_STATUS_OK;
230 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
231 if (fname == NULL) {
232 return NT_STATUS_NO_MEMORY;
235 hash_size = lpcfg_tdb_hash_size(lp_ctx, fname);
236 tdb_flags = lpcfg_tdb_flags(
237 lp_ctx,
238 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH);
240 global_db = dbwrap_local_open(
241 NULL,
242 fname,
243 hash_size,
244 tdb_flags,
245 O_RDWR|O_CREAT,
246 0600,
247 DBWRAP_LOCK_ORDER_2,
248 DBWRAP_FLAG_NONE);
249 if (global_db == NULL) {
250 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
251 fname, strerror(errno)));
252 talloc_free(fname);
253 return NT_STATUS_NO_MEMORY;
255 TALLOC_FREE(fname);
257 netlogon_creds_cli_global_db = global_db;
258 return NT_STATUS_OK;
261 void netlogon_creds_cli_close_global_db(void)
263 TALLOC_FREE(netlogon_creds_cli_global_db);
266 void netlogon_creds_cli_warn_options(struct loadparm_context *lp_ctx)
268 bool global_reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
269 bool global_require_strong_key = lpcfg_require_strong_key(lp_ctx);
270 int global_client_schannel = lpcfg_client_schannel(lp_ctx);
271 bool global_seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
272 int global_kerberos_enctypes = lpcfg_kerberos_encryption_types(lp_ctx);
273 static bool warned_global_reject_md5_servers = false;
274 static bool warned_global_require_strong_key = false;
275 static bool warned_global_client_schannel = false;
276 static bool warned_global_seal_secure_channel = false;
277 static bool warned_global_kerberos_encryption_types = false;
278 static int warned_global_pid = 0;
279 int current_pid = tevent_cached_getpid();
281 if (warned_global_pid != current_pid) {
282 warned_global_reject_md5_servers = false;
283 warned_global_require_strong_key = false;
284 warned_global_client_schannel = false;
285 warned_global_seal_secure_channel = false;
286 warned_global_kerberos_encryption_types = false;
287 warned_global_pid = current_pid;
290 if (!global_reject_md5_servers && !warned_global_reject_md5_servers) {
292 * We want admins to notice their misconfiguration!
294 DBG_ERR("CVE-2022-38023 (and others): "
295 "Please configure 'reject md5 servers = yes' (the default), "
296 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
297 warned_global_reject_md5_servers = true;
300 if (!global_require_strong_key && !warned_global_require_strong_key) {
302 * We want admins to notice their misconfiguration!
304 DBG_ERR("CVE-2022-38023 (and others): "
305 "Please configure 'require strong key = yes' (the default), "
306 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
307 warned_global_require_strong_key = true;
310 if (global_client_schannel != true && !warned_global_client_schannel) {
312 * We want admins to notice their misconfiguration!
314 DBG_ERR("CVE-2022-38023 (and others): "
315 "Please configure 'client schannel = yes' (the default), "
316 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
317 warned_global_client_schannel = true;
320 if (!global_seal_secure_channel && !warned_global_seal_secure_channel) {
322 * We want admins to notice their misconfiguration!
324 DBG_ERR("CVE-2022-38023 (and others): "
325 "Please configure 'winbind sealed pipes = yes' (the default), "
326 "See https://bugzilla.samba.org/show_bug.cgi?id=15240\n");
327 warned_global_seal_secure_channel = true;
330 if (global_kerberos_enctypes == KERBEROS_ETYPES_LEGACY &&
331 !warned_global_kerberos_encryption_types)
334 * We want admins to notice their misconfiguration!
336 DBG_ERR("CVE-2022-37966: "
337 "Please void 'kerberos encryption types = legacy', "
338 "See https://bugzilla.samba.org/show_bug.cgi?id=15237\n");
339 warned_global_kerberos_encryption_types = true;
343 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
344 struct messaging_context *msg_ctx,
345 const char *client_account,
346 enum netr_SchannelType type,
347 const char *server_computer,
348 const char *server_netbios_domain,
349 const char *server_dns_domain,
350 TALLOC_CTX *mem_ctx,
351 struct netlogon_creds_cli_context **_context)
353 TALLOC_CTX *frame = talloc_stackframe();
354 NTSTATUS status;
355 struct netlogon_creds_cli_context *context = NULL;
356 const char *client_computer;
357 uint32_t proposed_flags;
358 uint32_t required_flags = 0;
359 bool reject_md5_servers = true;
360 bool require_strong_key = true;
361 int require_sign_or_seal = true;
362 bool seal_secure_channel = true;
363 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
364 bool neutralize_nt4_emulation = false;
366 *_context = NULL;
368 if (msg_ctx == NULL) {
369 TALLOC_FREE(frame);
370 return NT_STATUS_INVALID_PARAMETER_MIX;
373 client_computer = lpcfg_netbios_name(lp_ctx);
374 if (strlen(client_computer) > 15) {
375 TALLOC_FREE(frame);
376 return NT_STATUS_INVALID_PARAMETER_MIX;
380 * allow overwrite per domain
381 * reject md5 servers:<netbios_domain>
383 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
384 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
385 "reject md5 servers",
386 server_netbios_domain,
387 reject_md5_servers);
390 * allow overwrite per domain
391 * require strong key:<netbios_domain>
393 require_strong_key = lpcfg_require_strong_key(lp_ctx);
394 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
395 "require strong key",
396 server_netbios_domain,
397 require_strong_key);
400 * allow overwrite per domain
401 * client schannel:<netbios_domain>
403 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
404 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
405 "client schannel",
406 server_netbios_domain,
407 require_sign_or_seal);
410 * allow overwrite per domain
411 * winbind sealed pipes:<netbios_domain>
413 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
414 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
415 "winbind sealed pipes",
416 server_netbios_domain,
417 seal_secure_channel);
420 * allow overwrite per domain
421 * neutralize nt4 emulation:<netbios_domain>
423 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
424 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
425 "neutralize nt4 emulation",
426 server_netbios_domain,
427 neutralize_nt4_emulation);
429 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
430 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
432 switch (type) {
433 case SEC_CHAN_WKSTA:
434 if (lpcfg_security(lp_ctx) == SEC_ADS) {
436 * AD domains should be secure
438 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
439 require_sign_or_seal = true;
440 require_strong_key = true;
442 break;
444 case SEC_CHAN_DOMAIN:
445 break;
447 case SEC_CHAN_DNS_DOMAIN:
449 * AD domains should be secure
451 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
452 require_sign_or_seal = true;
453 require_strong_key = true;
454 neutralize_nt4_emulation = true;
455 break;
457 case SEC_CHAN_BDC:
458 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
459 require_sign_or_seal = true;
460 require_strong_key = true;
461 break;
463 case SEC_CHAN_RODC:
464 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
465 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
466 require_sign_or_seal = true;
467 require_strong_key = true;
468 neutralize_nt4_emulation = true;
469 break;
471 default:
472 TALLOC_FREE(frame);
473 return NT_STATUS_INVALID_PARAMETER;
476 if (neutralize_nt4_emulation) {
477 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
480 if (require_sign_or_seal) {
481 required_flags |= NETLOGON_NEG_ARCFOUR;
482 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
483 } else {
484 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
487 if (reject_md5_servers) {
488 required_flags |= NETLOGON_NEG_ARCFOUR;
489 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
490 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
491 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
494 if (require_strong_key) {
495 required_flags |= NETLOGON_NEG_ARCFOUR;
496 required_flags |= NETLOGON_NEG_STRONG_KEYS;
497 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
501 * If weak crypto is disabled, do not announce that we support RC4 and
502 * require AES.
504 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
505 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
508 proposed_flags |= required_flags;
510 if (required_flags & NETLOGON_NEG_SUPPORTS_AES) {
511 required_flags &= ~NETLOGON_NEG_ARCFOUR;
512 required_flags &= ~NETLOGON_NEG_STRONG_KEYS;
515 if (seal_secure_channel) {
516 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
517 } else {
518 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
521 if (server_dns_domain == NULL) {
522 server_dns_domain = "";
525 status = netlogon_creds_cli_context_common(client_computer,
526 client_account,
527 type,
528 auth_level,
529 proposed_flags,
530 required_flags,
531 server_computer,
532 server_netbios_domain,
533 server_dns_domain,
534 mem_ctx,
535 &context);
536 if (!NT_STATUS_IS_OK(status)) {
537 TALLOC_FREE(frame);
538 return status;
541 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
542 if (context->db.g_ctx == NULL) {
543 TALLOC_FREE(context);
544 TALLOC_FREE(frame);
545 return NT_STATUS_NO_MEMORY;
548 status = netlogon_creds_cli_open_global_db(lp_ctx);
549 if (!NT_STATUS_IS_OK(status)) {
550 TALLOC_FREE(context);
551 TALLOC_FREE(frame);
552 return NT_STATUS_NO_MEMORY;
555 context->db.ctx = netlogon_creds_cli_global_db;
556 *_context = context;
557 TALLOC_FREE(frame);
558 return NT_STATUS_OK;
561 NTSTATUS netlogon_creds_bind_cli_credentials(
562 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
563 struct cli_credentials **pcli_creds)
565 struct cli_credentials *cli_creds;
566 struct netlogon_creds_CredentialState *ncreds;
567 NTSTATUS status;
569 cli_creds = cli_credentials_init(mem_ctx);
570 if (cli_creds == NULL) {
571 return NT_STATUS_NO_MEMORY;
573 cli_credentials_set_secure_channel_type(cli_creds,
574 context->client.type);
575 cli_credentials_set_username(cli_creds, context->client.account,
576 CRED_SPECIFIED);
577 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
578 CRED_SPECIFIED);
579 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
580 CRED_SPECIFIED);
582 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
583 if (!NT_STATUS_IS_OK(status)) {
584 TALLOC_FREE(cli_creds);
585 return status;
587 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
589 *pcli_creds = cli_creds;
590 return NT_STATUS_OK;
593 char *netlogon_creds_cli_debug_string(
594 const struct netlogon_creds_cli_context *context,
595 TALLOC_CTX *mem_ctx)
597 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
598 context->db.key_name);
601 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
602 struct netlogon_creds_cli_context *context)
604 return context->client.auth_level;
607 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
608 uint32_t proposed_flags,
609 uint32_t required_flags)
611 uint32_t req_flags = required_flags;
612 uint32_t tmp_flags;
614 req_flags = required_flags;
615 if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
616 (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
618 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
621 tmp_flags = negotiated_flags;
622 tmp_flags &= req_flags;
623 if (tmp_flags != req_flags) {
624 return true;
627 return false;
630 struct netlogon_creds_cli_fetch_state {
631 TALLOC_CTX *mem_ctx;
632 struct netlogon_creds_CredentialState *creds;
633 uint32_t proposed_flags;
634 uint32_t required_flags;
635 NTSTATUS status;
638 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
639 void *private_data)
641 struct netlogon_creds_cli_fetch_state *state =
642 (struct netlogon_creds_cli_fetch_state *)private_data;
643 enum ndr_err_code ndr_err;
644 DATA_BLOB blob;
645 bool downgraded;
647 state->creds = talloc_zero(state->mem_ctx,
648 struct netlogon_creds_CredentialState);
649 if (state->creds == NULL) {
650 state->status = NT_STATUS_NO_MEMORY;
651 return;
654 blob.data = data.dptr;
655 blob.length = data.dsize;
657 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
658 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
659 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
660 TALLOC_FREE(state->creds);
661 state->status = ndr_map_error2ntstatus(ndr_err);
662 return;
665 if (DEBUGLEVEL >= 10) {
666 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
669 if (state->proposed_flags != state->creds->client_requested_flags) {
670 TALLOC_FREE(state->creds);
671 state->status = NT_STATUS_RESOURCE_REQUIREMENTS_CHANGED;
672 return;
675 downgraded = netlogon_creds_cli_downgraded(
676 state->creds->negotiate_flags,
677 state->proposed_flags,
678 state->required_flags);
679 if (downgraded) {
680 TALLOC_FREE(state->creds);
681 state->status = NT_STATUS_DOWNGRADE_DETECTED;
682 return;
685 state->status = NT_STATUS_OK;
688 static NTSTATUS netlogon_creds_cli_get_internal(
689 struct netlogon_creds_cli_context *context,
690 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
692 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
693 TALLOC_CTX *mem_ctx,
694 struct netlogon_creds_CredentialState **_creds)
696 NTSTATUS status;
697 struct netlogon_creds_CredentialState *creds;
699 *_creds = NULL;
701 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
702 if (!NT_STATUS_IS_OK(status)) {
703 return status;
707 * mark it as invalid for step operations.
709 creds->sequence = 0;
710 creds->seed = (struct netr_Credential) {{0}};
711 creds->client = (struct netr_Credential) {{0}};
712 creds->server = (struct netr_Credential) {{0}};
714 *_creds = creds;
715 return NT_STATUS_OK;
718 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
719 const struct netlogon_creds_CredentialState *creds1)
721 TALLOC_CTX *frame = talloc_stackframe();
722 struct netlogon_creds_CredentialState *creds2;
723 DATA_BLOB blob1;
724 DATA_BLOB blob2;
725 NTSTATUS status;
726 enum ndr_err_code ndr_err;
727 bool equal;
729 status = netlogon_creds_cli_get(context, frame, &creds2);
730 if (!NT_STATUS_IS_OK(status)) {
731 TALLOC_FREE(frame);
732 return false;
735 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
736 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
737 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
738 TALLOC_FREE(frame);
739 return false;
742 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
743 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
745 TALLOC_FREE(frame);
746 return false;
749 equal = data_blob_equal_const_time(&blob1, &blob2);
751 TALLOC_FREE(frame);
753 return equal;
756 static NTSTATUS netlogon_creds_cli_store_internal(
757 struct netlogon_creds_cli_context *context,
758 struct netlogon_creds_CredentialState *creds)
760 TALLOC_CTX *frame = talloc_stackframe();
761 NTSTATUS status;
762 enum ndr_err_code ndr_err;
763 DATA_BLOB blob;
764 TDB_DATA data;
766 if (DEBUGLEVEL >= 10) {
767 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
770 ndr_err = ndr_push_struct_blob(&blob, frame, creds,
771 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
772 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
773 status = ndr_map_error2ntstatus(ndr_err);
774 TALLOC_FREE(frame);
775 return status;
778 data.dptr = blob.data;
779 data.dsize = blob.length;
781 status = dbwrap_store(context->db.ctx,
782 context->db.key_data,
783 data, TDB_REPLACE);
784 if (!NT_STATUS_IS_OK(status)) {
785 TALLOC_FREE(frame);
786 return status;
789 TALLOC_FREE(frame);
790 return NT_STATUS_OK;
793 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
794 struct netlogon_creds_CredentialState *creds)
796 NTSTATUS status;
798 if (context->db.locked_state == NULL) {
800 * this was not the result of netlogon_creds_cli_lock*()
802 return NT_STATUS_INVALID_PAGE_PROTECTION;
805 if (context->db.locked_state->creds != creds) {
807 * this was not the result of netlogon_creds_cli_lock*()
809 return NT_STATUS_INVALID_PAGE_PROTECTION;
812 status = netlogon_creds_cli_store_internal(context, creds);
813 return status;
816 static NTSTATUS netlogon_creds_cli_delete_internal(
817 struct netlogon_creds_cli_context *context)
819 NTSTATUS status;
820 status = dbwrap_delete(context->db.ctx, context->db.key_data);
821 return status;
824 NTSTATUS netlogon_creds_cli_delete_lck(
825 struct netlogon_creds_cli_context *context)
827 NTSTATUS status;
829 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
830 return NT_STATUS_NOT_LOCKED;
833 status = netlogon_creds_cli_delete_internal(context);
834 return status;
837 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
838 struct netlogon_creds_CredentialState *creds)
840 NTSTATUS status;
842 if (context->db.locked_state == NULL) {
844 * this was not the result of netlogon_creds_cli_lock*()
846 return NT_STATUS_INVALID_PAGE_PROTECTION;
849 if (context->db.locked_state->creds != creds) {
851 * this was not the result of netlogon_creds_cli_lock*()
853 return NT_STATUS_INVALID_PAGE_PROTECTION;
856 status = netlogon_creds_cli_delete_internal(context);
857 return status;
860 struct netlogon_creds_cli_lock_state {
861 struct netlogon_creds_cli_locked_state *locked_state;
862 struct netlogon_creds_CredentialState *creds;
865 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
867 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
868 struct tevent_context *ev,
869 struct netlogon_creds_cli_context *context)
871 struct tevent_req *req;
872 struct netlogon_creds_cli_lock_state *state;
873 struct netlogon_creds_cli_locked_state *locked_state;
874 struct tevent_req *subreq;
876 req = tevent_req_create(mem_ctx, &state,
877 struct netlogon_creds_cli_lock_state);
878 if (req == NULL) {
879 return NULL;
882 if (context->db.locked_state != NULL) {
883 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
884 return tevent_req_post(req, ev);
887 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
888 if (tevent_req_nomem(locked_state, req)) {
889 return tevent_req_post(req, ev);
891 talloc_set_destructor(locked_state,
892 netlogon_creds_cli_locked_state_destructor);
893 locked_state->context = context;
895 context->db.locked_state = locked_state;
896 state->locked_state = locked_state;
898 if (context->db.g_ctx == NULL) {
899 NTSTATUS status;
901 status = netlogon_creds_cli_get_internal(
902 context, state, &state->creds);
903 if (tevent_req_nterror(req, status)) {
904 return tevent_req_post(req, ev);
907 return req;
910 subreq = g_lock_lock_send(state, ev,
911 context->db.g_ctx,
912 string_term_tdb_data(context->db.key_name),
913 G_LOCK_WRITE,
914 NULL, NULL);
915 if (tevent_req_nomem(subreq, req)) {
916 return tevent_req_post(req, ev);
918 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
920 return req;
923 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
925 struct tevent_req *req =
926 tevent_req_callback_data(subreq,
927 struct tevent_req);
928 struct netlogon_creds_cli_lock_state *state =
929 tevent_req_data(req,
930 struct netlogon_creds_cli_lock_state);
931 NTSTATUS status;
933 status = g_lock_lock_recv(subreq);
934 TALLOC_FREE(subreq);
935 if (tevent_req_nterror(req, status)) {
936 return;
938 state->locked_state->is_glocked = true;
940 status = netlogon_creds_cli_get_internal(state->locked_state->context,
941 state, &state->creds);
942 if (tevent_req_nterror(req, status)) {
943 return;
945 tevent_req_done(req);
948 static NTSTATUS netlogon_creds_cli_get_internal(
949 struct netlogon_creds_cli_context *context,
950 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
952 struct netlogon_creds_cli_fetch_state fstate = {
953 .status = NT_STATUS_INTERNAL_ERROR,
954 .proposed_flags = context->client.proposed_flags,
955 .required_flags = context->client.required_flags,
957 NTSTATUS status;
959 fstate.mem_ctx = mem_ctx;
960 status = dbwrap_parse_record(context->db.ctx,
961 context->db.key_data,
962 netlogon_creds_cli_fetch_parser,
963 &fstate);
964 if (!NT_STATUS_IS_OK(status)) {
965 return status;
967 if (!NT_STATUS_IS_OK(fstate.status)) {
968 return fstate.status;
971 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
972 *pcreds = fstate.creds;
973 return NT_STATUS_OK;
977 * It is really important to try SamLogonEx here,
978 * because multiple processes can talk to the same
979 * domain controller, without using the credential
980 * chain.
982 * With a normal SamLogon call, we must keep the
983 * credentials chain updated and intact between all
984 * users of the machine account (which would imply
985 * cross-node communication for every NTLM logon).
987 * The credentials chain is not per NETLOGON pipe
988 * connection, but globally on the server/client pair
989 * by computer name.
991 * It's also important to use NetlogonValidationSamInfo4 (6),
992 * because it relies on the rpc transport encryption
993 * and avoids using the global netlogon schannel
994 * session key to en/decrypt secret information
995 * like the user_session_key for network logons.
997 * [MS-APDS] 3.1.5.2 NTLM Network Logon
998 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
999 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1000 * are the indication that the server supports
1001 * NetlogonValidationSamInfo4 (6). And it must only
1002 * be used if "SealSecureChannel" is used.
1004 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
1005 * check is done in netlogon_creds_cli_LogonSamLogon*().
1008 context->server.cached_flags = fstate.creds->negotiate_flags;
1009 context->server.try_validation6 = true;
1010 context->server.try_logon_ex = true;
1011 context->server.try_logon_with = true;
1013 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1014 context->server.try_validation6 = false;
1015 context->server.try_logon_ex = false;
1017 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1018 context->server.try_validation6 = false;
1021 *pcreds = fstate.creds;
1022 return NT_STATUS_OK;
1025 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
1026 TALLOC_CTX *mem_ctx,
1027 struct netlogon_creds_CredentialState **creds)
1029 struct netlogon_creds_cli_lock_state *state =
1030 tevent_req_data(req,
1031 struct netlogon_creds_cli_lock_state);
1032 NTSTATUS status;
1034 if (tevent_req_is_nterror(req, &status)) {
1035 tevent_req_received(req);
1036 return status;
1039 talloc_steal(state->creds, state->locked_state);
1040 state->locked_state->creds = state->creds;
1041 *creds = talloc_move(mem_ctx, &state->creds);
1042 tevent_req_received(req);
1043 return NT_STATUS_OK;
1046 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
1047 TALLOC_CTX *mem_ctx,
1048 struct netlogon_creds_CredentialState **creds)
1050 TALLOC_CTX *frame = talloc_stackframe();
1051 struct tevent_context *ev;
1052 struct tevent_req *req;
1053 NTSTATUS status = NT_STATUS_NO_MEMORY;
1055 ev = samba_tevent_context_init(frame);
1056 if (ev == NULL) {
1057 goto fail;
1059 req = netlogon_creds_cli_lock_send(frame, ev, context);
1060 if (req == NULL) {
1061 goto fail;
1063 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1064 goto fail;
1066 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
1067 fail:
1068 TALLOC_FREE(frame);
1069 return status;
1072 struct netlogon_creds_cli_lck {
1073 struct netlogon_creds_cli_context *context;
1076 struct netlogon_creds_cli_lck_state {
1077 struct netlogon_creds_cli_lck *lck;
1078 enum netlogon_creds_cli_lck_type type;
1081 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
1082 static int netlogon_creds_cli_lck_destructor(
1083 struct netlogon_creds_cli_lck *lck);
1085 struct tevent_req *netlogon_creds_cli_lck_send(
1086 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1087 struct netlogon_creds_cli_context *context,
1088 enum netlogon_creds_cli_lck_type type)
1090 struct tevent_req *req, *subreq;
1091 struct netlogon_creds_cli_lck_state *state;
1092 enum g_lock_type gtype;
1094 req = tevent_req_create(mem_ctx, &state,
1095 struct netlogon_creds_cli_lck_state);
1096 if (req == NULL) {
1097 return NULL;
1100 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
1101 DBG_DEBUG("context already locked\n");
1102 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
1103 return tevent_req_post(req, ev);
1106 switch (type) {
1107 case NETLOGON_CREDS_CLI_LCK_SHARED:
1108 gtype = G_LOCK_READ;
1109 break;
1110 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
1111 gtype = G_LOCK_WRITE;
1112 break;
1113 default:
1114 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1115 return tevent_req_post(req, ev);
1118 state->lck = talloc(state, struct netlogon_creds_cli_lck);
1119 if (tevent_req_nomem(state->lck, req)) {
1120 return tevent_req_post(req, ev);
1122 state->lck->context = context;
1123 state->type = type;
1125 subreq = g_lock_lock_send(state, ev,
1126 context->db.g_ctx,
1127 string_term_tdb_data(context->db.key_name),
1128 gtype,
1129 NULL, NULL);
1130 if (tevent_req_nomem(subreq, req)) {
1131 return tevent_req_post(req, ev);
1133 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1135 return req;
1138 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1140 struct tevent_req *req = tevent_req_callback_data(
1141 subreq, struct tevent_req);
1142 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1143 req, struct netlogon_creds_cli_lck_state);
1144 NTSTATUS status;
1146 status = g_lock_lock_recv(subreq);
1147 TALLOC_FREE(subreq);
1148 if (tevent_req_nterror(req, status)) {
1149 return;
1152 state->lck->context->db.lock = state->type;
1153 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1155 tevent_req_done(req);
1158 static int netlogon_creds_cli_lck_destructor(
1159 struct netlogon_creds_cli_lck *lck)
1161 struct netlogon_creds_cli_context *ctx = lck->context;
1162 NTSTATUS status;
1164 status = g_lock_unlock(ctx->db.g_ctx,
1165 string_term_tdb_data(ctx->db.key_name));
1166 if (!NT_STATUS_IS_OK(status)) {
1167 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1168 smb_panic("g_lock_unlock failed");
1170 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1171 return 0;
1174 NTSTATUS netlogon_creds_cli_lck_recv(
1175 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1176 struct netlogon_creds_cli_lck **lck)
1178 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1179 req, struct netlogon_creds_cli_lck_state);
1180 NTSTATUS status;
1182 if (tevent_req_is_nterror(req, &status)) {
1183 return status;
1185 *lck = talloc_move(mem_ctx, &state->lck);
1186 return NT_STATUS_OK;
1189 NTSTATUS netlogon_creds_cli_lck(
1190 struct netlogon_creds_cli_context *context,
1191 enum netlogon_creds_cli_lck_type type,
1192 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1194 TALLOC_CTX *frame = talloc_stackframe();
1195 struct tevent_context *ev;
1196 struct tevent_req *req;
1197 NTSTATUS status = NT_STATUS_NO_MEMORY;
1199 ev = samba_tevent_context_init(frame);
1200 if (ev == NULL) {
1201 goto fail;
1203 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1204 if (req == NULL) {
1205 goto fail;
1207 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1208 goto fail;
1210 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1211 fail:
1212 TALLOC_FREE(frame);
1213 return status;
1216 static NTSTATUS netlogon_creds_cli_check_transport(
1217 enum dcerpc_AuthType auth_type,
1218 enum dcerpc_AuthLevel auth_level,
1219 const struct netlogon_creds_CredentialState *creds,
1220 enum dcerpc_AuthLevel min_auth_level)
1222 if (auth_level < min_auth_level) {
1223 return NT_STATUS_INVALID_PARAMETER_MIX;
1226 if (creds == NULL) {
1227 return NT_STATUS_INVALID_PARAMETER_MIX;
1230 if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1231 switch (auth_level) {
1232 case DCERPC_AUTH_LEVEL_INTEGRITY:
1233 case DCERPC_AUTH_LEVEL_PRIVACY:
1234 return NT_STATUS_OK;
1235 default:
1236 break;
1239 return NT_STATUS_INVALID_PARAMETER_MIX;
1242 if (creds->negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1244 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1245 * it should be used, which means
1246 * we had a chance to verify no downgrade
1247 * happened.
1249 * This relies on netlogon_creds_cli_check*
1250 * being called before, as first request after
1251 * the DCERPC bind.
1253 return NT_STATUS_INVALID_PARAMETER_MIX;
1256 return NT_STATUS_OK;
1259 struct netlogon_creds_cli_auth_state {
1260 struct tevent_context *ev;
1261 struct netlogon_creds_cli_context *context;
1262 struct dcerpc_binding_handle *binding_handle;
1263 enum dcerpc_AuthType auth_type;
1264 enum dcerpc_AuthLevel auth_level;
1265 uint8_t num_nt_hashes;
1266 uint8_t idx_nt_hashes;
1267 const struct samr_Password * const *nt_hashes;
1268 const struct samr_Password *used_nt_hash;
1269 char *srv_name_slash;
1270 uint32_t current_flags;
1271 struct netr_Credential client_challenge;
1272 struct netr_Credential server_challenge;
1273 struct netlogon_creds_CredentialState *creds;
1274 struct netr_Credential client_credential;
1275 struct netr_Credential server_credential;
1276 uint32_t negotiate_flags;
1277 uint32_t rid;
1278 bool try_auth3;
1279 bool try_auth2;
1280 bool require_auth2;
1283 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1285 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1286 struct tevent_context *ev,
1287 struct netlogon_creds_cli_context *context,
1288 struct dcerpc_binding_handle *b,
1289 uint8_t num_nt_hashes,
1290 const struct samr_Password * const *nt_hashes)
1292 struct tevent_req *req;
1293 struct netlogon_creds_cli_auth_state *state;
1294 NTSTATUS status;
1296 req = tevent_req_create(mem_ctx, &state,
1297 struct netlogon_creds_cli_auth_state);
1298 if (req == NULL) {
1299 return NULL;
1302 state->ev = ev;
1303 state->context = context;
1304 state->binding_handle = b;
1305 if (num_nt_hashes < 1) {
1306 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1307 return tevent_req_post(req, ev);
1309 if (num_nt_hashes > 4) {
1310 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1311 return tevent_req_post(req, ev);
1314 state->num_nt_hashes = num_nt_hashes;
1315 state->idx_nt_hashes = 0;
1316 state->nt_hashes = nt_hashes;
1318 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1319 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1320 return tevent_req_post(req, ev);
1323 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1324 context->server.computer);
1325 if (tevent_req_nomem(state->srv_name_slash, req)) {
1326 return tevent_req_post(req, ev);
1329 dcerpc_binding_handle_auth_info(state->binding_handle,
1330 &state->auth_type,
1331 &state->auth_level);
1333 state->try_auth3 = true;
1334 state->try_auth2 = true;
1336 if (context->client.required_flags != 0) {
1337 state->require_auth2 = true;
1340 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1341 state->current_flags = context->client.proposed_flags;
1343 status = dbwrap_purge(state->context->db.ctx,
1344 state->context->db.key_data);
1345 if (tevent_req_nterror(req, status)) {
1346 return tevent_req_post(req, ev);
1349 netlogon_creds_cli_auth_challenge_start(req);
1350 if (!tevent_req_is_in_progress(req)) {
1351 return tevent_req_post(req, ev);
1354 return req;
1357 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1359 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1361 struct netlogon_creds_cli_auth_state *state =
1362 tevent_req_data(req,
1363 struct netlogon_creds_cli_auth_state);
1364 struct tevent_req *subreq;
1366 TALLOC_FREE(state->creds);
1368 netlogon_creds_random_challenge(&state->client_challenge);
1370 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1371 state->binding_handle,
1372 state->srv_name_slash,
1373 state->context->client.computer,
1374 &state->client_challenge,
1375 &state->server_challenge);
1376 if (tevent_req_nomem(subreq, req)) {
1377 return;
1379 tevent_req_set_callback(subreq,
1380 netlogon_creds_cli_auth_challenge_done,
1381 req);
1384 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1386 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1388 struct tevent_req *req =
1389 tevent_req_callback_data(subreq,
1390 struct tevent_req);
1391 struct netlogon_creds_cli_auth_state *state =
1392 tevent_req_data(req,
1393 struct netlogon_creds_cli_auth_state);
1394 NTSTATUS status;
1395 NTSTATUS result;
1397 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1398 TALLOC_FREE(subreq);
1399 if (tevent_req_nterror(req, status)) {
1400 return;
1402 if (tevent_req_nterror(req, result)) {
1403 return;
1406 if (!state->try_auth3 && !state->try_auth2) {
1407 state->current_flags = 0;
1410 /* Calculate the session key and client credentials */
1412 state->creds = netlogon_creds_client_init(state,
1413 state->context->client.account,
1414 state->context->client.computer,
1415 state->context->client.type,
1416 &state->client_challenge,
1417 &state->server_challenge,
1418 state->used_nt_hash,
1419 &state->client_credential,
1420 state->context->client.proposed_flags,
1421 state->current_flags);
1422 if (tevent_req_nomem(state->creds, req)) {
1423 return;
1426 if (state->try_auth3) {
1428 * We always need to send our proposed flags,
1429 * even if state->current_flags we passed to
1430 * netlogon_creds_client_init() is already downgraded,
1432 * An old server will just ignore the bits it doesn't
1433 * know about, but LogonGetCapabilities(level=2) will
1434 * report what we proposed.
1436 state->negotiate_flags = state->context->client.proposed_flags;
1438 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1439 state->binding_handle,
1440 state->srv_name_slash,
1441 state->context->client.account,
1442 state->context->client.type,
1443 state->context->client.computer,
1444 &state->client_credential,
1445 &state->server_credential,
1446 &state->negotiate_flags,
1447 &state->rid);
1448 if (tevent_req_nomem(subreq, req)) {
1449 return;
1451 } else if (state->try_auth2) {
1453 * We always need to send our proposed flags,
1454 * even if state->current_flags we passed to
1455 * netlogon_creds_client_init() is already downgraded,
1457 * An old server will just ignore the bits it doesn't
1458 * know about, but LogonGetCapabilities(level=2) will
1459 * report what we proposed.
1461 state->negotiate_flags = state->context->client.proposed_flags;
1462 state->rid = 0;
1464 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1465 state->binding_handle,
1466 state->srv_name_slash,
1467 state->context->client.account,
1468 state->context->client.type,
1469 state->context->client.computer,
1470 &state->client_credential,
1471 &state->server_credential,
1472 &state->negotiate_flags);
1473 if (tevent_req_nomem(subreq, req)) {
1474 return;
1476 } else {
1477 state->negotiate_flags = 0;
1478 state->rid = 0;
1480 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1481 state->binding_handle,
1482 state->srv_name_slash,
1483 state->context->client.account,
1484 state->context->client.type,
1485 state->context->client.computer,
1486 &state->client_credential,
1487 &state->server_credential);
1488 if (tevent_req_nomem(subreq, req)) {
1489 return;
1492 tevent_req_set_callback(subreq,
1493 netlogon_creds_cli_auth_srvauth_done,
1494 req);
1497 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1499 struct tevent_req *req =
1500 tevent_req_callback_data(subreq,
1501 struct tevent_req);
1502 struct netlogon_creds_cli_auth_state *state =
1503 tevent_req_data(req,
1504 struct netlogon_creds_cli_auth_state);
1505 NTSTATUS status;
1506 NTSTATUS result;
1507 bool downgraded;
1509 if (state->try_auth3) {
1510 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1511 &result);
1512 TALLOC_FREE(subreq);
1513 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1514 state->try_auth3 = false;
1515 netlogon_creds_cli_auth_challenge_start(req);
1516 return;
1518 if (tevent_req_nterror(req, status)) {
1519 return;
1521 } else if (state->try_auth2) {
1522 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1523 &result);
1524 TALLOC_FREE(subreq);
1525 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1526 state->try_auth2 = false;
1527 if (state->require_auth2) {
1528 status = NT_STATUS_DOWNGRADE_DETECTED;
1529 tevent_req_nterror(req, status);
1530 return;
1532 netlogon_creds_cli_auth_challenge_start(req);
1533 return;
1535 if (tevent_req_nterror(req, status)) {
1536 return;
1538 } else {
1539 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1540 &result);
1541 TALLOC_FREE(subreq);
1542 if (tevent_req_nterror(req, status)) {
1543 return;
1547 if (!NT_STATUS_IS_OK(result) &&
1548 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1550 tevent_req_nterror(req, result);
1551 return;
1554 downgraded = netlogon_creds_cli_downgraded(
1555 state->negotiate_flags,
1556 state->context->client.proposed_flags,
1557 state->context->client.required_flags);
1558 if (downgraded) {
1559 if (NT_STATUS_IS_OK(result)) {
1560 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1561 return;
1563 tevent_req_nterror(req, result);
1564 return;
1567 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1568 uint32_t prop_f = state->context->client.proposed_flags;
1569 uint32_t cli_f = state->current_flags;
1570 uint32_t srv_f = state->negotiate_flags;
1571 uint32_t nego_f = cli_f & srv_f;
1573 if (cli_f == prop_f && nego_f != prop_f) {
1575 * lets retry with the negotiated flags
1577 state->current_flags = nego_f;
1578 netlogon_creds_cli_auth_challenge_start(req);
1579 return;
1582 state->idx_nt_hashes += 1;
1583 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1585 * we already retried, giving up...
1587 tevent_req_nterror(req, result);
1588 return;
1592 * lets retry with the old nt hash.
1594 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1595 state->current_flags = state->context->client.proposed_flags;
1596 netlogon_creds_cli_auth_challenge_start(req);
1597 return;
1600 status = netlogon_creds_client_verify(state->creds,
1601 &state->server_credential,
1602 state->auth_type,
1603 state->auth_level);
1604 if (tevent_req_nterror(req, status)) {
1605 return;
1608 if (state->current_flags == state->context->client.proposed_flags) {
1610 * Without a downgrade in the crypto we proposed
1611 * we can adjust the otherwise downgraded flags
1612 * before storing.
1614 state->creds->negotiate_flags &= state->negotiate_flags;
1615 } else if (state->current_flags != state->negotiate_flags) {
1617 * We downgraded our crypto once, we should not
1618 * allow any additional downgrade!
1620 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1621 return;
1624 state->creds->client_sid.sub_auths[0] = state->rid;
1625 status = netlogon_creds_cli_store_internal(state->context,
1626 state->creds);
1627 if (tevent_req_nterror(req, status)) {
1628 return;
1631 tevent_req_done(req);
1634 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1635 uint8_t *idx_nt_hashes)
1637 struct netlogon_creds_cli_auth_state *state =
1638 tevent_req_data(req,
1639 struct netlogon_creds_cli_auth_state);
1640 NTSTATUS status;
1642 *idx_nt_hashes = 0;
1644 if (tevent_req_is_nterror(req, &status)) {
1645 tevent_req_received(req);
1646 return status;
1649 *idx_nt_hashes = state->idx_nt_hashes;
1650 tevent_req_received(req);
1651 return NT_STATUS_OK;
1654 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1655 struct dcerpc_binding_handle *b,
1656 uint8_t num_nt_hashes,
1657 const struct samr_Password * const *nt_hashes,
1658 uint8_t *idx_nt_hashes)
1660 TALLOC_CTX *frame = talloc_stackframe();
1661 struct tevent_context *ev;
1662 struct tevent_req *req;
1663 NTSTATUS status = NT_STATUS_NO_MEMORY;
1665 *idx_nt_hashes = 0;
1667 ev = samba_tevent_context_init(frame);
1668 if (ev == NULL) {
1669 goto fail;
1671 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1672 num_nt_hashes, nt_hashes);
1673 if (req == NULL) {
1674 goto fail;
1676 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1677 goto fail;
1679 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1680 fail:
1681 TALLOC_FREE(frame);
1682 return status;
1685 struct netlogon_creds_cli_check_state {
1686 struct tevent_context *ev;
1687 struct netlogon_creds_cli_context *context;
1688 struct dcerpc_binding_handle *binding_handle;
1689 enum dcerpc_AuthType auth_type;
1690 enum dcerpc_AuthLevel auth_level;
1692 char *srv_name_slash;
1694 union netr_Capabilities caps;
1695 union netr_Capabilities client_caps;
1697 struct netlogon_creds_CredentialState *creds;
1698 struct netr_Authenticator req_auth;
1699 struct netr_Authenticator rep_auth;
1701 union netr_CONTROL_QUERY_INFORMATION ctrl_info;
1704 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1705 NTSTATUS status);
1706 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req *subreq);
1707 static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq);
1709 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1710 struct tevent_context *ev,
1711 struct netlogon_creds_cli_context *context,
1712 struct dcerpc_binding_handle *b)
1714 struct tevent_req *req;
1715 struct netlogon_creds_cli_check_state *state;
1716 struct tevent_req *subreq;
1717 NTSTATUS status;
1719 req = tevent_req_create(mem_ctx, &state,
1720 struct netlogon_creds_cli_check_state);
1721 if (req == NULL) {
1722 return NULL;
1725 state->ev = ev;
1726 state->context = context;
1727 state->binding_handle = b;
1729 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1730 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1731 return tevent_req_post(req, ev);
1734 status = netlogon_creds_cli_get_internal(context, state,
1735 &state->creds);
1736 if (tevent_req_nterror(req, status)) {
1737 return tevent_req_post(req, ev);
1740 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1741 context->server.computer);
1742 if (tevent_req_nomem(state->srv_name_slash, req)) {
1743 return tevent_req_post(req, ev);
1746 dcerpc_binding_handle_auth_info(state->binding_handle,
1747 &state->auth_type,
1748 &state->auth_level);
1750 status = netlogon_creds_cli_check_transport(state->auth_type,
1751 state->auth_level,
1752 state->creds,
1753 DCERPC_AUTH_LEVEL_INTEGRITY);
1754 if (tevent_req_nterror(req, status)) {
1755 return tevent_req_post(req, ev);
1759 * we defer all callbacks in order to cleanup
1760 * the database record.
1762 tevent_req_defer_callback(req, state->ev);
1764 status = netlogon_creds_client_authenticator(state->creds,
1765 &state->req_auth);
1766 if (tevent_req_nterror(req, status)) {
1767 return tevent_req_post(req, ev);
1769 ZERO_STRUCT(state->rep_auth);
1771 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1772 state->binding_handle,
1773 state->srv_name_slash,
1774 state->context->client.computer,
1775 &state->req_auth,
1776 &state->rep_auth,
1778 &state->caps);
1779 if (tevent_req_nomem(subreq, req)) {
1780 return tevent_req_post(req, ev);
1783 tevent_req_set_callback(subreq,
1784 netlogon_creds_cli_check_negotiate_caps,
1785 req);
1787 return req;
1790 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1791 NTSTATUS status)
1793 struct netlogon_creds_cli_check_state *state =
1794 tevent_req_data(req,
1795 struct netlogon_creds_cli_check_state);
1797 if (state->creds == NULL) {
1798 return;
1801 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1802 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1803 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1804 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1805 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1806 TALLOC_FREE(state->creds);
1807 return;
1810 netlogon_creds_cli_delete_lck(state->context);
1811 TALLOC_FREE(state->creds);
1814 static void netlogon_creds_cli_check_control_do(struct tevent_req *req);
1816 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req *subreq)
1818 struct tevent_req *req =
1819 tevent_req_callback_data(subreq,
1820 struct tevent_req);
1821 struct netlogon_creds_cli_check_state *state =
1822 tevent_req_data(req,
1823 struct netlogon_creds_cli_check_state);
1824 NTSTATUS status;
1825 NTSTATUS result;
1827 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1828 &result);
1829 TALLOC_FREE(subreq);
1830 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1832 * Note that the negotiated flags are already checked
1833 * for our required flags after the ServerAuthenticate3/2 call.
1835 uint32_t negotiated = state->creds->negotiate_flags;
1837 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1839 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1840 * already, we expect this to work!
1842 status = NT_STATUS_DOWNGRADE_DETECTED;
1843 tevent_req_nterror(req, status);
1844 netlogon_creds_cli_check_cleanup(req, status);
1845 return;
1848 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1850 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1851 * we expect this to work at least as far as the
1852 * NOT_SUPPORTED error handled below!
1854 * NT 4.0 and Old Samba servers are not
1855 * allowed without "require strong key = no"
1857 status = NT_STATUS_DOWNGRADE_DETECTED;
1858 tevent_req_nterror(req, status);
1859 netlogon_creds_cli_check_cleanup(req, status);
1860 return;
1864 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1865 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1866 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1868 * This is needed against NT 4.0 and old Samba servers.
1870 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1871 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1872 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1873 * with the next request as the sequence number processing
1874 * gets out of sync.
1876 * So we'll do a LogonControl message to check that...
1878 netlogon_creds_cli_check_control_do(req);
1879 return;
1881 if (tevent_req_nterror(req, status)) {
1882 netlogon_creds_cli_check_cleanup(req, status);
1883 return;
1886 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1888 * Note that the negotiated flags are already checked
1889 * for our required flags after the ServerAuthenticate3/2 call.
1891 uint32_t negotiated = state->creds->negotiate_flags;
1893 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1895 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1896 * already, we expect this to work!
1898 status = NT_STATUS_DOWNGRADE_DETECTED;
1899 tevent_req_nterror(req, status);
1900 netlogon_creds_cli_check_cleanup(req, status);
1901 return;
1905 * This is ok, the server does not support
1906 * NETLOGON_NEG_SUPPORTS_AES.
1908 * netr_LogonGetCapabilities() was
1909 * netr_LogonDummyRoutine1() before
1910 * NETLOGON_NEG_SUPPORTS_AES was invented.
1912 netlogon_creds_cli_check_cleanup(req, result);
1913 tevent_req_done(req);
1914 return;
1917 status = netlogon_creds_client_verify(state->creds,
1918 &state->rep_auth.cred,
1919 state->auth_type,
1920 state->auth_level);
1921 if (tevent_req_nterror(req, status)) {
1922 netlogon_creds_cli_check_cleanup(req, status);
1923 return;
1926 if (tevent_req_nterror(req, result)) {
1927 netlogon_creds_cli_check_cleanup(req, result);
1928 return;
1931 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1932 status = NT_STATUS_DOWNGRADE_DETECTED;
1933 tevent_req_nterror(req, status);
1934 netlogon_creds_cli_check_cleanup(req, status);
1935 return;
1939 * This is the key check that makes this check secure. If we
1940 * get OK here (rather than NOT_SUPPORTED), then the server
1941 * did support AES. If the server only proposed STRONG_KEYS
1942 * and not AES, then it should have failed with
1943 * NOT_IMPLEMENTED. We always send AES as a client, so the
1944 * server should always have returned it.
1946 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1947 status = NT_STATUS_DOWNGRADE_DETECTED;
1948 tevent_req_nterror(req, status);
1949 netlogon_creds_cli_check_cleanup(req, status);
1950 return;
1953 status = netlogon_creds_cli_store_internal(state->context,
1954 state->creds);
1955 if (tevent_req_nterror(req, status)) {
1956 return;
1960 * Now try to verify our client proposed flags
1961 * arrived at the server, using query_level = 2
1964 status = netlogon_creds_client_authenticator(state->creds,
1965 &state->req_auth);
1966 if (tevent_req_nterror(req, status)) {
1967 return;
1969 ZERO_STRUCT(state->rep_auth);
1971 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1972 state->binding_handle,
1973 state->srv_name_slash,
1974 state->context->client.computer,
1975 &state->req_auth,
1976 &state->rep_auth,
1978 &state->client_caps);
1979 if (tevent_req_nomem(subreq, req)) {
1980 return;
1983 tevent_req_set_callback(subreq,
1984 netlogon_creds_cli_check_client_caps,
1985 req);
1986 return;
1989 static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq)
1991 struct tevent_req *req =
1992 tevent_req_callback_data(subreq,
1993 struct tevent_req);
1994 struct netlogon_creds_cli_check_state *state =
1995 tevent_req_data(req,
1996 struct netlogon_creds_cli_check_state);
1997 uint32_t requested_flags;
1998 NTSTATUS status;
1999 NTSTATUS result;
2001 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
2002 &result);
2003 TALLOC_FREE(subreq);
2004 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_BAD_STUB_DATA)) {
2006 * unpatched Samba server, see
2007 * https://bugzilla.samba.org/show_bug.cgi?id=15418
2009 status = NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE;
2011 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
2013 * Here we know the negotiated flags were already
2014 * verified with query_level=1, which means
2015 * the server supported NETLOGON_NEG_SUPPORTS_AES
2016 * and also NETLOGON_NEG_AUTHENTICATED_RPC
2018 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
2019 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
2020 * we should detect a faked
2021 * NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
2022 * with the next request as the sequence number processing
2023 * gets out of sync.
2025 * So we'll do a LogonControl message to check that...
2027 netlogon_creds_cli_check_control_do(req);
2028 return;
2030 if (tevent_req_nterror(req, status)) {
2031 netlogon_creds_cli_check_cleanup(req, status);
2032 return;
2035 status = netlogon_creds_client_verify(state->creds,
2036 &state->rep_auth.cred,
2037 state->auth_type,
2038 state->auth_level);
2039 if (tevent_req_nterror(req, status)) {
2040 netlogon_creds_cli_check_cleanup(req, status);
2041 return;
2043 if (tevent_req_nterror(req, result)) {
2044 netlogon_creds_cli_check_cleanup(req, result);
2045 return;
2048 requested_flags = state->creds->client_requested_flags;
2050 if (state->client_caps.requested_flags != requested_flags) {
2051 status = NT_STATUS_DOWNGRADE_DETECTED;
2052 tevent_req_nterror(req, status);
2053 netlogon_creds_cli_check_cleanup(req, status);
2054 return;
2057 status = netlogon_creds_cli_store_internal(state->context,
2058 state->creds);
2059 if (tevent_req_nterror(req, status)) {
2060 return;
2063 tevent_req_done(req);
2066 static void netlogon_creds_cli_check_control_done(struct tevent_req *subreq);
2068 static void netlogon_creds_cli_check_control_do(struct tevent_req *req)
2070 struct netlogon_creds_cli_check_state *state =
2071 tevent_req_data(req,
2072 struct netlogon_creds_cli_check_state);
2073 struct tevent_req *subreq = NULL;
2076 * In case we got a downgrade based on a FAULT
2077 * we use a LogonControl that is supposed to
2078 * return WERR_NOT_SUPPORTED (without a DCERPC FAULT)
2079 * to verify that the connection is still ok and didn't
2080 * get out of sync.
2082 subreq = dcerpc_netr_LogonControl_send(state,
2083 state->ev,
2084 state->binding_handle,
2085 state->srv_name_slash,
2086 NETLOGON_CONTROL_QUERY,
2088 &state->ctrl_info);
2089 if (tevent_req_nomem(subreq, req)) {
2090 return;
2093 tevent_req_set_callback(subreq,
2094 netlogon_creds_cli_check_control_done,
2095 req);
2096 return;
2099 static void netlogon_creds_cli_check_control_done(struct tevent_req *subreq)
2101 struct tevent_req *req =
2102 tevent_req_callback_data(subreq,
2103 struct tevent_req);
2104 struct netlogon_creds_cli_check_state *state =
2105 tevent_req_data(req,
2106 struct netlogon_creds_cli_check_state);
2107 NTSTATUS status;
2108 WERROR result;
2110 status = dcerpc_netr_LogonControl_recv(subreq, state, &result);
2111 TALLOC_FREE(subreq);
2112 if (tevent_req_nterror(req, status)) {
2114 * We want to delete the creds,
2115 * so we pass NT_STATUS_DOWNGRADE_DETECTED
2116 * to netlogon_creds_cli_check_cleanup()
2118 status = NT_STATUS_DOWNGRADE_DETECTED;
2119 netlogon_creds_cli_check_cleanup(req, status);
2120 return;
2123 if (!W_ERROR_EQUAL(result, WERR_NOT_SUPPORTED)) {
2124 status = NT_STATUS_DOWNGRADE_DETECTED;
2125 tevent_req_nterror(req, status);
2126 netlogon_creds_cli_check_cleanup(req, status);
2127 return;
2130 tevent_req_done(req);
2133 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
2134 union netr_Capabilities *capabilities)
2136 struct netlogon_creds_cli_check_state *state = tevent_req_data(
2137 req, struct netlogon_creds_cli_check_state);
2138 NTSTATUS status;
2140 if (tevent_req_is_nterror(req, &status)) {
2141 netlogon_creds_cli_check_cleanup(req, status);
2142 tevent_req_received(req);
2143 return status;
2146 if (capabilities != NULL) {
2147 *capabilities = state->caps;
2150 tevent_req_received(req);
2151 return NT_STATUS_OK;
2154 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
2155 struct dcerpc_binding_handle *b,
2156 union netr_Capabilities *capabilities)
2158 TALLOC_CTX *frame = talloc_stackframe();
2159 struct tevent_context *ev;
2160 struct tevent_req *req;
2161 NTSTATUS status = NT_STATUS_NO_MEMORY;
2163 ev = samba_tevent_context_init(frame);
2164 if (ev == NULL) {
2165 goto fail;
2167 req = netlogon_creds_cli_check_send(frame, ev, context, b);
2168 if (req == NULL) {
2169 goto fail;
2171 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2172 goto fail;
2174 status = netlogon_creds_cli_check_recv(req, capabilities);
2175 fail:
2176 TALLOC_FREE(frame);
2177 return status;
2180 struct netlogon_creds_cli_ServerPasswordSet_state {
2181 struct tevent_context *ev;
2182 struct netlogon_creds_cli_context *context;
2183 struct dcerpc_binding_handle *binding_handle;
2184 uint32_t old_timeout;
2186 char *srv_name_slash;
2187 enum dcerpc_AuthType auth_type;
2188 enum dcerpc_AuthLevel auth_level;
2190 struct samr_CryptPassword samr_crypt_password;
2191 struct netr_CryptPassword netr_crypt_password;
2192 struct samr_Password samr_password;
2194 struct netlogon_creds_CredentialState *creds;
2195 struct netlogon_creds_CredentialState tmp_creds;
2196 struct netr_Authenticator req_auth;
2197 struct netr_Authenticator rep_auth;
2200 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2201 NTSTATUS status);
2202 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
2204 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
2205 struct tevent_context *ev,
2206 struct netlogon_creds_cli_context *context,
2207 struct dcerpc_binding_handle *b,
2208 const DATA_BLOB *new_password,
2209 const uint32_t *new_version)
2211 struct tevent_req *req;
2212 struct netlogon_creds_cli_ServerPasswordSet_state *state;
2213 struct tevent_req *subreq;
2214 bool ok;
2216 req = tevent_req_create(mem_ctx, &state,
2217 struct netlogon_creds_cli_ServerPasswordSet_state);
2218 if (req == NULL) {
2219 return NULL;
2222 state->ev = ev;
2223 state->context = context;
2224 state->binding_handle = b;
2226 if (new_password->length < 14) {
2227 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2228 return tevent_req_post(req, ev);
2232 * netr_ServerPasswordSet
2234 mdfour(state->samr_password.hash, new_password->data, new_password->length);
2237 * netr_ServerPasswordSet2
2239 ok = set_pw_in_buffer(state->samr_crypt_password.data,
2240 new_password);
2241 if (!ok) {
2242 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2243 return tevent_req_post(req, ev);
2246 if (new_version != NULL) {
2247 struct NL_PASSWORD_VERSION version;
2248 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
2249 uint32_t ofs = 512 - len;
2250 uint8_t *p;
2252 if (len > 500) {
2253 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2254 return tevent_req_post(req, ev);
2256 ofs -= 12;
2258 version.ReservedField = 0;
2259 version.PasswordVersionNumber = *new_version;
2260 version.PasswordVersionPresent =
2261 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
2263 p = state->samr_crypt_password.data + ofs;
2264 SIVAL(p, 0, version.ReservedField);
2265 SIVAL(p, 4, version.PasswordVersionNumber);
2266 SIVAL(p, 8, version.PasswordVersionPresent);
2269 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2270 context->server.computer);
2271 if (tevent_req_nomem(state->srv_name_slash, req)) {
2272 return tevent_req_post(req, ev);
2275 dcerpc_binding_handle_auth_info(state->binding_handle,
2276 &state->auth_type,
2277 &state->auth_level);
2279 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2280 state->context);
2281 if (tevent_req_nomem(subreq, req)) {
2282 return tevent_req_post(req, ev);
2285 tevent_req_set_callback(subreq,
2286 netlogon_creds_cli_ServerPasswordSet_locked,
2287 req);
2289 return req;
2292 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2293 NTSTATUS status)
2295 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2296 tevent_req_data(req,
2297 struct netlogon_creds_cli_ServerPasswordSet_state);
2299 if (state->creds == NULL) {
2300 return;
2303 dcerpc_binding_handle_set_timeout(state->binding_handle,
2304 state->old_timeout);
2306 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2307 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2308 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2309 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2310 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2311 TALLOC_FREE(state->creds);
2312 return;
2315 netlogon_creds_cli_delete(state->context, state->creds);
2316 TALLOC_FREE(state->creds);
2319 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
2321 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
2323 struct tevent_req *req =
2324 tevent_req_callback_data(subreq,
2325 struct tevent_req);
2326 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2327 tevent_req_data(req,
2328 struct netlogon_creds_cli_ServerPasswordSet_state);
2329 NTSTATUS status;
2331 status = netlogon_creds_cli_lock_recv(subreq, state,
2332 &state->creds);
2333 TALLOC_FREE(subreq);
2334 if (tevent_req_nterror(req, status)) {
2335 return;
2338 status = netlogon_creds_cli_check_transport(state->auth_type,
2339 state->auth_level,
2340 state->creds,
2341 DCERPC_AUTH_LEVEL_NONE);
2342 if (tevent_req_nterror(req, status)) {
2343 return;
2346 state->old_timeout = dcerpc_binding_handle_set_timeout(
2347 state->binding_handle, 600000);
2350 * we defer all callbacks in order to cleanup
2351 * the database record.
2353 tevent_req_defer_callback(req, state->ev);
2355 state->tmp_creds = *state->creds;
2356 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2357 &state->req_auth);
2358 if (tevent_req_nterror(req, status)) {
2359 return;
2361 ZERO_STRUCT(state->rep_auth);
2363 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2365 status = netlogon_creds_encrypt_samr_CryptPassword(&state->tmp_creds,
2366 &state->samr_crypt_password,
2367 state->auth_type,
2368 state->auth_level);
2369 if (tevent_req_nterror(req, status)) {
2370 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2371 return;
2374 memcpy(state->netr_crypt_password.data,
2375 state->samr_crypt_password.data, 512);
2376 state->netr_crypt_password.length =
2377 IVAL(state->samr_crypt_password.data, 512);
2379 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2380 state->binding_handle,
2381 state->srv_name_slash,
2382 state->tmp_creds.account_name,
2383 state->tmp_creds.secure_channel_type,
2384 state->tmp_creds.computer_name,
2385 &state->req_auth,
2386 &state->rep_auth,
2387 &state->netr_crypt_password);
2388 if (tevent_req_nomem(subreq, req)) {
2389 status = NT_STATUS_NO_MEMORY;
2390 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2391 return;
2393 } else {
2394 status = netlogon_creds_encrypt_samr_Password(&state->tmp_creds,
2395 &state->samr_password,
2396 state->auth_type,
2397 state->auth_level);
2398 if (tevent_req_nterror(req, status)) {
2399 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2400 return;
2403 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2404 state->binding_handle,
2405 state->srv_name_slash,
2406 state->tmp_creds.account_name,
2407 state->tmp_creds.secure_channel_type,
2408 state->tmp_creds.computer_name,
2409 &state->req_auth,
2410 &state->rep_auth,
2411 &state->samr_password);
2412 if (tevent_req_nomem(subreq, req)) {
2413 status = NT_STATUS_NO_MEMORY;
2414 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2415 return;
2419 tevent_req_set_callback(subreq,
2420 netlogon_creds_cli_ServerPasswordSet_done,
2421 req);
2424 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2426 struct tevent_req *req =
2427 tevent_req_callback_data(subreq,
2428 struct tevent_req);
2429 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2430 tevent_req_data(req,
2431 struct netlogon_creds_cli_ServerPasswordSet_state);
2432 NTSTATUS status;
2433 NTSTATUS result;
2435 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2436 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2437 &result);
2438 TALLOC_FREE(subreq);
2439 if (tevent_req_nterror(req, status)) {
2440 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2441 return;
2443 } else {
2444 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2445 &result);
2446 TALLOC_FREE(subreq);
2447 if (tevent_req_nterror(req, status)) {
2448 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2449 return;
2453 status = netlogon_creds_client_verify(&state->tmp_creds,
2454 &state->rep_auth.cred,
2455 state->auth_type,
2456 state->auth_level);
2457 if (tevent_req_nterror(req, status)) {
2458 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2459 return;
2462 if (tevent_req_nterror(req, result)) {
2463 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2464 return;
2467 dcerpc_binding_handle_set_timeout(state->binding_handle,
2468 state->old_timeout);
2470 *state->creds = state->tmp_creds;
2471 status = netlogon_creds_cli_store(state->context,
2472 state->creds);
2473 TALLOC_FREE(state->creds);
2474 if (tevent_req_nterror(req, status)) {
2475 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2476 return;
2479 tevent_req_done(req);
2482 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2484 NTSTATUS status;
2486 if (tevent_req_is_nterror(req, &status)) {
2487 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2488 tevent_req_received(req);
2489 return status;
2492 tevent_req_received(req);
2493 return NT_STATUS_OK;
2496 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2497 struct netlogon_creds_cli_context *context,
2498 struct dcerpc_binding_handle *b,
2499 const DATA_BLOB *new_password,
2500 const uint32_t *new_version)
2502 TALLOC_CTX *frame = talloc_stackframe();
2503 struct tevent_context *ev;
2504 struct tevent_req *req;
2505 NTSTATUS status = NT_STATUS_NO_MEMORY;
2507 ev = samba_tevent_context_init(frame);
2508 if (ev == NULL) {
2509 goto fail;
2511 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2512 new_password,
2513 new_version);
2514 if (req == NULL) {
2515 goto fail;
2517 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2518 goto fail;
2520 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2521 fail:
2522 TALLOC_FREE(frame);
2523 return status;
2526 struct netlogon_creds_cli_LogonSamLogon_state {
2527 struct tevent_context *ev;
2528 struct netlogon_creds_cli_context *context;
2529 struct dcerpc_binding_handle *binding_handle;
2531 char *srv_name_slash;
2533 enum netr_LogonInfoClass logon_level;
2534 const union netr_LogonLevel *const_logon;
2535 union netr_LogonLevel *logon;
2536 uint32_t flags;
2538 uint16_t validation_level;
2539 union netr_Validation *validation;
2540 uint8_t authoritative;
2543 * do we need encryption at the application layer?
2545 bool user_encrypt;
2546 bool try_logon_ex;
2547 bool try_validation6;
2550 * the read only credentials before we started the operation
2551 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2553 struct netlogon_creds_CredentialState *ro_creds;
2556 * The (locked) credentials used for the credential chain
2557 * used for netr_LogonSamLogonWithFlags() or
2558 * netr_LogonSamLogonWith().
2560 struct netlogon_creds_CredentialState *lk_creds;
2563 * While we have locked the global credentials (lk_creds above)
2564 * we operate an a temporary copy, because a server
2565 * may not support netr_LogonSamLogonWithFlags() and
2566 * didn't process our netr_Authenticator, so we need to
2567 * restart from lk_creds.
2569 struct netlogon_creds_CredentialState tmp_creds;
2570 struct netr_Authenticator req_auth;
2571 struct netr_Authenticator rep_auth;
2574 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2575 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2576 NTSTATUS status);
2578 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2579 struct tevent_context *ev,
2580 struct netlogon_creds_cli_context *context,
2581 struct dcerpc_binding_handle *b,
2582 enum netr_LogonInfoClass logon_level,
2583 const union netr_LogonLevel *logon,
2584 uint32_t flags)
2586 struct tevent_req *req;
2587 struct netlogon_creds_cli_LogonSamLogon_state *state;
2589 req = tevent_req_create(mem_ctx, &state,
2590 struct netlogon_creds_cli_LogonSamLogon_state);
2591 if (req == NULL) {
2592 return NULL;
2595 state->ev = ev;
2596 state->context = context;
2597 state->binding_handle = b;
2599 state->logon_level = logon_level;
2600 state->const_logon = logon;
2601 state->flags = flags;
2603 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2604 context->server.computer);
2605 if (tevent_req_nomem(state->srv_name_slash, req)) {
2606 return tevent_req_post(req, ev);
2609 switch (logon_level) {
2610 case NetlogonInteractiveInformation:
2611 case NetlogonInteractiveTransitiveInformation:
2612 case NetlogonServiceInformation:
2613 case NetlogonServiceTransitiveInformation:
2614 case NetlogonGenericInformation:
2615 state->user_encrypt = true;
2616 break;
2618 case NetlogonNetworkInformation:
2619 case NetlogonNetworkTransitiveInformation:
2620 case NetlogonTicketLogonInformation:
2621 break;
2624 state->validation = talloc_zero(state, union netr_Validation);
2625 if (tevent_req_nomem(state->validation, req)) {
2626 return tevent_req_post(req, ev);
2629 netlogon_creds_cli_LogonSamLogon_start(req);
2630 if (!tevent_req_is_in_progress(req)) {
2631 return tevent_req_post(req, ev);
2635 * we defer all callbacks in order to cleanup
2636 * the database record.
2638 tevent_req_defer_callback(req, state->ev);
2639 return req;
2642 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2643 NTSTATUS status)
2645 struct netlogon_creds_cli_LogonSamLogon_state *state =
2646 tevent_req_data(req,
2647 struct netlogon_creds_cli_LogonSamLogon_state);
2649 if (state->lk_creds == NULL) {
2650 return;
2653 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2655 * This is a hack to recover from a bug in old
2656 * Samba servers, when LogonSamLogonEx() fails:
2658 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2660 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2662 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2663 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2664 * If the sign/seal check fails.
2666 * In that case we need to cleanup the netlogon session.
2668 * It's the job of the caller to disconnect the current
2669 * connection, if netlogon_creds_cli_LogonSamLogon()
2670 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2672 if (!state->context->server.try_logon_with) {
2673 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2677 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2678 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2679 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2680 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2681 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2682 TALLOC_FREE(state->lk_creds);
2683 return;
2686 netlogon_creds_cli_delete(state->context, state->lk_creds);
2687 TALLOC_FREE(state->lk_creds);
2690 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2692 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2694 struct netlogon_creds_cli_LogonSamLogon_state *state =
2695 tevent_req_data(req,
2696 struct netlogon_creds_cli_LogonSamLogon_state);
2697 struct tevent_req *subreq;
2698 NTSTATUS status;
2699 enum dcerpc_AuthType auth_type;
2700 enum dcerpc_AuthLevel auth_level;
2702 TALLOC_FREE(state->ro_creds);
2703 TALLOC_FREE(state->logon);
2704 ZERO_STRUCTP(state->validation);
2706 dcerpc_binding_handle_auth_info(state->binding_handle,
2707 &auth_type, &auth_level);
2709 state->try_logon_ex = state->context->server.try_logon_ex;
2710 state->try_validation6 = state->context->server.try_validation6;
2712 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2713 state->try_logon_ex = false;
2716 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2717 state->try_validation6 = false;
2720 if (state->try_logon_ex) {
2721 if (state->try_validation6) {
2722 state->validation_level = 6;
2723 } else {
2724 state->validation_level = 3;
2725 state->user_encrypt = true;
2728 state->logon = netlogon_creds_shallow_copy_logon(state,
2729 state->logon_level,
2730 state->const_logon);
2731 if (tevent_req_nomem(state->logon, req)) {
2732 status = NT_STATUS_NO_MEMORY;
2733 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2734 return;
2737 if (state->user_encrypt) {
2738 status = netlogon_creds_cli_get(state->context,
2739 state,
2740 &state->ro_creds);
2741 if (!NT_STATUS_IS_OK(status)) {
2742 status = NT_STATUS_ACCESS_DENIED;
2743 tevent_req_nterror(req, status);
2744 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2745 return;
2748 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2749 state->logon_level,
2750 state->logon,
2751 auth_type,
2752 auth_level);
2753 if (!NT_STATUS_IS_OK(status)) {
2754 status = NT_STATUS_ACCESS_DENIED;
2755 tevent_req_nterror(req, status);
2756 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2757 return;
2761 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2762 state->binding_handle,
2763 state->srv_name_slash,
2764 state->context->client.computer,
2765 state->logon_level,
2766 state->logon,
2767 state->validation_level,
2768 state->validation,
2769 &state->authoritative,
2770 &state->flags);
2771 if (tevent_req_nomem(subreq, req)) {
2772 status = NT_STATUS_NO_MEMORY;
2773 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2774 return;
2776 tevent_req_set_callback(subreq,
2777 netlogon_creds_cli_LogonSamLogon_done,
2778 req);
2779 return;
2782 if (state->lk_creds == NULL) {
2783 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2784 state->context);
2785 if (tevent_req_nomem(subreq, req)) {
2786 status = NT_STATUS_NO_MEMORY;
2787 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2788 return;
2790 tevent_req_set_callback(subreq,
2791 netlogon_creds_cli_LogonSamLogon_done,
2792 req);
2793 return;
2796 state->tmp_creds = *state->lk_creds;
2797 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2798 &state->req_auth);
2799 if (tevent_req_nterror(req, status)) {
2800 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2801 return;
2803 ZERO_STRUCT(state->rep_auth);
2805 state->logon = netlogon_creds_shallow_copy_logon(state,
2806 state->logon_level,
2807 state->const_logon);
2808 if (tevent_req_nomem(state->logon, req)) {
2809 status = NT_STATUS_NO_MEMORY;
2810 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2811 return;
2814 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2815 state->logon_level,
2816 state->logon,
2817 auth_type,
2818 auth_level);
2819 if (tevent_req_nterror(req, status)) {
2820 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2821 return;
2824 state->validation_level = 3;
2826 if (state->context->server.try_logon_with) {
2827 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2828 state->binding_handle,
2829 state->srv_name_slash,
2830 state->context->client.computer,
2831 &state->req_auth,
2832 &state->rep_auth,
2833 state->logon_level,
2834 state->logon,
2835 state->validation_level,
2836 state->validation,
2837 &state->authoritative,
2838 &state->flags);
2839 if (tevent_req_nomem(subreq, req)) {
2840 status = NT_STATUS_NO_MEMORY;
2841 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2842 return;
2844 } else {
2845 state->flags = 0;
2847 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2848 state->binding_handle,
2849 state->srv_name_slash,
2850 state->context->client.computer,
2851 &state->req_auth,
2852 &state->rep_auth,
2853 state->logon_level,
2854 state->logon,
2855 state->validation_level,
2856 state->validation,
2857 &state->authoritative);
2858 if (tevent_req_nomem(subreq, req)) {
2859 status = NT_STATUS_NO_MEMORY;
2860 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2861 return;
2865 tevent_req_set_callback(subreq,
2866 netlogon_creds_cli_LogonSamLogon_done,
2867 req);
2870 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2872 struct tevent_req *req =
2873 tevent_req_callback_data(subreq,
2874 struct tevent_req);
2875 struct netlogon_creds_cli_LogonSamLogon_state *state =
2876 tevent_req_data(req,
2877 struct netlogon_creds_cli_LogonSamLogon_state);
2878 enum dcerpc_AuthType auth_type;
2879 enum dcerpc_AuthLevel auth_level;
2880 NTSTATUS status;
2881 NTSTATUS result;
2882 bool ok;
2884 dcerpc_binding_handle_auth_info(state->binding_handle,
2885 &auth_type,
2886 &auth_level);
2888 if (state->try_logon_ex) {
2889 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2890 state->validation,
2891 &result);
2892 TALLOC_FREE(subreq);
2893 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2894 state->context->server.try_validation6 = false;
2895 state->context->server.try_logon_ex = false;
2896 netlogon_creds_cli_LogonSamLogon_start(req);
2897 return;
2899 if (tevent_req_nterror(req, status)) {
2900 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2901 return;
2904 if ((state->validation_level == 6) &&
2905 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2906 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2907 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2909 state->context->server.try_validation6 = false;
2910 netlogon_creds_cli_LogonSamLogon_start(req);
2911 return;
2914 if (tevent_req_nterror(req, result)) {
2915 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2916 return;
2919 if (state->ro_creds == NULL) {
2920 tevent_req_done(req);
2921 return;
2924 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2925 if (!ok) {
2927 * We got a race, lets retry with on authenticator
2928 * protection.
2930 * netlogon_creds_cli_LogonSamLogon_start()
2931 * will TALLOC_FREE(state->ro_creds);
2933 state->try_logon_ex = false;
2934 netlogon_creds_cli_LogonSamLogon_start(req);
2935 return;
2938 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2939 state->validation_level,
2940 state->validation,
2941 auth_type,
2942 auth_level);
2943 if (tevent_req_nterror(req, status)) {
2944 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2945 return;
2948 tevent_req_done(req);
2949 return;
2952 if (state->lk_creds == NULL) {
2953 status = netlogon_creds_cli_lock_recv(subreq, state,
2954 &state->lk_creds);
2955 TALLOC_FREE(subreq);
2956 if (tevent_req_nterror(req, status)) {
2957 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2958 return;
2961 netlogon_creds_cli_LogonSamLogon_start(req);
2962 return;
2965 if (state->context->server.try_logon_with) {
2966 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2967 state->validation,
2968 &result);
2969 TALLOC_FREE(subreq);
2970 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2971 state->context->server.try_logon_with = false;
2972 netlogon_creds_cli_LogonSamLogon_start(req);
2973 return;
2975 if (tevent_req_nterror(req, status)) {
2976 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2977 return;
2979 } else {
2980 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2981 state->validation,
2982 &result);
2983 TALLOC_FREE(subreq);
2984 if (tevent_req_nterror(req, status)) {
2985 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2986 return;
2990 status = netlogon_creds_client_verify(&state->tmp_creds,
2991 &state->rep_auth.cred,
2992 auth_type,
2993 auth_level);
2994 if (tevent_req_nterror(req, status)) {
2995 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2996 return;
2999 *state->lk_creds = state->tmp_creds;
3000 status = netlogon_creds_cli_store(state->context,
3001 state->lk_creds);
3002 TALLOC_FREE(state->lk_creds);
3004 if (tevent_req_nterror(req, status)) {
3005 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3006 return;
3009 if (tevent_req_nterror(req, result)) {
3010 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
3011 return;
3014 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
3015 state->validation_level,
3016 state->validation,
3017 auth_type,
3018 auth_level);
3019 if (tevent_req_nterror(req, status)) {
3020 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
3021 return;
3024 tevent_req_done(req);
3027 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
3028 TALLOC_CTX *mem_ctx,
3029 uint16_t *validation_level,
3030 union netr_Validation **validation,
3031 uint8_t *authoritative,
3032 uint32_t *flags)
3034 struct netlogon_creds_cli_LogonSamLogon_state *state =
3035 tevent_req_data(req,
3036 struct netlogon_creds_cli_LogonSamLogon_state);
3037 NTSTATUS status;
3039 /* authoritative is also returned on error */
3040 *authoritative = state->authoritative;
3042 if (tevent_req_is_nterror(req, &status)) {
3043 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3044 tevent_req_received(req);
3045 return status;
3048 *validation_level = state->validation_level;
3049 *validation = talloc_move(mem_ctx, &state->validation);
3050 *flags = state->flags;
3052 tevent_req_received(req);
3053 return NT_STATUS_OK;
3056 NTSTATUS netlogon_creds_cli_LogonSamLogon(
3057 struct netlogon_creds_cli_context *context,
3058 struct dcerpc_binding_handle *b,
3059 enum netr_LogonInfoClass logon_level,
3060 const union netr_LogonLevel *logon,
3061 TALLOC_CTX *mem_ctx,
3062 uint16_t *validation_level,
3063 union netr_Validation **validation,
3064 uint8_t *authoritative,
3065 uint32_t *flags)
3067 TALLOC_CTX *frame = talloc_stackframe();
3068 struct tevent_context *ev;
3069 struct tevent_req *req;
3070 NTSTATUS status = NT_STATUS_NO_MEMORY;
3072 ev = samba_tevent_context_init(frame);
3073 if (ev == NULL) {
3074 goto fail;
3076 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
3077 logon_level, logon,
3078 *flags);
3079 if (req == NULL) {
3080 goto fail;
3082 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3083 goto fail;
3085 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
3086 validation_level,
3087 validation,
3088 authoritative,
3089 flags);
3090 fail:
3091 TALLOC_FREE(frame);
3092 return status;
3095 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
3096 struct tevent_context *ev;
3097 struct netlogon_creds_cli_context *context;
3098 struct dcerpc_binding_handle *binding_handle;
3100 char *srv_name_slash;
3101 enum dcerpc_AuthType auth_type;
3102 enum dcerpc_AuthLevel auth_level;
3104 const char *site_name;
3105 uint32_t dns_ttl;
3106 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
3108 struct netlogon_creds_CredentialState *creds;
3109 struct netlogon_creds_CredentialState tmp_creds;
3110 struct netr_Authenticator req_auth;
3111 struct netr_Authenticator rep_auth;
3114 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
3115 NTSTATUS status);
3116 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
3118 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
3119 struct tevent_context *ev,
3120 struct netlogon_creds_cli_context *context,
3121 struct dcerpc_binding_handle *b,
3122 const char *site_name,
3123 uint32_t dns_ttl,
3124 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3126 struct tevent_req *req;
3127 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
3128 struct tevent_req *subreq;
3130 req = tevent_req_create(mem_ctx, &state,
3131 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3132 if (req == NULL) {
3133 return NULL;
3136 state->ev = ev;
3137 state->context = context;
3138 state->binding_handle = b;
3140 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3141 context->server.computer);
3142 if (tevent_req_nomem(state->srv_name_slash, req)) {
3143 return tevent_req_post(req, ev);
3146 state->site_name = site_name;
3147 state->dns_ttl = dns_ttl;
3148 state->dns_names = dns_names;
3150 dcerpc_binding_handle_auth_info(state->binding_handle,
3151 &state->auth_type,
3152 &state->auth_level);
3154 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3155 state->context);
3156 if (tevent_req_nomem(subreq, req)) {
3157 return tevent_req_post(req, ev);
3160 tevent_req_set_callback(subreq,
3161 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
3162 req);
3164 return req;
3167 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
3168 NTSTATUS status)
3170 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3171 tevent_req_data(req,
3172 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3174 if (state->creds == NULL) {
3175 return;
3178 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3179 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3180 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3181 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3182 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3183 TALLOC_FREE(state->creds);
3184 return;
3187 netlogon_creds_cli_delete(state->context, state->creds);
3188 TALLOC_FREE(state->creds);
3191 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
3193 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
3195 struct tevent_req *req =
3196 tevent_req_callback_data(subreq,
3197 struct tevent_req);
3198 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3199 tevent_req_data(req,
3200 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3201 NTSTATUS status;
3203 status = netlogon_creds_cli_lock_recv(subreq, state,
3204 &state->creds);
3205 TALLOC_FREE(subreq);
3206 if (tevent_req_nterror(req, status)) {
3207 return;
3210 status = netlogon_creds_cli_check_transport(state->auth_type,
3211 state->auth_level,
3212 state->creds,
3213 DCERPC_AUTH_LEVEL_NONE);
3214 if (tevent_req_nterror(req, status)) {
3215 return;
3219 * we defer all callbacks in order to cleanup
3220 * the database record.
3222 tevent_req_defer_callback(req, state->ev);
3224 state->tmp_creds = *state->creds;
3225 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3226 &state->req_auth);
3227 if (tevent_req_nterror(req, status)) {
3228 return;
3230 ZERO_STRUCT(state->rep_auth);
3232 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
3233 state->binding_handle,
3234 state->srv_name_slash,
3235 state->tmp_creds.computer_name,
3236 &state->req_auth,
3237 &state->rep_auth,
3238 state->site_name,
3239 state->dns_ttl,
3240 state->dns_names);
3241 if (tevent_req_nomem(subreq, req)) {
3242 status = NT_STATUS_NO_MEMORY;
3243 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3244 return;
3247 tevent_req_set_callback(subreq,
3248 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
3249 req);
3252 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
3254 struct tevent_req *req =
3255 tevent_req_callback_data(subreq,
3256 struct tevent_req);
3257 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3258 tevent_req_data(req,
3259 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3260 NTSTATUS status;
3261 NTSTATUS result;
3264 * We use state->dns_names as the memory context, as this is
3265 * the only in/out variable and it has been overwritten by the
3266 * out parameter from the server.
3268 * We need to preserve the return value until the caller can use it.
3270 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
3271 &result);
3272 TALLOC_FREE(subreq);
3273 if (tevent_req_nterror(req, status)) {
3274 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3275 return;
3278 status = netlogon_creds_client_verify(&state->tmp_creds,
3279 &state->rep_auth.cred,
3280 state->auth_type,
3281 state->auth_level);
3282 if (tevent_req_nterror(req, status)) {
3283 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3284 return;
3287 *state->creds = state->tmp_creds;
3288 status = netlogon_creds_cli_store(state->context,
3289 state->creds);
3290 TALLOC_FREE(state->creds);
3292 if (tevent_req_nterror(req, status)) {
3293 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3294 return;
3297 if (tevent_req_nterror(req, result)) {
3298 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
3299 return;
3302 tevent_req_done(req);
3305 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
3307 NTSTATUS status;
3309 if (tevent_req_is_nterror(req, &status)) {
3310 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3311 tevent_req_received(req);
3312 return status;
3315 tevent_req_received(req);
3316 return NT_STATUS_OK;
3319 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3320 struct netlogon_creds_cli_context *context,
3321 struct dcerpc_binding_handle *b,
3322 const char *site_name,
3323 uint32_t dns_ttl,
3324 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3326 TALLOC_CTX *frame = talloc_stackframe();
3327 struct tevent_context *ev;
3328 struct tevent_req *req;
3329 NTSTATUS status = NT_STATUS_NO_MEMORY;
3331 ev = samba_tevent_context_init(frame);
3332 if (ev == NULL) {
3333 goto fail;
3335 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
3336 site_name,
3337 dns_ttl,
3338 dns_names);
3339 if (req == NULL) {
3340 goto fail;
3342 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3343 goto fail;
3345 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
3346 fail:
3347 TALLOC_FREE(frame);
3348 return status;
3351 struct netlogon_creds_cli_ServerGetTrustInfo_state {
3352 struct tevent_context *ev;
3353 struct netlogon_creds_cli_context *context;
3354 struct dcerpc_binding_handle *binding_handle;
3356 char *srv_name_slash;
3357 enum dcerpc_AuthType auth_type;
3358 enum dcerpc_AuthLevel auth_level;
3360 struct samr_Password new_owf_password;
3361 struct samr_Password old_owf_password;
3362 struct netr_TrustInfo *trust_info;
3364 struct netlogon_creds_CredentialState *creds;
3365 struct netlogon_creds_CredentialState tmp_creds;
3366 struct netr_Authenticator req_auth;
3367 struct netr_Authenticator rep_auth;
3370 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3371 NTSTATUS status);
3372 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3374 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3375 struct tevent_context *ev,
3376 struct netlogon_creds_cli_context *context,
3377 struct dcerpc_binding_handle *b)
3379 struct tevent_req *req;
3380 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3381 struct tevent_req *subreq;
3383 req = tevent_req_create(mem_ctx, &state,
3384 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3385 if (req == NULL) {
3386 return NULL;
3389 state->ev = ev;
3390 state->context = context;
3391 state->binding_handle = b;
3393 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3394 context->server.computer);
3395 if (tevent_req_nomem(state->srv_name_slash, req)) {
3396 return tevent_req_post(req, ev);
3399 dcerpc_binding_handle_auth_info(state->binding_handle,
3400 &state->auth_type,
3401 &state->auth_level);
3403 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3404 state->context);
3405 if (tevent_req_nomem(subreq, req)) {
3406 return tevent_req_post(req, ev);
3409 tevent_req_set_callback(subreq,
3410 netlogon_creds_cli_ServerGetTrustInfo_locked,
3411 req);
3413 return req;
3416 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3417 NTSTATUS status)
3419 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3420 tevent_req_data(req,
3421 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3423 if (state->creds == NULL) {
3424 return;
3427 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3428 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3429 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3430 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3431 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3432 TALLOC_FREE(state->creds);
3433 return;
3436 netlogon_creds_cli_delete(state->context, state->creds);
3437 TALLOC_FREE(state->creds);
3440 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3442 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3444 struct tevent_req *req =
3445 tevent_req_callback_data(subreq,
3446 struct tevent_req);
3447 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3448 tevent_req_data(req,
3449 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3450 NTSTATUS status;
3452 status = netlogon_creds_cli_lock_recv(subreq, state,
3453 &state->creds);
3454 TALLOC_FREE(subreq);
3455 if (tevent_req_nterror(req, status)) {
3456 return;
3459 status = netlogon_creds_cli_check_transport(state->auth_type,
3460 state->auth_level,
3461 state->creds,
3462 DCERPC_AUTH_LEVEL_PRIVACY);
3463 if (tevent_req_nterror(req, status)) {
3464 return;
3468 * we defer all callbacks in order to cleanup
3469 * the database record.
3471 tevent_req_defer_callback(req, state->ev);
3473 state->tmp_creds = *state->creds;
3474 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3475 &state->req_auth);
3476 if (tevent_req_nterror(req, status)) {
3477 return;
3479 ZERO_STRUCT(state->rep_auth);
3481 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3482 state->binding_handle,
3483 state->srv_name_slash,
3484 state->tmp_creds.account_name,
3485 state->tmp_creds.secure_channel_type,
3486 state->tmp_creds.computer_name,
3487 &state->req_auth,
3488 &state->rep_auth,
3489 &state->new_owf_password,
3490 &state->old_owf_password,
3491 &state->trust_info);
3492 if (tevent_req_nomem(subreq, req)) {
3493 status = NT_STATUS_NO_MEMORY;
3494 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3495 return;
3498 tevent_req_set_callback(subreq,
3499 netlogon_creds_cli_ServerGetTrustInfo_done,
3500 req);
3503 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3505 struct tevent_req *req =
3506 tevent_req_callback_data(subreq,
3507 struct tevent_req);
3508 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3509 tevent_req_data(req,
3510 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3511 NTSTATUS status;
3512 NTSTATUS result;
3515 * We use state->dns_names as the memory context, as this is
3516 * the only in/out variable and it has been overwritten by the
3517 * out parameter from the server.
3519 * We need to preserve the return value until the caller can use it.
3521 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3522 TALLOC_FREE(subreq);
3523 if (tevent_req_nterror(req, status)) {
3524 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3525 return;
3528 status = netlogon_creds_client_verify(&state->tmp_creds,
3529 &state->rep_auth.cred,
3530 state->auth_type,
3531 state->auth_level);
3532 if (tevent_req_nterror(req, status)) {
3533 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3534 return;
3537 status = netlogon_creds_decrypt_samr_Password(&state->tmp_creds,
3538 &state->new_owf_password,
3539 state->auth_type,
3540 state->auth_level);
3541 if (tevent_req_nterror(req, status)) {
3542 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3543 return;
3545 status = netlogon_creds_decrypt_samr_Password(&state->tmp_creds,
3546 &state->old_owf_password,
3547 state->auth_type,
3548 state->auth_level);
3549 if (tevent_req_nterror(req, status)) {
3550 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3551 return;
3554 *state->creds = state->tmp_creds;
3555 status = netlogon_creds_cli_store(state->context,
3556 state->creds);
3557 TALLOC_FREE(state->creds);
3558 if (tevent_req_nterror(req, status)) {
3559 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3560 return;
3563 if (tevent_req_nterror(req, result)) {
3564 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3565 return;
3568 tevent_req_done(req);
3571 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3572 TALLOC_CTX *mem_ctx,
3573 struct samr_Password *new_owf_password,
3574 struct samr_Password *old_owf_password,
3575 struct netr_TrustInfo **trust_info)
3577 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3578 tevent_req_data(req,
3579 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3580 NTSTATUS status;
3582 if (tevent_req_is_nterror(req, &status)) {
3583 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3584 tevent_req_received(req);
3585 return status;
3588 if (new_owf_password != NULL) {
3589 *new_owf_password = state->new_owf_password;
3591 if (old_owf_password != NULL) {
3592 *old_owf_password = state->old_owf_password;
3594 if (trust_info != NULL) {
3595 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3598 tevent_req_received(req);
3599 return NT_STATUS_OK;
3602 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3603 struct netlogon_creds_cli_context *context,
3604 struct dcerpc_binding_handle *b,
3605 TALLOC_CTX *mem_ctx,
3606 struct samr_Password *new_owf_password,
3607 struct samr_Password *old_owf_password,
3608 struct netr_TrustInfo **trust_info)
3610 TALLOC_CTX *frame = talloc_stackframe();
3611 struct tevent_context *ev;
3612 struct tevent_req *req;
3613 NTSTATUS status = NT_STATUS_NO_MEMORY;
3615 ev = samba_tevent_context_init(frame);
3616 if (ev == NULL) {
3617 goto fail;
3619 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3620 if (req == NULL) {
3621 goto fail;
3623 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3624 goto fail;
3626 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3627 mem_ctx,
3628 new_owf_password,
3629 old_owf_password,
3630 trust_info);
3631 fail:
3632 TALLOC_FREE(frame);
3633 return status;
3636 struct netlogon_creds_cli_GetForestTrustInformation_state {
3637 struct tevent_context *ev;
3638 struct netlogon_creds_cli_context *context;
3639 struct dcerpc_binding_handle *binding_handle;
3641 char *srv_name_slash;
3642 enum dcerpc_AuthType auth_type;
3643 enum dcerpc_AuthLevel auth_level;
3645 uint32_t flags;
3646 struct lsa_ForestTrustInformation *forest_trust_info;
3648 struct netlogon_creds_CredentialState *creds;
3649 struct netlogon_creds_CredentialState tmp_creds;
3650 struct netr_Authenticator req_auth;
3651 struct netr_Authenticator rep_auth;
3654 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3655 NTSTATUS status);
3656 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3658 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3659 struct tevent_context *ev,
3660 struct netlogon_creds_cli_context *context,
3661 struct dcerpc_binding_handle *b)
3663 struct tevent_req *req;
3664 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3665 struct tevent_req *subreq;
3667 req = tevent_req_create(mem_ctx, &state,
3668 struct netlogon_creds_cli_GetForestTrustInformation_state);
3669 if (req == NULL) {
3670 return NULL;
3673 state->ev = ev;
3674 state->context = context;
3675 state->binding_handle = b;
3677 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3678 context->server.computer);
3679 if (tevent_req_nomem(state->srv_name_slash, req)) {
3680 return tevent_req_post(req, ev);
3683 state->flags = 0;
3685 dcerpc_binding_handle_auth_info(state->binding_handle,
3686 &state->auth_type,
3687 &state->auth_level);
3689 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3690 state->context);
3691 if (tevent_req_nomem(subreq, req)) {
3692 return tevent_req_post(req, ev);
3695 tevent_req_set_callback(subreq,
3696 netlogon_creds_cli_GetForestTrustInformation_locked,
3697 req);
3699 return req;
3702 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3703 NTSTATUS status)
3705 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3706 tevent_req_data(req,
3707 struct netlogon_creds_cli_GetForestTrustInformation_state);
3709 if (state->creds == NULL) {
3710 return;
3713 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3714 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3715 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3716 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3717 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3718 TALLOC_FREE(state->creds);
3719 return;
3722 netlogon_creds_cli_delete(state->context, state->creds);
3723 TALLOC_FREE(state->creds);
3726 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3728 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3730 struct tevent_req *req =
3731 tevent_req_callback_data(subreq,
3732 struct tevent_req);
3733 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3734 tevent_req_data(req,
3735 struct netlogon_creds_cli_GetForestTrustInformation_state);
3736 NTSTATUS status;
3738 status = netlogon_creds_cli_lock_recv(subreq, state,
3739 &state->creds);
3740 TALLOC_FREE(subreq);
3741 if (tevent_req_nterror(req, status)) {
3742 return;
3745 status = netlogon_creds_cli_check_transport(state->auth_type,
3746 state->auth_level,
3747 state->creds,
3748 DCERPC_AUTH_LEVEL_NONE);
3749 if (tevent_req_nterror(req, status)) {
3750 return;
3754 * we defer all callbacks in order to cleanup
3755 * the database record.
3757 tevent_req_defer_callback(req, state->ev);
3759 state->tmp_creds = *state->creds;
3760 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3761 &state->req_auth);
3762 if (tevent_req_nterror(req, status)) {
3763 return;
3765 ZERO_STRUCT(state->rep_auth);
3767 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3768 state->binding_handle,
3769 state->srv_name_slash,
3770 state->tmp_creds.computer_name,
3771 &state->req_auth,
3772 &state->rep_auth,
3773 state->flags,
3774 &state->forest_trust_info);
3775 if (tevent_req_nomem(subreq, req)) {
3776 status = NT_STATUS_NO_MEMORY;
3777 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3778 return;
3781 tevent_req_set_callback(subreq,
3782 netlogon_creds_cli_GetForestTrustInformation_done,
3783 req);
3786 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3788 struct tevent_req *req =
3789 tevent_req_callback_data(subreq,
3790 struct tevent_req);
3791 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3792 tevent_req_data(req,
3793 struct netlogon_creds_cli_GetForestTrustInformation_state);
3794 NTSTATUS status;
3795 NTSTATUS result;
3798 * We use state->dns_names as the memory context, as this is
3799 * the only in/out variable and it has been overwritten by the
3800 * out parameter from the server.
3802 * We need to preserve the return value until the caller can use it.
3804 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3805 TALLOC_FREE(subreq);
3806 if (tevent_req_nterror(req, status)) {
3807 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3808 return;
3811 status = netlogon_creds_client_verify(&state->tmp_creds,
3812 &state->rep_auth.cred,
3813 state->auth_type,
3814 state->auth_level);
3815 if (tevent_req_nterror(req, status)) {
3816 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3817 return;
3820 *state->creds = state->tmp_creds;
3821 status = netlogon_creds_cli_store(state->context,
3822 state->creds);
3823 TALLOC_FREE(state->creds);
3825 if (tevent_req_nterror(req, status)) {
3826 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3827 return;
3830 if (tevent_req_nterror(req, result)) {
3831 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3832 return;
3835 tevent_req_done(req);
3838 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3839 TALLOC_CTX *mem_ctx,
3840 struct lsa_ForestTrustInformation **forest_trust_info)
3842 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3843 tevent_req_data(req,
3844 struct netlogon_creds_cli_GetForestTrustInformation_state);
3845 NTSTATUS status;
3847 if (tevent_req_is_nterror(req, &status)) {
3848 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3849 tevent_req_received(req);
3850 return status;
3853 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3855 tevent_req_received(req);
3856 return NT_STATUS_OK;
3859 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3860 struct netlogon_creds_cli_context *context,
3861 struct dcerpc_binding_handle *b,
3862 TALLOC_CTX *mem_ctx,
3863 struct lsa_ForestTrustInformation **forest_trust_info)
3865 TALLOC_CTX *frame = talloc_stackframe();
3866 struct tevent_context *ev;
3867 struct tevent_req *req;
3868 NTSTATUS status = NT_STATUS_NO_MEMORY;
3870 ev = samba_tevent_context_init(frame);
3871 if (ev == NULL) {
3872 goto fail;
3874 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3875 if (req == NULL) {
3876 goto fail;
3878 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3879 goto fail;
3881 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3882 mem_ctx,
3883 forest_trust_info);
3884 fail:
3885 TALLOC_FREE(frame);
3886 return status;
3888 struct netlogon_creds_cli_SendToSam_state {
3889 struct tevent_context *ev;
3890 struct netlogon_creds_cli_context *context;
3891 struct dcerpc_binding_handle *binding_handle;
3893 char *srv_name_slash;
3894 enum dcerpc_AuthType auth_type;
3895 enum dcerpc_AuthLevel auth_level;
3897 DATA_BLOB opaque;
3899 struct netlogon_creds_CredentialState *creds;
3900 struct netlogon_creds_CredentialState tmp_creds;
3901 struct netr_Authenticator req_auth;
3902 struct netr_Authenticator rep_auth;
3905 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3906 NTSTATUS status);
3907 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3909 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3910 struct tevent_context *ev,
3911 struct netlogon_creds_cli_context *context,
3912 struct dcerpc_binding_handle *b,
3913 struct netr_SendToSamBase *message)
3915 struct tevent_req *req;
3916 struct netlogon_creds_cli_SendToSam_state *state;
3917 struct tevent_req *subreq;
3918 enum ndr_err_code ndr_err;
3920 req = tevent_req_create(mem_ctx, &state,
3921 struct netlogon_creds_cli_SendToSam_state);
3922 if (req == NULL) {
3923 return NULL;
3926 state->ev = ev;
3927 state->context = context;
3928 state->binding_handle = b;
3930 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3931 context->server.computer);
3932 if (tevent_req_nomem(state->srv_name_slash, req)) {
3933 return tevent_req_post(req, ev);
3936 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3937 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3938 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3939 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3940 tevent_req_nterror(req, status);
3941 return tevent_req_post(req, ev);
3944 dcerpc_binding_handle_auth_info(state->binding_handle,
3945 &state->auth_type,
3946 &state->auth_level);
3948 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3949 state->context);
3950 if (tevent_req_nomem(subreq, req)) {
3951 return tevent_req_post(req, ev);
3954 tevent_req_set_callback(subreq,
3955 netlogon_creds_cli_SendToSam_locked,
3956 req);
3958 return req;
3961 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3962 NTSTATUS status)
3964 struct netlogon_creds_cli_SendToSam_state *state =
3965 tevent_req_data(req,
3966 struct netlogon_creds_cli_SendToSam_state);
3968 if (state->creds == NULL) {
3969 return;
3972 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3973 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3974 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3975 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3976 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3977 TALLOC_FREE(state->creds);
3978 return;
3981 netlogon_creds_cli_delete(state->context, state->creds);
3982 TALLOC_FREE(state->creds);
3985 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3987 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3989 struct tevent_req *req =
3990 tevent_req_callback_data(subreq,
3991 struct tevent_req);
3992 struct netlogon_creds_cli_SendToSam_state *state =
3993 tevent_req_data(req,
3994 struct netlogon_creds_cli_SendToSam_state);
3995 NTSTATUS status;
3997 status = netlogon_creds_cli_lock_recv(subreq, state,
3998 &state->creds);
3999 TALLOC_FREE(subreq);
4000 if (tevent_req_nterror(req, status)) {
4001 return;
4004 status = netlogon_creds_cli_check_transport(state->auth_type,
4005 state->auth_level,
4006 state->creds,
4007 DCERPC_AUTH_LEVEL_NONE);
4008 if (tevent_req_nterror(req, status)) {
4009 return;
4013 * we defer all callbacks in order to cleanup
4014 * the database record.
4016 tevent_req_defer_callback(req, state->ev);
4018 state->tmp_creds = *state->creds;
4019 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4020 &state->req_auth);
4021 if (tevent_req_nterror(req, status)) {
4022 return;
4024 ZERO_STRUCT(state->rep_auth);
4026 status = netlogon_creds_encrypt_SendToSam(&state->tmp_creds,
4027 state->opaque.data,
4028 state->opaque.length,
4029 state->auth_type,
4030 state->auth_level);
4031 if (tevent_req_nterror(req, status)) {
4032 netlogon_creds_cli_SendToSam_cleanup(req, status);
4033 return;
4036 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
4037 state->binding_handle,
4038 state->srv_name_slash,
4039 state->tmp_creds.computer_name,
4040 &state->req_auth,
4041 &state->rep_auth,
4042 state->opaque.data,
4043 state->opaque.length);
4044 if (tevent_req_nomem(subreq, req)) {
4045 status = NT_STATUS_NO_MEMORY;
4046 netlogon_creds_cli_SendToSam_cleanup(req, status);
4047 return;
4050 tevent_req_set_callback(subreq,
4051 netlogon_creds_cli_SendToSam_done,
4052 req);
4055 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
4057 struct tevent_req *req =
4058 tevent_req_callback_data(subreq,
4059 struct tevent_req);
4060 struct netlogon_creds_cli_SendToSam_state *state =
4061 tevent_req_data(req,
4062 struct netlogon_creds_cli_SendToSam_state);
4063 NTSTATUS status;
4064 NTSTATUS result;
4066 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
4067 TALLOC_FREE(subreq);
4068 if (tevent_req_nterror(req, status)) {
4069 netlogon_creds_cli_SendToSam_cleanup(req, status);
4070 return;
4073 status = netlogon_creds_client_verify(&state->tmp_creds,
4074 &state->rep_auth.cred,
4075 state->auth_type,
4076 state->auth_level);
4077 if (tevent_req_nterror(req, status)) {
4078 netlogon_creds_cli_SendToSam_cleanup(req, status);
4079 return;
4082 *state->creds = state->tmp_creds;
4083 status = netlogon_creds_cli_store(state->context,
4084 state->creds);
4085 TALLOC_FREE(state->creds);
4087 if (tevent_req_nterror(req, status)) {
4088 netlogon_creds_cli_SendToSam_cleanup(req, status);
4089 return;
4093 * Creds must be stored before we send back application errors
4094 * e.g. NT_STATUS_NOT_IMPLEMENTED
4096 if (tevent_req_nterror(req, result)) {
4097 netlogon_creds_cli_SendToSam_cleanup(req, result);
4098 return;
4101 tevent_req_done(req);
4104 NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
4106 NTSTATUS status;
4108 if (tevent_req_is_nterror(req, &status)) {
4109 netlogon_creds_cli_SendToSam_cleanup(req, status);
4110 tevent_req_received(req);
4111 return status;
4114 tevent_req_received(req);
4115 return NT_STATUS_OK;
4118 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
4119 struct dcerpc_binding_handle *b,
4120 struct netr_SendToSamBase *message)
4122 TALLOC_CTX *frame = talloc_stackframe();
4123 struct tevent_context *ev;
4124 struct tevent_req *req;
4125 NTSTATUS status = NT_STATUS_NO_MEMORY;
4127 ev = samba_tevent_context_init(frame);
4128 if (ev == NULL) {
4129 goto fail;
4131 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
4132 if (req == NULL) {
4133 goto fail;
4135 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4136 goto fail;
4138 status = netlogon_creds_cli_SendToSam_recv(req);
4139 fail:
4140 TALLOC_FREE(frame);
4141 return status;
4144 struct netlogon_creds_cli_LogonGetDomainInfo_state {
4145 struct tevent_context *ev;
4146 struct netlogon_creds_cli_context *context;
4147 struct dcerpc_binding_handle *binding_handle;
4149 char *srv_name_slash;
4150 enum dcerpc_AuthType auth_type;
4151 enum dcerpc_AuthLevel auth_level;
4153 uint32_t level;
4154 union netr_WorkstationInfo *query;
4155 union netr_DomainInfo *info;
4157 struct netlogon_creds_CredentialState *creds;
4158 struct netlogon_creds_CredentialState tmp_creds;
4159 struct netr_Authenticator req_auth;
4160 struct netr_Authenticator rep_auth;
4163 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4164 NTSTATUS status);
4165 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
4167 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
4168 struct tevent_context *ev,
4169 struct netlogon_creds_cli_context *context,
4170 struct dcerpc_binding_handle *b,
4171 uint32_t level,
4172 union netr_WorkstationInfo *query)
4174 struct tevent_req *req;
4175 struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
4176 struct tevent_req *subreq;
4178 req = tevent_req_create(mem_ctx, &state,
4179 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4180 if (req == NULL) {
4181 return NULL;
4184 state->ev = ev;
4185 state->context = context;
4186 state->binding_handle = b;
4188 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
4189 context->server.computer);
4190 if (tevent_req_nomem(state->srv_name_slash, req)) {
4191 return tevent_req_post(req, ev);
4194 state->level = level;
4195 state->query = query;
4196 state->info = talloc_zero(state, union netr_DomainInfo);
4197 if (tevent_req_nomem(state->info, req)) {
4198 return tevent_req_post(req, ev);
4201 dcerpc_binding_handle_auth_info(state->binding_handle,
4202 &state->auth_type,
4203 &state->auth_level);
4205 subreq = netlogon_creds_cli_lock_send(state, state->ev,
4206 state->context);
4207 if (tevent_req_nomem(subreq, req)) {
4208 return tevent_req_post(req, ev);
4211 tevent_req_set_callback(subreq,
4212 netlogon_creds_cli_LogonGetDomainInfo_locked,
4213 req);
4215 return req;
4218 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4219 NTSTATUS status)
4221 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4222 tevent_req_data(req,
4223 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4225 if (state->creds == NULL) {
4226 return;
4229 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
4230 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
4231 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
4232 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
4233 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
4234 TALLOC_FREE(state->creds);
4235 return;
4238 netlogon_creds_cli_delete(state->context, state->creds);
4241 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
4243 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
4245 struct tevent_req *req =
4246 tevent_req_callback_data(subreq,
4247 struct tevent_req);
4248 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4249 tevent_req_data(req,
4250 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4251 NTSTATUS status;
4253 status = netlogon_creds_cli_lock_recv(subreq, state,
4254 &state->creds);
4255 TALLOC_FREE(subreq);
4256 if (tevent_req_nterror(req, status)) {
4257 return;
4260 status = netlogon_creds_cli_check_transport(state->auth_type,
4261 state->auth_level,
4262 state->creds,
4263 DCERPC_AUTH_LEVEL_NONE);
4264 if (tevent_req_nterror(req, status)) {
4265 return;
4269 * we defer all callbacks in order to cleanup
4270 * the database record.
4272 tevent_req_defer_callback(req, state->ev);
4274 state->tmp_creds = *state->creds;
4275 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4276 &state->req_auth);
4277 if (tevent_req_nterror(req, status)) {
4278 return;
4280 ZERO_STRUCT(state->rep_auth);
4282 subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
4283 state->binding_handle,
4284 state->srv_name_slash,
4285 state->tmp_creds.computer_name,
4286 &state->req_auth,
4287 &state->rep_auth,
4288 state->level,
4289 state->query,
4290 state->info);
4291 if (tevent_req_nomem(subreq, req)) {
4292 status = NT_STATUS_NO_MEMORY;
4293 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4294 return;
4297 tevent_req_set_callback(subreq,
4298 netlogon_creds_cli_LogonGetDomainInfo_done,
4299 req);
4302 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4304 struct tevent_req *req =
4305 tevent_req_callback_data(subreq,
4306 struct tevent_req);
4307 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4308 tevent_req_data(req,
4309 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4310 NTSTATUS status;
4311 NTSTATUS result;
4314 * We use state->dns_names as the memory context, as this is
4315 * the only in/out variable and it has been overwritten by the
4316 * out parameter from the server.
4318 * We need to preserve the return value until the caller can use it.
4320 status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4321 TALLOC_FREE(subreq);
4322 if (tevent_req_nterror(req, status)) {
4323 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4324 return;
4327 status = netlogon_creds_client_verify(&state->tmp_creds,
4328 &state->rep_auth.cred,
4329 state->auth_type,
4330 state->auth_level);
4331 if (tevent_req_nterror(req, status)) {
4332 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4333 return;
4336 if (tevent_req_nterror(req, result)) {
4337 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4338 return;
4341 *state->creds = state->tmp_creds;
4342 status = netlogon_creds_cli_store(state->context,
4343 state->creds);
4344 if (tevent_req_nterror(req, status)) {
4345 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4346 return;
4349 tevent_req_done(req);
4352 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4353 TALLOC_CTX *mem_ctx,
4354 union netr_DomainInfo **info)
4356 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4357 tevent_req_data(req,
4358 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4359 NTSTATUS status;
4361 if (tevent_req_is_nterror(req, &status)) {
4362 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4363 tevent_req_received(req);
4364 return status;
4367 *info = talloc_move(mem_ctx, &state->info);
4369 tevent_req_received(req);
4370 return NT_STATUS_OK;
4373 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4374 struct netlogon_creds_cli_context *context,
4375 struct dcerpc_binding_handle *b,
4376 TALLOC_CTX *mem_ctx,
4377 uint32_t level,
4378 union netr_WorkstationInfo *query,
4379 union netr_DomainInfo **info)
4381 TALLOC_CTX *frame = talloc_stackframe();
4382 struct tevent_context *ev;
4383 struct tevent_req *req;
4384 NTSTATUS status = NT_STATUS_OK;
4386 ev = samba_tevent_context_init(frame);
4387 if (ev == NULL) {
4388 goto fail;
4390 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4391 level, query);
4392 if (req == NULL) {
4393 goto fail;
4395 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4396 goto fail;
4398 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4399 mem_ctx,
4400 info);
4401 fail:
4402 TALLOC_FREE(frame);
4403 return status;