fuzzing: fix fuzz_stable_sort_r_unstable comparison
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob118c81f6246b1ef6fe125097dea799172415b9bc
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_ARCFOUR;
506 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
507 proposed_flags &= ~NETLOGON_NEG_ARCFOUR;
508 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
511 proposed_flags |= required_flags;
513 if (seal_secure_channel) {
514 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
515 } else {
516 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
519 status = netlogon_creds_cli_context_common(client_computer,
520 client_account,
521 type,
522 auth_level,
523 proposed_flags,
524 required_flags,
525 server_computer,
526 server_netbios_domain,
528 mem_ctx,
529 &context);
530 if (!NT_STATUS_IS_OK(status)) {
531 TALLOC_FREE(frame);
532 return status;
535 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
536 if (context->db.g_ctx == NULL) {
537 TALLOC_FREE(context);
538 TALLOC_FREE(frame);
539 return NT_STATUS_NO_MEMORY;
542 status = netlogon_creds_cli_open_global_db(lp_ctx);
543 if (!NT_STATUS_IS_OK(status)) {
544 TALLOC_FREE(context);
545 TALLOC_FREE(frame);
546 return NT_STATUS_NO_MEMORY;
549 context->db.ctx = netlogon_creds_cli_global_db;
550 *_context = context;
551 TALLOC_FREE(frame);
552 return NT_STATUS_OK;
555 NTSTATUS netlogon_creds_bind_cli_credentials(
556 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
557 struct cli_credentials **pcli_creds)
559 struct cli_credentials *cli_creds;
560 struct netlogon_creds_CredentialState *ncreds;
561 NTSTATUS status;
563 cli_creds = cli_credentials_init(mem_ctx);
564 if (cli_creds == NULL) {
565 return NT_STATUS_NO_MEMORY;
567 cli_credentials_set_secure_channel_type(cli_creds,
568 context->client.type);
569 cli_credentials_set_username(cli_creds, context->client.account,
570 CRED_SPECIFIED);
571 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
572 CRED_SPECIFIED);
573 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
574 CRED_SPECIFIED);
576 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
577 if (!NT_STATUS_IS_OK(status)) {
578 TALLOC_FREE(cli_creds);
579 return status;
581 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
583 *pcli_creds = cli_creds;
584 return NT_STATUS_OK;
587 char *netlogon_creds_cli_debug_string(
588 const struct netlogon_creds_cli_context *context,
589 TALLOC_CTX *mem_ctx)
591 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
592 context->db.key_name);
595 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
596 struct netlogon_creds_cli_context *context)
598 return context->client.auth_level;
601 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
602 uint32_t proposed_flags,
603 uint32_t required_flags)
605 uint32_t req_flags = required_flags;
606 uint32_t tmp_flags;
608 req_flags = required_flags;
609 if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
610 (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
612 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
615 tmp_flags = negotiated_flags;
616 tmp_flags &= req_flags;
617 if (tmp_flags != req_flags) {
618 return true;
621 return false;
624 struct netlogon_creds_cli_fetch_state {
625 TALLOC_CTX *mem_ctx;
626 struct netlogon_creds_CredentialState *creds;
627 uint32_t proposed_flags;
628 uint32_t required_flags;
629 NTSTATUS status;
632 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
633 void *private_data)
635 struct netlogon_creds_cli_fetch_state *state =
636 (struct netlogon_creds_cli_fetch_state *)private_data;
637 enum ndr_err_code ndr_err;
638 DATA_BLOB blob;
639 bool downgraded;
641 state->creds = talloc_zero(state->mem_ctx,
642 struct netlogon_creds_CredentialState);
643 if (state->creds == NULL) {
644 state->status = NT_STATUS_NO_MEMORY;
645 return;
648 blob.data = data.dptr;
649 blob.length = data.dsize;
651 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
652 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
654 TALLOC_FREE(state->creds);
655 state->status = ndr_map_error2ntstatus(ndr_err);
656 return;
659 if (DEBUGLEVEL >= 10) {
660 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
663 downgraded = netlogon_creds_cli_downgraded(
664 state->creds->negotiate_flags,
665 state->proposed_flags,
666 state->required_flags);
667 if (downgraded) {
668 TALLOC_FREE(state->creds);
669 state->status = NT_STATUS_DOWNGRADE_DETECTED;
670 return;
673 state->status = NT_STATUS_OK;
676 static NTSTATUS netlogon_creds_cli_get_internal(
677 struct netlogon_creds_cli_context *context,
678 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
680 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
681 TALLOC_CTX *mem_ctx,
682 struct netlogon_creds_CredentialState **_creds)
684 NTSTATUS status;
685 struct netlogon_creds_CredentialState *creds;
687 *_creds = NULL;
689 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
690 if (!NT_STATUS_IS_OK(status)) {
691 return status;
695 * mark it as invalid for step operations.
697 creds->sequence = 0;
698 creds->seed = (struct netr_Credential) {{0}};
699 creds->client = (struct netr_Credential) {{0}};
700 creds->server = (struct netr_Credential) {{0}};
702 *_creds = creds;
703 return NT_STATUS_OK;
706 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
707 const struct netlogon_creds_CredentialState *creds1)
709 TALLOC_CTX *frame = talloc_stackframe();
710 struct netlogon_creds_CredentialState *creds2;
711 DATA_BLOB blob1;
712 DATA_BLOB blob2;
713 NTSTATUS status;
714 enum ndr_err_code ndr_err;
715 bool equal;
717 status = netlogon_creds_cli_get(context, frame, &creds2);
718 if (!NT_STATUS_IS_OK(status)) {
719 TALLOC_FREE(frame);
720 return false;
723 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
724 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
725 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
726 TALLOC_FREE(frame);
727 return false;
730 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
731 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
732 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
733 TALLOC_FREE(frame);
734 return false;
737 equal = data_blob_equal_const_time(&blob1, &blob2);
739 TALLOC_FREE(frame);
741 return equal;
744 static NTSTATUS netlogon_creds_cli_store_internal(
745 struct netlogon_creds_cli_context *context,
746 struct netlogon_creds_CredentialState *creds)
748 NTSTATUS status;
749 enum ndr_err_code ndr_err;
750 DATA_BLOB blob;
751 TDB_DATA data;
753 if (DEBUGLEVEL >= 10) {
754 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
757 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
758 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
759 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
760 status = ndr_map_error2ntstatus(ndr_err);
761 return status;
764 data.dptr = blob.data;
765 data.dsize = blob.length;
767 status = dbwrap_store(context->db.ctx,
768 context->db.key_data,
769 data, TDB_REPLACE);
770 TALLOC_FREE(data.dptr);
771 if (!NT_STATUS_IS_OK(status)) {
772 return status;
775 return NT_STATUS_OK;
778 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
779 struct netlogon_creds_CredentialState *creds)
781 NTSTATUS status;
783 if (context->db.locked_state == NULL) {
785 * this was not the result of netlogon_creds_cli_lock*()
787 return NT_STATUS_INVALID_PAGE_PROTECTION;
790 if (context->db.locked_state->creds != creds) {
792 * this was not the result of netlogon_creds_cli_lock*()
794 return NT_STATUS_INVALID_PAGE_PROTECTION;
797 status = netlogon_creds_cli_store_internal(context, creds);
798 return status;
801 static NTSTATUS netlogon_creds_cli_delete_internal(
802 struct netlogon_creds_cli_context *context)
804 NTSTATUS status;
805 status = dbwrap_delete(context->db.ctx, context->db.key_data);
806 return status;
809 NTSTATUS netlogon_creds_cli_delete_lck(
810 struct netlogon_creds_cli_context *context)
812 NTSTATUS status;
814 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
815 return NT_STATUS_NOT_LOCKED;
818 status = netlogon_creds_cli_delete_internal(context);
819 return status;
822 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
823 struct netlogon_creds_CredentialState *creds)
825 NTSTATUS status;
827 if (context->db.locked_state == NULL) {
829 * this was not the result of netlogon_creds_cli_lock*()
831 return NT_STATUS_INVALID_PAGE_PROTECTION;
834 if (context->db.locked_state->creds != creds) {
836 * this was not the result of netlogon_creds_cli_lock*()
838 return NT_STATUS_INVALID_PAGE_PROTECTION;
841 status = netlogon_creds_cli_delete_internal(context);
842 return status;
845 struct netlogon_creds_cli_lock_state {
846 struct netlogon_creds_cli_locked_state *locked_state;
847 struct netlogon_creds_CredentialState *creds;
850 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
852 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
853 struct tevent_context *ev,
854 struct netlogon_creds_cli_context *context)
856 struct tevent_req *req;
857 struct netlogon_creds_cli_lock_state *state;
858 struct netlogon_creds_cli_locked_state *locked_state;
859 struct tevent_req *subreq;
861 req = tevent_req_create(mem_ctx, &state,
862 struct netlogon_creds_cli_lock_state);
863 if (req == NULL) {
864 return NULL;
867 if (context->db.locked_state != NULL) {
868 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
869 return tevent_req_post(req, ev);
872 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
873 if (tevent_req_nomem(locked_state, req)) {
874 return tevent_req_post(req, ev);
876 talloc_set_destructor(locked_state,
877 netlogon_creds_cli_locked_state_destructor);
878 locked_state->context = context;
880 context->db.locked_state = locked_state;
881 state->locked_state = locked_state;
883 if (context->db.g_ctx == NULL) {
884 NTSTATUS status;
886 status = netlogon_creds_cli_get_internal(
887 context, state, &state->creds);
888 if (tevent_req_nterror(req, status)) {
889 return tevent_req_post(req, ev);
892 return req;
895 subreq = g_lock_lock_send(state, ev,
896 context->db.g_ctx,
897 string_term_tdb_data(context->db.key_name),
898 G_LOCK_WRITE,
899 NULL, NULL);
900 if (tevent_req_nomem(subreq, req)) {
901 return tevent_req_post(req, ev);
903 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
905 return req;
908 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
910 struct tevent_req *req =
911 tevent_req_callback_data(subreq,
912 struct tevent_req);
913 struct netlogon_creds_cli_lock_state *state =
914 tevent_req_data(req,
915 struct netlogon_creds_cli_lock_state);
916 NTSTATUS status;
918 status = g_lock_lock_recv(subreq);
919 TALLOC_FREE(subreq);
920 if (tevent_req_nterror(req, status)) {
921 return;
923 state->locked_state->is_glocked = true;
925 status = netlogon_creds_cli_get_internal(state->locked_state->context,
926 state, &state->creds);
927 if (tevent_req_nterror(req, status)) {
928 return;
930 tevent_req_done(req);
933 static NTSTATUS netlogon_creds_cli_get_internal(
934 struct netlogon_creds_cli_context *context,
935 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
937 struct netlogon_creds_cli_fetch_state fstate = {
938 .status = NT_STATUS_INTERNAL_ERROR,
939 .proposed_flags = context->client.proposed_flags,
940 .required_flags = context->client.required_flags,
942 NTSTATUS status;
944 fstate.mem_ctx = mem_ctx;
945 status = dbwrap_parse_record(context->db.ctx,
946 context->db.key_data,
947 netlogon_creds_cli_fetch_parser,
948 &fstate);
949 if (!NT_STATUS_IS_OK(status)) {
950 return status;
952 if (!NT_STATUS_IS_OK(fstate.status)) {
953 return fstate.status;
956 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
957 *pcreds = fstate.creds;
958 return NT_STATUS_OK;
962 * It is really important to try SamLogonEx here,
963 * because multiple processes can talk to the same
964 * domain controller, without using the credential
965 * chain.
967 * With a normal SamLogon call, we must keep the
968 * credentials chain updated and intact between all
969 * users of the machine account (which would imply
970 * cross-node communication for every NTLM logon).
972 * The credentials chain is not per NETLOGON pipe
973 * connection, but globally on the server/client pair
974 * by computer name.
976 * It's also important to use NetlogonValidationSamInfo4 (6),
977 * because it relies on the rpc transport encryption
978 * and avoids using the global netlogon schannel
979 * session key to en/decrypt secret information
980 * like the user_session_key for network logons.
982 * [MS-APDS] 3.1.5.2 NTLM Network Logon
983 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
984 * NETLOGON_NEG_AUTHENTICATED_RPC set together
985 * are the indication that the server supports
986 * NetlogonValidationSamInfo4 (6). And it must only
987 * be used if "SealSecureChannel" is used.
989 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
990 * check is done in netlogon_creds_cli_LogonSamLogon*().
993 context->server.cached_flags = fstate.creds->negotiate_flags;
994 context->server.try_validation6 = true;
995 context->server.try_logon_ex = true;
996 context->server.try_logon_with = true;
998 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
999 context->server.try_validation6 = false;
1000 context->server.try_logon_ex = false;
1002 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1003 context->server.try_validation6 = false;
1006 *pcreds = fstate.creds;
1007 return NT_STATUS_OK;
1010 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
1011 TALLOC_CTX *mem_ctx,
1012 struct netlogon_creds_CredentialState **creds)
1014 struct netlogon_creds_cli_lock_state *state =
1015 tevent_req_data(req,
1016 struct netlogon_creds_cli_lock_state);
1017 NTSTATUS status;
1019 if (tevent_req_is_nterror(req, &status)) {
1020 tevent_req_received(req);
1021 return status;
1024 talloc_steal(state->creds, state->locked_state);
1025 state->locked_state->creds = state->creds;
1026 *creds = talloc_move(mem_ctx, &state->creds);
1027 tevent_req_received(req);
1028 return NT_STATUS_OK;
1031 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
1032 TALLOC_CTX *mem_ctx,
1033 struct netlogon_creds_CredentialState **creds)
1035 TALLOC_CTX *frame = talloc_stackframe();
1036 struct tevent_context *ev;
1037 struct tevent_req *req;
1038 NTSTATUS status = NT_STATUS_NO_MEMORY;
1040 ev = samba_tevent_context_init(frame);
1041 if (ev == NULL) {
1042 goto fail;
1044 req = netlogon_creds_cli_lock_send(frame, ev, context);
1045 if (req == NULL) {
1046 goto fail;
1048 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1049 goto fail;
1051 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
1052 fail:
1053 TALLOC_FREE(frame);
1054 return status;
1057 struct netlogon_creds_cli_lck {
1058 struct netlogon_creds_cli_context *context;
1061 struct netlogon_creds_cli_lck_state {
1062 struct netlogon_creds_cli_lck *lck;
1063 enum netlogon_creds_cli_lck_type type;
1066 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
1067 static int netlogon_creds_cli_lck_destructor(
1068 struct netlogon_creds_cli_lck *lck);
1070 struct tevent_req *netlogon_creds_cli_lck_send(
1071 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1072 struct netlogon_creds_cli_context *context,
1073 enum netlogon_creds_cli_lck_type type)
1075 struct tevent_req *req, *subreq;
1076 struct netlogon_creds_cli_lck_state *state;
1077 enum g_lock_type gtype;
1079 req = tevent_req_create(mem_ctx, &state,
1080 struct netlogon_creds_cli_lck_state);
1081 if (req == NULL) {
1082 return NULL;
1085 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
1086 DBG_DEBUG("context already locked\n");
1087 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
1088 return tevent_req_post(req, ev);
1091 switch (type) {
1092 case NETLOGON_CREDS_CLI_LCK_SHARED:
1093 gtype = G_LOCK_READ;
1094 break;
1095 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
1096 gtype = G_LOCK_WRITE;
1097 break;
1098 default:
1099 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1100 return tevent_req_post(req, ev);
1103 state->lck = talloc(state, struct netlogon_creds_cli_lck);
1104 if (tevent_req_nomem(state->lck, req)) {
1105 return tevent_req_post(req, ev);
1107 state->lck->context = context;
1108 state->type = type;
1110 subreq = g_lock_lock_send(state, ev,
1111 context->db.g_ctx,
1112 string_term_tdb_data(context->db.key_name),
1113 gtype,
1114 NULL, NULL);
1115 if (tevent_req_nomem(subreq, req)) {
1116 return tevent_req_post(req, ev);
1118 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1120 return req;
1123 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1125 struct tevent_req *req = tevent_req_callback_data(
1126 subreq, struct tevent_req);
1127 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1128 req, struct netlogon_creds_cli_lck_state);
1129 NTSTATUS status;
1131 status = g_lock_lock_recv(subreq);
1132 TALLOC_FREE(subreq);
1133 if (tevent_req_nterror(req, status)) {
1134 return;
1137 state->lck->context->db.lock = state->type;
1138 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1140 tevent_req_done(req);
1143 static int netlogon_creds_cli_lck_destructor(
1144 struct netlogon_creds_cli_lck *lck)
1146 struct netlogon_creds_cli_context *ctx = lck->context;
1147 NTSTATUS status;
1149 status = g_lock_unlock(ctx->db.g_ctx,
1150 string_term_tdb_data(ctx->db.key_name));
1151 if (!NT_STATUS_IS_OK(status)) {
1152 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1153 smb_panic("g_lock_unlock failed");
1155 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1156 return 0;
1159 NTSTATUS netlogon_creds_cli_lck_recv(
1160 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1161 struct netlogon_creds_cli_lck **lck)
1163 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1164 req, struct netlogon_creds_cli_lck_state);
1165 NTSTATUS status;
1167 if (tevent_req_is_nterror(req, &status)) {
1168 return status;
1170 *lck = talloc_move(mem_ctx, &state->lck);
1171 return NT_STATUS_OK;
1174 NTSTATUS netlogon_creds_cli_lck(
1175 struct netlogon_creds_cli_context *context,
1176 enum netlogon_creds_cli_lck_type type,
1177 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1179 TALLOC_CTX *frame = talloc_stackframe();
1180 struct tevent_context *ev;
1181 struct tevent_req *req;
1182 NTSTATUS status = NT_STATUS_NO_MEMORY;
1184 ev = samba_tevent_context_init(frame);
1185 if (ev == NULL) {
1186 goto fail;
1188 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1189 if (req == NULL) {
1190 goto fail;
1192 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1193 goto fail;
1195 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1196 fail:
1197 TALLOC_FREE(frame);
1198 return status;
1201 struct netlogon_creds_cli_auth_state {
1202 struct tevent_context *ev;
1203 struct netlogon_creds_cli_context *context;
1204 struct dcerpc_binding_handle *binding_handle;
1205 uint8_t num_nt_hashes;
1206 uint8_t idx_nt_hashes;
1207 const struct samr_Password * const *nt_hashes;
1208 const struct samr_Password *used_nt_hash;
1209 char *srv_name_slash;
1210 uint32_t current_flags;
1211 struct netr_Credential client_challenge;
1212 struct netr_Credential server_challenge;
1213 struct netlogon_creds_CredentialState *creds;
1214 struct netr_Credential client_credential;
1215 struct netr_Credential server_credential;
1216 uint32_t rid;
1217 bool try_auth3;
1218 bool try_auth2;
1219 bool require_auth2;
1222 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1224 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1225 struct tevent_context *ev,
1226 struct netlogon_creds_cli_context *context,
1227 struct dcerpc_binding_handle *b,
1228 uint8_t num_nt_hashes,
1229 const struct samr_Password * const *nt_hashes)
1231 struct tevent_req *req;
1232 struct netlogon_creds_cli_auth_state *state;
1233 NTSTATUS status;
1235 req = tevent_req_create(mem_ctx, &state,
1236 struct netlogon_creds_cli_auth_state);
1237 if (req == NULL) {
1238 return NULL;
1241 state->ev = ev;
1242 state->context = context;
1243 state->binding_handle = b;
1244 if (num_nt_hashes < 1) {
1245 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1246 return tevent_req_post(req, ev);
1248 if (num_nt_hashes > 4) {
1249 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1250 return tevent_req_post(req, ev);
1253 state->num_nt_hashes = num_nt_hashes;
1254 state->idx_nt_hashes = 0;
1255 state->nt_hashes = nt_hashes;
1257 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1258 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1259 return tevent_req_post(req, ev);
1262 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1263 context->server.computer);
1264 if (tevent_req_nomem(state->srv_name_slash, req)) {
1265 return tevent_req_post(req, ev);
1268 state->try_auth3 = true;
1269 state->try_auth2 = true;
1271 if (context->client.required_flags != 0) {
1272 state->require_auth2 = true;
1275 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1276 state->current_flags = context->client.proposed_flags;
1278 status = dbwrap_purge(state->context->db.ctx,
1279 state->context->db.key_data);
1280 if (tevent_req_nterror(req, status)) {
1281 return tevent_req_post(req, ev);
1284 netlogon_creds_cli_auth_challenge_start(req);
1285 if (!tevent_req_is_in_progress(req)) {
1286 return tevent_req_post(req, ev);
1289 return req;
1292 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1294 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1296 struct netlogon_creds_cli_auth_state *state =
1297 tevent_req_data(req,
1298 struct netlogon_creds_cli_auth_state);
1299 struct tevent_req *subreq;
1301 TALLOC_FREE(state->creds);
1303 netlogon_creds_random_challenge(&state->client_challenge);
1305 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1306 state->binding_handle,
1307 state->srv_name_slash,
1308 state->context->client.computer,
1309 &state->client_challenge,
1310 &state->server_challenge);
1311 if (tevent_req_nomem(subreq, req)) {
1312 return;
1314 tevent_req_set_callback(subreq,
1315 netlogon_creds_cli_auth_challenge_done,
1316 req);
1319 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1321 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1323 struct tevent_req *req =
1324 tevent_req_callback_data(subreq,
1325 struct tevent_req);
1326 struct netlogon_creds_cli_auth_state *state =
1327 tevent_req_data(req,
1328 struct netlogon_creds_cli_auth_state);
1329 NTSTATUS status;
1330 NTSTATUS result;
1332 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1333 TALLOC_FREE(subreq);
1334 if (tevent_req_nterror(req, status)) {
1335 return;
1337 if (tevent_req_nterror(req, result)) {
1338 return;
1341 if (!state->try_auth3 && !state->try_auth2) {
1342 state->current_flags = 0;
1345 /* Calculate the session key and client credentials */
1347 state->creds = netlogon_creds_client_init(state,
1348 state->context->client.account,
1349 state->context->client.computer,
1350 state->context->client.type,
1351 &state->client_challenge,
1352 &state->server_challenge,
1353 state->used_nt_hash,
1354 &state->client_credential,
1355 state->current_flags);
1356 if (tevent_req_nomem(state->creds, req)) {
1357 return;
1360 if (state->try_auth3) {
1361 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1362 state->binding_handle,
1363 state->srv_name_slash,
1364 state->context->client.account,
1365 state->context->client.type,
1366 state->context->client.computer,
1367 &state->client_credential,
1368 &state->server_credential,
1369 &state->creds->negotiate_flags,
1370 &state->rid);
1371 if (tevent_req_nomem(subreq, req)) {
1372 return;
1374 } else if (state->try_auth2) {
1375 state->rid = 0;
1377 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1378 state->binding_handle,
1379 state->srv_name_slash,
1380 state->context->client.account,
1381 state->context->client.type,
1382 state->context->client.computer,
1383 &state->client_credential,
1384 &state->server_credential,
1385 &state->creds->negotiate_flags);
1386 if (tevent_req_nomem(subreq, req)) {
1387 return;
1389 } else {
1390 state->rid = 0;
1392 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1393 state->binding_handle,
1394 state->srv_name_slash,
1395 state->context->client.account,
1396 state->context->client.type,
1397 state->context->client.computer,
1398 &state->client_credential,
1399 &state->server_credential);
1400 if (tevent_req_nomem(subreq, req)) {
1401 return;
1404 tevent_req_set_callback(subreq,
1405 netlogon_creds_cli_auth_srvauth_done,
1406 req);
1409 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1411 struct tevent_req *req =
1412 tevent_req_callback_data(subreq,
1413 struct tevent_req);
1414 struct netlogon_creds_cli_auth_state *state =
1415 tevent_req_data(req,
1416 struct netlogon_creds_cli_auth_state);
1417 NTSTATUS status;
1418 NTSTATUS result;
1419 bool ok;
1420 enum ndr_err_code ndr_err;
1421 DATA_BLOB blob;
1422 TDB_DATA data;
1423 bool downgraded;
1425 if (state->try_auth3) {
1426 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1427 &result);
1428 TALLOC_FREE(subreq);
1429 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1430 state->try_auth3 = false;
1431 netlogon_creds_cli_auth_challenge_start(req);
1432 return;
1434 if (tevent_req_nterror(req, status)) {
1435 return;
1437 } else if (state->try_auth2) {
1438 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1439 &result);
1440 TALLOC_FREE(subreq);
1441 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1442 state->try_auth2 = false;
1443 if (state->require_auth2) {
1444 status = NT_STATUS_DOWNGRADE_DETECTED;
1445 tevent_req_nterror(req, status);
1446 return;
1448 netlogon_creds_cli_auth_challenge_start(req);
1449 return;
1451 if (tevent_req_nterror(req, status)) {
1452 return;
1454 } else {
1455 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1456 &result);
1457 TALLOC_FREE(subreq);
1458 if (tevent_req_nterror(req, status)) {
1459 return;
1463 if (!NT_STATUS_IS_OK(result) &&
1464 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1466 tevent_req_nterror(req, result);
1467 return;
1470 downgraded = netlogon_creds_cli_downgraded(
1471 state->creds->negotiate_flags,
1472 state->context->client.proposed_flags,
1473 state->context->client.required_flags);
1474 if (downgraded) {
1475 if (NT_STATUS_IS_OK(result)) {
1476 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1477 return;
1479 tevent_req_nterror(req, result);
1480 return;
1483 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1484 uint32_t tmp_flags = state->context->client.proposed_flags;
1485 if ((state->current_flags == tmp_flags) &&
1486 (state->creds->negotiate_flags != tmp_flags))
1489 * lets retry with the negotiated flags
1491 state->current_flags = state->creds->negotiate_flags;
1492 netlogon_creds_cli_auth_challenge_start(req);
1493 return;
1496 state->idx_nt_hashes += 1;
1497 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1499 * we already retried, giving up...
1501 tevent_req_nterror(req, result);
1502 return;
1506 * lets retry with the old nt hash.
1508 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1509 state->current_flags = state->context->client.proposed_flags;
1510 netlogon_creds_cli_auth_challenge_start(req);
1511 return;
1514 ok = netlogon_creds_client_check(state->creds,
1515 &state->server_credential);
1516 if (!ok) {
1517 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1518 return;
1521 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1522 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1524 status = ndr_map_error2ntstatus(ndr_err);
1525 tevent_req_nterror(req, status);
1526 return;
1529 data.dptr = blob.data;
1530 data.dsize = blob.length;
1532 status = dbwrap_store(state->context->db.ctx,
1533 state->context->db.key_data,
1534 data, TDB_REPLACE);
1535 if (tevent_req_nterror(req, status)) {
1536 return;
1539 tevent_req_done(req);
1542 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1543 uint8_t *idx_nt_hashes)
1545 struct netlogon_creds_cli_auth_state *state =
1546 tevent_req_data(req,
1547 struct netlogon_creds_cli_auth_state);
1548 NTSTATUS status;
1550 *idx_nt_hashes = 0;
1552 if (tevent_req_is_nterror(req, &status)) {
1553 tevent_req_received(req);
1554 return status;
1557 *idx_nt_hashes = state->idx_nt_hashes;
1558 tevent_req_received(req);
1559 return NT_STATUS_OK;
1562 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1563 struct dcerpc_binding_handle *b,
1564 uint8_t num_nt_hashes,
1565 const struct samr_Password * const *nt_hashes,
1566 uint8_t *idx_nt_hashes)
1568 TALLOC_CTX *frame = talloc_stackframe();
1569 struct tevent_context *ev;
1570 struct tevent_req *req;
1571 NTSTATUS status = NT_STATUS_NO_MEMORY;
1573 *idx_nt_hashes = 0;
1575 ev = samba_tevent_context_init(frame);
1576 if (ev == NULL) {
1577 goto fail;
1579 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1580 num_nt_hashes, nt_hashes);
1581 if (req == NULL) {
1582 goto fail;
1584 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1585 goto fail;
1587 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1588 fail:
1589 TALLOC_FREE(frame);
1590 return status;
1593 struct netlogon_creds_cli_check_state {
1594 struct tevent_context *ev;
1595 struct netlogon_creds_cli_context *context;
1596 struct dcerpc_binding_handle *binding_handle;
1598 char *srv_name_slash;
1600 union netr_Capabilities caps;
1602 struct netlogon_creds_CredentialState *creds;
1603 struct netr_Authenticator req_auth;
1604 struct netr_Authenticator rep_auth;
1607 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1608 NTSTATUS status);
1609 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1611 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1612 struct tevent_context *ev,
1613 struct netlogon_creds_cli_context *context,
1614 struct dcerpc_binding_handle *b)
1616 struct tevent_req *req;
1617 struct netlogon_creds_cli_check_state *state;
1618 struct tevent_req *subreq;
1619 enum dcerpc_AuthType auth_type;
1620 enum dcerpc_AuthLevel auth_level;
1621 NTSTATUS status;
1623 req = tevent_req_create(mem_ctx, &state,
1624 struct netlogon_creds_cli_check_state);
1625 if (req == NULL) {
1626 return NULL;
1629 state->ev = ev;
1630 state->context = context;
1631 state->binding_handle = b;
1633 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1634 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1635 return tevent_req_post(req, ev);
1638 status = netlogon_creds_cli_get_internal(context, state,
1639 &state->creds);
1640 if (tevent_req_nterror(req, status)) {
1641 return tevent_req_post(req, ev);
1644 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1645 context->server.computer);
1646 if (tevent_req_nomem(state->srv_name_slash, req)) {
1647 return tevent_req_post(req, ev);
1650 dcerpc_binding_handle_auth_info(state->binding_handle,
1651 &auth_type, &auth_level);
1653 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1654 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1655 return tevent_req_post(req, ev);
1658 switch (auth_level) {
1659 case DCERPC_AUTH_LEVEL_INTEGRITY:
1660 case DCERPC_AUTH_LEVEL_PRIVACY:
1661 break;
1662 default:
1663 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1664 return tevent_req_post(req, ev);
1668 * we defer all callbacks in order to cleanup
1669 * the database record.
1671 tevent_req_defer_callback(req, state->ev);
1673 status = netlogon_creds_client_authenticator(state->creds,
1674 &state->req_auth);
1675 if (tevent_req_nterror(req, status)) {
1676 return tevent_req_post(req, ev);
1678 ZERO_STRUCT(state->rep_auth);
1680 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1681 state->binding_handle,
1682 state->srv_name_slash,
1683 state->context->client.computer,
1684 &state->req_auth,
1685 &state->rep_auth,
1687 &state->caps);
1688 if (tevent_req_nomem(subreq, req)) {
1689 return tevent_req_post(req, ev);
1692 tevent_req_set_callback(subreq,
1693 netlogon_creds_cli_check_caps,
1694 req);
1696 return req;
1699 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1700 NTSTATUS status)
1702 struct netlogon_creds_cli_check_state *state =
1703 tevent_req_data(req,
1704 struct netlogon_creds_cli_check_state);
1706 if (state->creds == NULL) {
1707 return;
1710 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1711 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1712 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1713 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1714 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1715 TALLOC_FREE(state->creds);
1716 return;
1719 netlogon_creds_cli_delete_lck(state->context);
1720 TALLOC_FREE(state->creds);
1723 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1725 struct tevent_req *req =
1726 tevent_req_callback_data(subreq,
1727 struct tevent_req);
1728 struct netlogon_creds_cli_check_state *state =
1729 tevent_req_data(req,
1730 struct netlogon_creds_cli_check_state);
1731 NTSTATUS status;
1732 NTSTATUS result;
1733 bool ok;
1735 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1736 &result);
1737 TALLOC_FREE(subreq);
1738 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1740 * Note that the negotiated flags are already checked
1741 * for our required flags after the ServerAuthenticate3/2 call.
1743 uint32_t negotiated = state->creds->negotiate_flags;
1745 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1747 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1748 * already, we expect this to work!
1750 status = NT_STATUS_DOWNGRADE_DETECTED;
1751 tevent_req_nterror(req, status);
1752 netlogon_creds_cli_check_cleanup(req, status);
1753 return;
1756 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1758 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1759 * we expect this to work at least as far as the
1760 * NOT_SUPPORTED error handled below!
1762 * NT 4.0 and Old Samba servers are not
1763 * allowed without "require strong key = no"
1765 status = NT_STATUS_DOWNGRADE_DETECTED;
1766 tevent_req_nterror(req, status);
1767 netlogon_creds_cli_check_cleanup(req, status);
1768 return;
1772 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1773 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1774 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1776 * This is needed against NT 4.0 and old Samba servers.
1778 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1779 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1780 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1781 * with the next request as the sequence number processing
1782 * gets out of sync.
1784 netlogon_creds_cli_check_cleanup(req, status);
1785 tevent_req_done(req);
1786 return;
1788 if (tevent_req_nterror(req, status)) {
1789 netlogon_creds_cli_check_cleanup(req, status);
1790 return;
1793 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1795 * Note that the negotiated flags are already checked
1796 * for our required flags after the ServerAuthenticate3/2 call.
1798 uint32_t negotiated = state->creds->negotiate_flags;
1800 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1802 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1803 * already, we expect this to work!
1805 status = NT_STATUS_DOWNGRADE_DETECTED;
1806 tevent_req_nterror(req, status);
1807 netlogon_creds_cli_check_cleanup(req, status);
1808 return;
1812 * This is ok, the server does not support
1813 * NETLOGON_NEG_SUPPORTS_AES.
1815 * netr_LogonGetCapabilities() was
1816 * netr_LogonDummyRoutine1() before
1817 * NETLOGON_NEG_SUPPORTS_AES was invented.
1819 netlogon_creds_cli_check_cleanup(req, result);
1820 tevent_req_done(req);
1821 return;
1824 ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
1825 if (!ok) {
1826 status = NT_STATUS_ACCESS_DENIED;
1827 tevent_req_nterror(req, status);
1828 netlogon_creds_cli_check_cleanup(req, status);
1829 return;
1832 if (tevent_req_nterror(req, result)) {
1833 netlogon_creds_cli_check_cleanup(req, result);
1834 return;
1837 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
1838 status = NT_STATUS_DOWNGRADE_DETECTED;
1839 tevent_req_nterror(req, status);
1840 netlogon_creds_cli_check_cleanup(req, status);
1841 return;
1845 * This is the key check that makes this check secure. If we
1846 * get OK here (rather than NOT_SUPPORTED), then the server
1847 * did support AES. If the server only proposed STRONG_KEYS
1848 * and not AES, then it should have failed with
1849 * NOT_IMPLEMENTED. We always send AES as a client, so the
1850 * server should always have returned it.
1852 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1853 status = NT_STATUS_DOWNGRADE_DETECTED;
1854 tevent_req_nterror(req, status);
1855 netlogon_creds_cli_check_cleanup(req, status);
1856 return;
1859 status = netlogon_creds_cli_store_internal(state->context,
1860 state->creds);
1861 if (tevent_req_nterror(req, status)) {
1862 return;
1865 tevent_req_done(req);
1868 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
1869 union netr_Capabilities *capabilities)
1871 struct netlogon_creds_cli_check_state *state = tevent_req_data(
1872 req, struct netlogon_creds_cli_check_state);
1873 NTSTATUS status;
1875 if (tevent_req_is_nterror(req, &status)) {
1876 netlogon_creds_cli_check_cleanup(req, status);
1877 tevent_req_received(req);
1878 return status;
1881 if (capabilities != NULL) {
1882 *capabilities = state->caps;
1885 tevent_req_received(req);
1886 return NT_STATUS_OK;
1889 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1890 struct dcerpc_binding_handle *b,
1891 union netr_Capabilities *capabilities)
1893 TALLOC_CTX *frame = talloc_stackframe();
1894 struct tevent_context *ev;
1895 struct tevent_req *req;
1896 NTSTATUS status = NT_STATUS_NO_MEMORY;
1898 ev = samba_tevent_context_init(frame);
1899 if (ev == NULL) {
1900 goto fail;
1902 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1903 if (req == NULL) {
1904 goto fail;
1906 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1907 goto fail;
1909 status = netlogon_creds_cli_check_recv(req, capabilities);
1910 fail:
1911 TALLOC_FREE(frame);
1912 return status;
1915 struct netlogon_creds_cli_ServerPasswordSet_state {
1916 struct tevent_context *ev;
1917 struct netlogon_creds_cli_context *context;
1918 struct dcerpc_binding_handle *binding_handle;
1919 uint32_t old_timeout;
1921 char *srv_name_slash;
1922 enum dcerpc_AuthType auth_type;
1923 enum dcerpc_AuthLevel auth_level;
1925 struct samr_CryptPassword samr_crypt_password;
1926 struct netr_CryptPassword netr_crypt_password;
1927 struct samr_Password samr_password;
1929 struct netlogon_creds_CredentialState *creds;
1930 struct netlogon_creds_CredentialState tmp_creds;
1931 struct netr_Authenticator req_auth;
1932 struct netr_Authenticator rep_auth;
1935 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1936 NTSTATUS status);
1937 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1939 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1940 struct tevent_context *ev,
1941 struct netlogon_creds_cli_context *context,
1942 struct dcerpc_binding_handle *b,
1943 const DATA_BLOB *new_password,
1944 const uint32_t *new_version)
1946 struct tevent_req *req;
1947 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1948 struct tevent_req *subreq;
1949 bool ok;
1951 req = tevent_req_create(mem_ctx, &state,
1952 struct netlogon_creds_cli_ServerPasswordSet_state);
1953 if (req == NULL) {
1954 return NULL;
1957 state->ev = ev;
1958 state->context = context;
1959 state->binding_handle = b;
1961 if (new_password->length < 14) {
1962 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1963 return tevent_req_post(req, ev);
1967 * netr_ServerPasswordSet
1969 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1972 * netr_ServerPasswordSet2
1974 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1975 new_password);
1976 if (!ok) {
1977 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1978 return tevent_req_post(req, ev);
1981 if (new_version != NULL) {
1982 struct NL_PASSWORD_VERSION version;
1983 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1984 uint32_t ofs = 512 - len;
1985 uint8_t *p;
1987 if (len > 500) {
1988 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1989 return tevent_req_post(req, ev);
1991 ofs -= 12;
1993 version.ReservedField = 0;
1994 version.PasswordVersionNumber = *new_version;
1995 version.PasswordVersionPresent =
1996 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1998 p = state->samr_crypt_password.data + ofs;
1999 SIVAL(p, 0, version.ReservedField);
2000 SIVAL(p, 4, version.PasswordVersionNumber);
2001 SIVAL(p, 8, version.PasswordVersionPresent);
2004 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2005 context->server.computer);
2006 if (tevent_req_nomem(state->srv_name_slash, req)) {
2007 return tevent_req_post(req, ev);
2010 dcerpc_binding_handle_auth_info(state->binding_handle,
2011 &state->auth_type,
2012 &state->auth_level);
2014 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2015 state->context);
2016 if (tevent_req_nomem(subreq, req)) {
2017 return tevent_req_post(req, ev);
2020 tevent_req_set_callback(subreq,
2021 netlogon_creds_cli_ServerPasswordSet_locked,
2022 req);
2024 return req;
2027 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2028 NTSTATUS status)
2030 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2031 tevent_req_data(req,
2032 struct netlogon_creds_cli_ServerPasswordSet_state);
2034 if (state->creds == NULL) {
2035 return;
2038 dcerpc_binding_handle_set_timeout(state->binding_handle,
2039 state->old_timeout);
2041 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2042 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2043 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2044 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2045 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2046 TALLOC_FREE(state->creds);
2047 return;
2050 netlogon_creds_cli_delete(state->context, state->creds);
2051 TALLOC_FREE(state->creds);
2054 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
2056 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
2058 struct tevent_req *req =
2059 tevent_req_callback_data(subreq,
2060 struct tevent_req);
2061 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2062 tevent_req_data(req,
2063 struct netlogon_creds_cli_ServerPasswordSet_state);
2064 NTSTATUS status;
2066 status = netlogon_creds_cli_lock_recv(subreq, state,
2067 &state->creds);
2068 TALLOC_FREE(subreq);
2069 if (tevent_req_nterror(req, status)) {
2070 return;
2073 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2074 switch (state->auth_level) {
2075 case DCERPC_AUTH_LEVEL_INTEGRITY:
2076 case DCERPC_AUTH_LEVEL_PRIVACY:
2077 break;
2078 default:
2079 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2080 return;
2082 } else {
2083 uint32_t tmp = state->creds->negotiate_flags;
2085 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2087 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2088 * it should be used, which means
2089 * we had a chance to verify no downgrade
2090 * happened.
2092 * This relies on netlogon_creds_cli_check*
2093 * being called before, as first request after
2094 * the DCERPC bind.
2096 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2097 return;
2101 state->old_timeout = dcerpc_binding_handle_set_timeout(
2102 state->binding_handle, 600000);
2105 * we defer all callbacks in order to cleanup
2106 * the database record.
2108 tevent_req_defer_callback(req, state->ev);
2110 state->tmp_creds = *state->creds;
2111 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2112 &state->req_auth);
2113 if (tevent_req_nterror(req, status)) {
2114 return;
2116 ZERO_STRUCT(state->rep_auth);
2118 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2120 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
2121 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
2122 state->samr_crypt_password.data,
2123 516);
2124 if (tevent_req_nterror(req, status)) {
2125 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2126 return;
2128 } else {
2129 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
2130 state->samr_crypt_password.data,
2131 516);
2132 if (tevent_req_nterror(req, status)) {
2133 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2134 return;
2138 memcpy(state->netr_crypt_password.data,
2139 state->samr_crypt_password.data, 512);
2140 state->netr_crypt_password.length =
2141 IVAL(state->samr_crypt_password.data, 512);
2143 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2144 state->binding_handle,
2145 state->srv_name_slash,
2146 state->tmp_creds.account_name,
2147 state->tmp_creds.secure_channel_type,
2148 state->tmp_creds.computer_name,
2149 &state->req_auth,
2150 &state->rep_auth,
2151 &state->netr_crypt_password);
2152 if (tevent_req_nomem(subreq, req)) {
2153 status = NT_STATUS_NO_MEMORY;
2154 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2155 return;
2157 } else {
2158 status = netlogon_creds_des_encrypt(&state->tmp_creds,
2159 &state->samr_password);
2160 if (tevent_req_nterror(req, status)) {
2161 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2162 return;
2165 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2166 state->binding_handle,
2167 state->srv_name_slash,
2168 state->tmp_creds.account_name,
2169 state->tmp_creds.secure_channel_type,
2170 state->tmp_creds.computer_name,
2171 &state->req_auth,
2172 &state->rep_auth,
2173 &state->samr_password);
2174 if (tevent_req_nomem(subreq, req)) {
2175 status = NT_STATUS_NO_MEMORY;
2176 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2177 return;
2181 tevent_req_set_callback(subreq,
2182 netlogon_creds_cli_ServerPasswordSet_done,
2183 req);
2186 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2188 struct tevent_req *req =
2189 tevent_req_callback_data(subreq,
2190 struct tevent_req);
2191 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2192 tevent_req_data(req,
2193 struct netlogon_creds_cli_ServerPasswordSet_state);
2194 NTSTATUS status;
2195 NTSTATUS result;
2196 bool ok;
2198 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2199 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2200 &result);
2201 TALLOC_FREE(subreq);
2202 if (tevent_req_nterror(req, status)) {
2203 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2204 return;
2206 } else {
2207 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2208 &result);
2209 TALLOC_FREE(subreq);
2210 if (tevent_req_nterror(req, status)) {
2211 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2212 return;
2216 ok = netlogon_creds_client_check(&state->tmp_creds,
2217 &state->rep_auth.cred);
2218 if (!ok) {
2219 status = NT_STATUS_ACCESS_DENIED;
2220 tevent_req_nterror(req, status);
2221 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2222 return;
2225 if (tevent_req_nterror(req, result)) {
2226 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2227 return;
2230 dcerpc_binding_handle_set_timeout(state->binding_handle,
2231 state->old_timeout);
2233 *state->creds = state->tmp_creds;
2234 status = netlogon_creds_cli_store(state->context,
2235 state->creds);
2236 TALLOC_FREE(state->creds);
2237 if (tevent_req_nterror(req, status)) {
2238 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2239 return;
2242 tevent_req_done(req);
2245 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2247 NTSTATUS status;
2249 if (tevent_req_is_nterror(req, &status)) {
2250 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2251 tevent_req_received(req);
2252 return status;
2255 tevent_req_received(req);
2256 return NT_STATUS_OK;
2259 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2260 struct netlogon_creds_cli_context *context,
2261 struct dcerpc_binding_handle *b,
2262 const DATA_BLOB *new_password,
2263 const uint32_t *new_version)
2265 TALLOC_CTX *frame = talloc_stackframe();
2266 struct tevent_context *ev;
2267 struct tevent_req *req;
2268 NTSTATUS status = NT_STATUS_NO_MEMORY;
2270 ev = samba_tevent_context_init(frame);
2271 if (ev == NULL) {
2272 goto fail;
2274 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2275 new_password,
2276 new_version);
2277 if (req == NULL) {
2278 goto fail;
2280 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2281 goto fail;
2283 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2284 fail:
2285 TALLOC_FREE(frame);
2286 return status;
2289 struct netlogon_creds_cli_LogonSamLogon_state {
2290 struct tevent_context *ev;
2291 struct netlogon_creds_cli_context *context;
2292 struct dcerpc_binding_handle *binding_handle;
2294 char *srv_name_slash;
2296 enum netr_LogonInfoClass logon_level;
2297 const union netr_LogonLevel *const_logon;
2298 union netr_LogonLevel *logon;
2299 uint32_t flags;
2301 uint16_t validation_level;
2302 union netr_Validation *validation;
2303 uint8_t authoritative;
2306 * do we need encryption at the application layer?
2308 bool user_encrypt;
2309 bool try_logon_ex;
2310 bool try_validation6;
2313 * the read only credentials before we started the operation
2314 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2316 struct netlogon_creds_CredentialState *ro_creds;
2319 * The (locked) credentials used for the credential chain
2320 * used for netr_LogonSamLogonWithFlags() or
2321 * netr_LogonSamLogonWith().
2323 struct netlogon_creds_CredentialState *lk_creds;
2326 * While we have locked the global credentials (lk_creds above)
2327 * we operate an a temporary copy, because a server
2328 * may not support netr_LogonSamLogonWithFlags() and
2329 * didn't process our netr_Authenticator, so we need to
2330 * restart from lk_creds.
2332 struct netlogon_creds_CredentialState tmp_creds;
2333 struct netr_Authenticator req_auth;
2334 struct netr_Authenticator rep_auth;
2337 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2338 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2339 NTSTATUS status);
2341 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2342 struct tevent_context *ev,
2343 struct netlogon_creds_cli_context *context,
2344 struct dcerpc_binding_handle *b,
2345 enum netr_LogonInfoClass logon_level,
2346 const union netr_LogonLevel *logon,
2347 uint32_t flags)
2349 struct tevent_req *req;
2350 struct netlogon_creds_cli_LogonSamLogon_state *state;
2352 req = tevent_req_create(mem_ctx, &state,
2353 struct netlogon_creds_cli_LogonSamLogon_state);
2354 if (req == NULL) {
2355 return NULL;
2358 state->ev = ev;
2359 state->context = context;
2360 state->binding_handle = b;
2362 state->logon_level = logon_level;
2363 state->const_logon = logon;
2364 state->flags = flags;
2366 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2367 context->server.computer);
2368 if (tevent_req_nomem(state->srv_name_slash, req)) {
2369 return tevent_req_post(req, ev);
2372 switch (logon_level) {
2373 case NetlogonInteractiveInformation:
2374 case NetlogonInteractiveTransitiveInformation:
2375 case NetlogonServiceInformation:
2376 case NetlogonServiceTransitiveInformation:
2377 case NetlogonGenericInformation:
2378 state->user_encrypt = true;
2379 break;
2381 case NetlogonNetworkInformation:
2382 case NetlogonNetworkTransitiveInformation:
2383 break;
2386 state->validation = talloc_zero(state, union netr_Validation);
2387 if (tevent_req_nomem(state->validation, req)) {
2388 return tevent_req_post(req, ev);
2391 netlogon_creds_cli_LogonSamLogon_start(req);
2392 if (!tevent_req_is_in_progress(req)) {
2393 return tevent_req_post(req, ev);
2397 * we defer all callbacks in order to cleanup
2398 * the database record.
2400 tevent_req_defer_callback(req, state->ev);
2401 return req;
2404 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2405 NTSTATUS status)
2407 struct netlogon_creds_cli_LogonSamLogon_state *state =
2408 tevent_req_data(req,
2409 struct netlogon_creds_cli_LogonSamLogon_state);
2411 if (state->lk_creds == NULL) {
2412 return;
2415 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2417 * This is a hack to recover from a bug in old
2418 * Samba servers, when LogonSamLogonEx() fails:
2420 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2422 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2424 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2425 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2426 * If the sign/seal check fails.
2428 * In that case we need to cleanup the netlogon session.
2430 * It's the job of the caller to disconnect the current
2431 * connection, if netlogon_creds_cli_LogonSamLogon()
2432 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2434 if (!state->context->server.try_logon_with) {
2435 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2439 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2440 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2441 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2442 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2443 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2444 TALLOC_FREE(state->lk_creds);
2445 return;
2448 netlogon_creds_cli_delete(state->context, state->lk_creds);
2449 TALLOC_FREE(state->lk_creds);
2452 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2454 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2456 struct netlogon_creds_cli_LogonSamLogon_state *state =
2457 tevent_req_data(req,
2458 struct netlogon_creds_cli_LogonSamLogon_state);
2459 struct tevent_req *subreq;
2460 NTSTATUS status;
2461 enum dcerpc_AuthType auth_type;
2462 enum dcerpc_AuthLevel auth_level;
2464 TALLOC_FREE(state->ro_creds);
2465 TALLOC_FREE(state->logon);
2466 ZERO_STRUCTP(state->validation);
2468 dcerpc_binding_handle_auth_info(state->binding_handle,
2469 &auth_type, &auth_level);
2471 state->try_logon_ex = state->context->server.try_logon_ex;
2472 state->try_validation6 = state->context->server.try_validation6;
2474 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2475 state->try_logon_ex = false;
2478 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2479 state->try_validation6 = false;
2482 if (state->try_logon_ex) {
2483 if (state->try_validation6) {
2484 state->validation_level = 6;
2485 } else {
2486 state->validation_level = 3;
2487 state->user_encrypt = true;
2490 state->logon = netlogon_creds_shallow_copy_logon(state,
2491 state->logon_level,
2492 state->const_logon);
2493 if (tevent_req_nomem(state->logon, req)) {
2494 status = NT_STATUS_NO_MEMORY;
2495 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2496 return;
2499 if (state->user_encrypt) {
2500 status = netlogon_creds_cli_get(state->context,
2501 state,
2502 &state->ro_creds);
2503 if (!NT_STATUS_IS_OK(status)) {
2504 status = NT_STATUS_ACCESS_DENIED;
2505 tevent_req_nterror(req, status);
2506 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2507 return;
2510 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2511 state->logon_level,
2512 state->logon);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 status = NT_STATUS_ACCESS_DENIED;
2515 tevent_req_nterror(req, status);
2516 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2517 return;
2521 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2522 state->binding_handle,
2523 state->srv_name_slash,
2524 state->context->client.computer,
2525 state->logon_level,
2526 state->logon,
2527 state->validation_level,
2528 state->validation,
2529 &state->authoritative,
2530 &state->flags);
2531 if (tevent_req_nomem(subreq, req)) {
2532 status = NT_STATUS_NO_MEMORY;
2533 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2534 return;
2536 tevent_req_set_callback(subreq,
2537 netlogon_creds_cli_LogonSamLogon_done,
2538 req);
2539 return;
2542 if (state->lk_creds == NULL) {
2543 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2544 state->context);
2545 if (tevent_req_nomem(subreq, req)) {
2546 status = NT_STATUS_NO_MEMORY;
2547 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2548 return;
2550 tevent_req_set_callback(subreq,
2551 netlogon_creds_cli_LogonSamLogon_done,
2552 req);
2553 return;
2556 state->tmp_creds = *state->lk_creds;
2557 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2558 &state->req_auth);
2559 if (tevent_req_nterror(req, status)) {
2560 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2561 return;
2563 ZERO_STRUCT(state->rep_auth);
2565 state->logon = netlogon_creds_shallow_copy_logon(state,
2566 state->logon_level,
2567 state->const_logon);
2568 if (tevent_req_nomem(state->logon, req)) {
2569 status = NT_STATUS_NO_MEMORY;
2570 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2571 return;
2574 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2575 state->logon_level,
2576 state->logon);
2577 if (tevent_req_nterror(req, status)) {
2578 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2579 return;
2582 state->validation_level = 3;
2584 if (state->context->server.try_logon_with) {
2585 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2586 state->binding_handle,
2587 state->srv_name_slash,
2588 state->context->client.computer,
2589 &state->req_auth,
2590 &state->rep_auth,
2591 state->logon_level,
2592 state->logon,
2593 state->validation_level,
2594 state->validation,
2595 &state->authoritative,
2596 &state->flags);
2597 if (tevent_req_nomem(subreq, req)) {
2598 status = NT_STATUS_NO_MEMORY;
2599 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2600 return;
2602 } else {
2603 state->flags = 0;
2605 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2606 state->binding_handle,
2607 state->srv_name_slash,
2608 state->context->client.computer,
2609 &state->req_auth,
2610 &state->rep_auth,
2611 state->logon_level,
2612 state->logon,
2613 state->validation_level,
2614 state->validation,
2615 &state->authoritative);
2616 if (tevent_req_nomem(subreq, req)) {
2617 status = NT_STATUS_NO_MEMORY;
2618 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2619 return;
2623 tevent_req_set_callback(subreq,
2624 netlogon_creds_cli_LogonSamLogon_done,
2625 req);
2628 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2630 struct tevent_req *req =
2631 tevent_req_callback_data(subreq,
2632 struct tevent_req);
2633 struct netlogon_creds_cli_LogonSamLogon_state *state =
2634 tevent_req_data(req,
2635 struct netlogon_creds_cli_LogonSamLogon_state);
2636 NTSTATUS status;
2637 NTSTATUS result;
2638 bool ok;
2640 if (state->try_logon_ex) {
2641 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2642 state->validation,
2643 &result);
2644 TALLOC_FREE(subreq);
2645 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2646 state->context->server.try_validation6 = false;
2647 state->context->server.try_logon_ex = false;
2648 netlogon_creds_cli_LogonSamLogon_start(req);
2649 return;
2651 if (tevent_req_nterror(req, status)) {
2652 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2653 return;
2656 if ((state->validation_level == 6) &&
2657 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2658 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2659 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2661 state->context->server.try_validation6 = false;
2662 netlogon_creds_cli_LogonSamLogon_start(req);
2663 return;
2666 if (tevent_req_nterror(req, result)) {
2667 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2668 return;
2671 if (state->ro_creds == NULL) {
2672 tevent_req_done(req);
2673 return;
2676 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2677 if (!ok) {
2679 * We got a race, lets retry with on authenticator
2680 * protection.
2682 * netlogon_creds_cli_LogonSamLogon_start()
2683 * will TALLOC_FREE(state->ro_creds);
2685 state->try_logon_ex = false;
2686 netlogon_creds_cli_LogonSamLogon_start(req);
2687 return;
2690 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2691 state->validation_level,
2692 state->validation);
2693 if (tevent_req_nterror(req, status)) {
2694 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2695 return;
2698 tevent_req_done(req);
2699 return;
2702 if (state->lk_creds == NULL) {
2703 status = netlogon_creds_cli_lock_recv(subreq, state,
2704 &state->lk_creds);
2705 TALLOC_FREE(subreq);
2706 if (tevent_req_nterror(req, status)) {
2707 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2708 return;
2711 netlogon_creds_cli_LogonSamLogon_start(req);
2712 return;
2715 if (state->context->server.try_logon_with) {
2716 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2717 state->validation,
2718 &result);
2719 TALLOC_FREE(subreq);
2720 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2721 state->context->server.try_logon_with = false;
2722 netlogon_creds_cli_LogonSamLogon_start(req);
2723 return;
2725 if (tevent_req_nterror(req, status)) {
2726 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2727 return;
2729 } else {
2730 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2731 state->validation,
2732 &result);
2733 TALLOC_FREE(subreq);
2734 if (tevent_req_nterror(req, status)) {
2735 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2736 return;
2740 ok = netlogon_creds_client_check(&state->tmp_creds,
2741 &state->rep_auth.cred);
2742 if (!ok) {
2743 status = NT_STATUS_ACCESS_DENIED;
2744 tevent_req_nterror(req, status);
2745 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2746 return;
2749 *state->lk_creds = state->tmp_creds;
2750 status = netlogon_creds_cli_store(state->context,
2751 state->lk_creds);
2752 TALLOC_FREE(state->lk_creds);
2754 if (tevent_req_nterror(req, status)) {
2755 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2756 return;
2759 if (tevent_req_nterror(req, result)) {
2760 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2761 return;
2764 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2765 state->validation_level,
2766 state->validation);
2767 if (tevent_req_nterror(req, status)) {
2768 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2769 return;
2772 tevent_req_done(req);
2775 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2776 TALLOC_CTX *mem_ctx,
2777 uint16_t *validation_level,
2778 union netr_Validation **validation,
2779 uint8_t *authoritative,
2780 uint32_t *flags)
2782 struct netlogon_creds_cli_LogonSamLogon_state *state =
2783 tevent_req_data(req,
2784 struct netlogon_creds_cli_LogonSamLogon_state);
2785 NTSTATUS status;
2787 /* authoritative is also returned on error */
2788 *authoritative = state->authoritative;
2790 if (tevent_req_is_nterror(req, &status)) {
2791 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2792 tevent_req_received(req);
2793 return status;
2796 *validation_level = state->validation_level;
2797 *validation = talloc_move(mem_ctx, &state->validation);
2798 *flags = state->flags;
2800 tevent_req_received(req);
2801 return NT_STATUS_OK;
2804 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2805 struct netlogon_creds_cli_context *context,
2806 struct dcerpc_binding_handle *b,
2807 enum netr_LogonInfoClass logon_level,
2808 const union netr_LogonLevel *logon,
2809 TALLOC_CTX *mem_ctx,
2810 uint16_t *validation_level,
2811 union netr_Validation **validation,
2812 uint8_t *authoritative,
2813 uint32_t *flags)
2815 TALLOC_CTX *frame = talloc_stackframe();
2816 struct tevent_context *ev;
2817 struct tevent_req *req;
2818 NTSTATUS status = NT_STATUS_NO_MEMORY;
2820 ev = samba_tevent_context_init(frame);
2821 if (ev == NULL) {
2822 goto fail;
2824 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2825 logon_level, logon,
2826 *flags);
2827 if (req == NULL) {
2828 goto fail;
2830 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2831 goto fail;
2833 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2834 validation_level,
2835 validation,
2836 authoritative,
2837 flags);
2838 fail:
2839 TALLOC_FREE(frame);
2840 return status;
2843 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2844 struct tevent_context *ev;
2845 struct netlogon_creds_cli_context *context;
2846 struct dcerpc_binding_handle *binding_handle;
2848 char *srv_name_slash;
2849 enum dcerpc_AuthType auth_type;
2850 enum dcerpc_AuthLevel auth_level;
2852 const char *site_name;
2853 uint32_t dns_ttl;
2854 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2856 struct netlogon_creds_CredentialState *creds;
2857 struct netlogon_creds_CredentialState tmp_creds;
2858 struct netr_Authenticator req_auth;
2859 struct netr_Authenticator rep_auth;
2862 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2863 NTSTATUS status);
2864 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2866 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2867 struct tevent_context *ev,
2868 struct netlogon_creds_cli_context *context,
2869 struct dcerpc_binding_handle *b,
2870 const char *site_name,
2871 uint32_t dns_ttl,
2872 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2874 struct tevent_req *req;
2875 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2876 struct tevent_req *subreq;
2878 req = tevent_req_create(mem_ctx, &state,
2879 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2880 if (req == NULL) {
2881 return NULL;
2884 state->ev = ev;
2885 state->context = context;
2886 state->binding_handle = b;
2888 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2889 context->server.computer);
2890 if (tevent_req_nomem(state->srv_name_slash, req)) {
2891 return tevent_req_post(req, ev);
2894 state->site_name = site_name;
2895 state->dns_ttl = dns_ttl;
2896 state->dns_names = dns_names;
2898 dcerpc_binding_handle_auth_info(state->binding_handle,
2899 &state->auth_type,
2900 &state->auth_level);
2902 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2903 state->context);
2904 if (tevent_req_nomem(subreq, req)) {
2905 return tevent_req_post(req, ev);
2908 tevent_req_set_callback(subreq,
2909 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2910 req);
2912 return req;
2915 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2916 NTSTATUS status)
2918 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2919 tevent_req_data(req,
2920 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2922 if (state->creds == NULL) {
2923 return;
2926 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2927 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2928 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2929 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2930 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2931 TALLOC_FREE(state->creds);
2932 return;
2935 netlogon_creds_cli_delete(state->context, state->creds);
2936 TALLOC_FREE(state->creds);
2939 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2941 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2943 struct tevent_req *req =
2944 tevent_req_callback_data(subreq,
2945 struct tevent_req);
2946 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2947 tevent_req_data(req,
2948 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2949 NTSTATUS status;
2951 status = netlogon_creds_cli_lock_recv(subreq, state,
2952 &state->creds);
2953 TALLOC_FREE(subreq);
2954 if (tevent_req_nterror(req, status)) {
2955 return;
2958 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2959 switch (state->auth_level) {
2960 case DCERPC_AUTH_LEVEL_INTEGRITY:
2961 case DCERPC_AUTH_LEVEL_PRIVACY:
2962 break;
2963 default:
2964 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2965 return;
2967 } else {
2968 uint32_t tmp = state->creds->negotiate_flags;
2970 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2972 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2973 * it should be used, which means
2974 * we had a chance to verify no downgrade
2975 * happened.
2977 * This relies on netlogon_creds_cli_check*
2978 * being called before, as first request after
2979 * the DCERPC bind.
2981 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2982 return;
2987 * we defer all callbacks in order to cleanup
2988 * the database record.
2990 tevent_req_defer_callback(req, state->ev);
2992 state->tmp_creds = *state->creds;
2993 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2994 &state->req_auth);
2995 if (tevent_req_nterror(req, status)) {
2996 return;
2998 ZERO_STRUCT(state->rep_auth);
3000 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
3001 state->binding_handle,
3002 state->srv_name_slash,
3003 state->tmp_creds.computer_name,
3004 &state->req_auth,
3005 &state->rep_auth,
3006 state->site_name,
3007 state->dns_ttl,
3008 state->dns_names);
3009 if (tevent_req_nomem(subreq, req)) {
3010 status = NT_STATUS_NO_MEMORY;
3011 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3012 return;
3015 tevent_req_set_callback(subreq,
3016 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
3017 req);
3020 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
3022 struct tevent_req *req =
3023 tevent_req_callback_data(subreq,
3024 struct tevent_req);
3025 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3026 tevent_req_data(req,
3027 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3028 NTSTATUS status;
3029 NTSTATUS result;
3030 bool ok;
3033 * We use state->dns_names as the memory context, as this is
3034 * the only in/out variable and it has been overwritten by the
3035 * out parameter from the server.
3037 * We need to preserve the return value until the caller can use it.
3039 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
3040 &result);
3041 TALLOC_FREE(subreq);
3042 if (tevent_req_nterror(req, status)) {
3043 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3044 return;
3047 ok = netlogon_creds_client_check(&state->tmp_creds,
3048 &state->rep_auth.cred);
3049 if (!ok) {
3050 status = NT_STATUS_ACCESS_DENIED;
3051 tevent_req_nterror(req, status);
3052 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3053 return;
3056 *state->creds = state->tmp_creds;
3057 status = netlogon_creds_cli_store(state->context,
3058 state->creds);
3059 TALLOC_FREE(state->creds);
3061 if (tevent_req_nterror(req, status)) {
3062 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3063 return;
3066 if (tevent_req_nterror(req, result)) {
3067 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
3068 return;
3071 tevent_req_done(req);
3074 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
3076 NTSTATUS status;
3078 if (tevent_req_is_nterror(req, &status)) {
3079 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3080 tevent_req_received(req);
3081 return status;
3084 tevent_req_received(req);
3085 return NT_STATUS_OK;
3088 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3089 struct netlogon_creds_cli_context *context,
3090 struct dcerpc_binding_handle *b,
3091 const char *site_name,
3092 uint32_t dns_ttl,
3093 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3095 TALLOC_CTX *frame = talloc_stackframe();
3096 struct tevent_context *ev;
3097 struct tevent_req *req;
3098 NTSTATUS status = NT_STATUS_NO_MEMORY;
3100 ev = samba_tevent_context_init(frame);
3101 if (ev == NULL) {
3102 goto fail;
3104 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
3105 site_name,
3106 dns_ttl,
3107 dns_names);
3108 if (req == NULL) {
3109 goto fail;
3111 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3112 goto fail;
3114 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
3115 fail:
3116 TALLOC_FREE(frame);
3117 return status;
3120 struct netlogon_creds_cli_ServerGetTrustInfo_state {
3121 struct tevent_context *ev;
3122 struct netlogon_creds_cli_context *context;
3123 struct dcerpc_binding_handle *binding_handle;
3125 char *srv_name_slash;
3126 enum dcerpc_AuthType auth_type;
3127 enum dcerpc_AuthLevel auth_level;
3129 struct samr_Password new_owf_password;
3130 struct samr_Password old_owf_password;
3131 struct netr_TrustInfo *trust_info;
3133 struct netlogon_creds_CredentialState *creds;
3134 struct netlogon_creds_CredentialState tmp_creds;
3135 struct netr_Authenticator req_auth;
3136 struct netr_Authenticator rep_auth;
3139 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3140 NTSTATUS status);
3141 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3143 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3144 struct tevent_context *ev,
3145 struct netlogon_creds_cli_context *context,
3146 struct dcerpc_binding_handle *b)
3148 struct tevent_req *req;
3149 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3150 struct tevent_req *subreq;
3152 req = tevent_req_create(mem_ctx, &state,
3153 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3154 if (req == NULL) {
3155 return NULL;
3158 state->ev = ev;
3159 state->context = context;
3160 state->binding_handle = b;
3162 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3163 context->server.computer);
3164 if (tevent_req_nomem(state->srv_name_slash, req)) {
3165 return tevent_req_post(req, ev);
3168 dcerpc_binding_handle_auth_info(state->binding_handle,
3169 &state->auth_type,
3170 &state->auth_level);
3172 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3173 state->context);
3174 if (tevent_req_nomem(subreq, req)) {
3175 return tevent_req_post(req, ev);
3178 tevent_req_set_callback(subreq,
3179 netlogon_creds_cli_ServerGetTrustInfo_locked,
3180 req);
3182 return req;
3185 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3186 NTSTATUS status)
3188 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3189 tevent_req_data(req,
3190 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3192 if (state->creds == NULL) {
3193 return;
3196 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3197 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3198 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3199 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3200 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3201 TALLOC_FREE(state->creds);
3202 return;
3205 netlogon_creds_cli_delete(state->context, state->creds);
3206 TALLOC_FREE(state->creds);
3209 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3211 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3213 struct tevent_req *req =
3214 tevent_req_callback_data(subreq,
3215 struct tevent_req);
3216 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3217 tevent_req_data(req,
3218 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3219 NTSTATUS status;
3221 status = netlogon_creds_cli_lock_recv(subreq, state,
3222 &state->creds);
3223 TALLOC_FREE(subreq);
3224 if (tevent_req_nterror(req, status)) {
3225 return;
3228 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3229 switch (state->auth_level) {
3230 case DCERPC_AUTH_LEVEL_PRIVACY:
3231 break;
3232 default:
3233 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3234 return;
3236 } else {
3237 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3238 return;
3242 * we defer all callbacks in order to cleanup
3243 * the database record.
3245 tevent_req_defer_callback(req, state->ev);
3247 state->tmp_creds = *state->creds;
3248 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3249 &state->req_auth);
3250 if (tevent_req_nterror(req, status)) {
3251 return;
3253 ZERO_STRUCT(state->rep_auth);
3255 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3256 state->binding_handle,
3257 state->srv_name_slash,
3258 state->tmp_creds.account_name,
3259 state->tmp_creds.secure_channel_type,
3260 state->tmp_creds.computer_name,
3261 &state->req_auth,
3262 &state->rep_auth,
3263 &state->new_owf_password,
3264 &state->old_owf_password,
3265 &state->trust_info);
3266 if (tevent_req_nomem(subreq, req)) {
3267 status = NT_STATUS_NO_MEMORY;
3268 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3269 return;
3272 tevent_req_set_callback(subreq,
3273 netlogon_creds_cli_ServerGetTrustInfo_done,
3274 req);
3277 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3279 struct tevent_req *req =
3280 tevent_req_callback_data(subreq,
3281 struct tevent_req);
3282 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3283 tevent_req_data(req,
3284 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3285 NTSTATUS status;
3286 NTSTATUS result;
3287 const struct samr_Password zero = {};
3288 bool cmp;
3289 bool ok;
3292 * We use state->dns_names as the memory context, as this is
3293 * the only in/out variable and it has been overwritten by the
3294 * out parameter from the server.
3296 * We need to preserve the return value until the caller can use it.
3298 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3299 TALLOC_FREE(subreq);
3300 if (tevent_req_nterror(req, status)) {
3301 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3302 return;
3305 ok = netlogon_creds_client_check(&state->tmp_creds,
3306 &state->rep_auth.cred);
3307 if (!ok) {
3308 status = NT_STATUS_ACCESS_DENIED;
3309 tevent_req_nterror(req, status);
3310 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3311 return;
3314 cmp = mem_equal_const_time(state->new_owf_password.hash,
3315 zero.hash, sizeof(zero.hash));
3316 if (!cmp) {
3317 status = netlogon_creds_des_decrypt(&state->tmp_creds,
3318 &state->new_owf_password);
3319 if (tevent_req_nterror(req, status)) {
3320 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3321 return;
3324 cmp = mem_equal_const_time(state->old_owf_password.hash,
3325 zero.hash, sizeof(zero.hash));
3326 if (!cmp) {
3327 status = netlogon_creds_des_decrypt(&state->tmp_creds,
3328 &state->old_owf_password);
3329 if (tevent_req_nterror(req, status)) {
3330 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3331 return;
3335 *state->creds = state->tmp_creds;
3336 status = netlogon_creds_cli_store(state->context,
3337 state->creds);
3338 TALLOC_FREE(state->creds);
3339 if (tevent_req_nterror(req, status)) {
3340 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3341 return;
3344 if (tevent_req_nterror(req, result)) {
3345 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3346 return;
3349 tevent_req_done(req);
3352 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3353 TALLOC_CTX *mem_ctx,
3354 struct samr_Password *new_owf_password,
3355 struct samr_Password *old_owf_password,
3356 struct netr_TrustInfo **trust_info)
3358 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3359 tevent_req_data(req,
3360 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3361 NTSTATUS status;
3363 if (tevent_req_is_nterror(req, &status)) {
3364 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3365 tevent_req_received(req);
3366 return status;
3369 if (new_owf_password != NULL) {
3370 *new_owf_password = state->new_owf_password;
3372 if (old_owf_password != NULL) {
3373 *old_owf_password = state->old_owf_password;
3375 if (trust_info != NULL) {
3376 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3379 tevent_req_received(req);
3380 return NT_STATUS_OK;
3383 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3384 struct netlogon_creds_cli_context *context,
3385 struct dcerpc_binding_handle *b,
3386 TALLOC_CTX *mem_ctx,
3387 struct samr_Password *new_owf_password,
3388 struct samr_Password *old_owf_password,
3389 struct netr_TrustInfo **trust_info)
3391 TALLOC_CTX *frame = talloc_stackframe();
3392 struct tevent_context *ev;
3393 struct tevent_req *req;
3394 NTSTATUS status = NT_STATUS_NO_MEMORY;
3396 ev = samba_tevent_context_init(frame);
3397 if (ev == NULL) {
3398 goto fail;
3400 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3401 if (req == NULL) {
3402 goto fail;
3404 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3405 goto fail;
3407 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3408 mem_ctx,
3409 new_owf_password,
3410 old_owf_password,
3411 trust_info);
3412 fail:
3413 TALLOC_FREE(frame);
3414 return status;
3417 struct netlogon_creds_cli_GetForestTrustInformation_state {
3418 struct tevent_context *ev;
3419 struct netlogon_creds_cli_context *context;
3420 struct dcerpc_binding_handle *binding_handle;
3422 char *srv_name_slash;
3423 enum dcerpc_AuthType auth_type;
3424 enum dcerpc_AuthLevel auth_level;
3426 uint32_t flags;
3427 struct lsa_ForestTrustInformation *forest_trust_info;
3429 struct netlogon_creds_CredentialState *creds;
3430 struct netlogon_creds_CredentialState tmp_creds;
3431 struct netr_Authenticator req_auth;
3432 struct netr_Authenticator rep_auth;
3435 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3436 NTSTATUS status);
3437 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3439 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3440 struct tevent_context *ev,
3441 struct netlogon_creds_cli_context *context,
3442 struct dcerpc_binding_handle *b)
3444 struct tevent_req *req;
3445 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3446 struct tevent_req *subreq;
3448 req = tevent_req_create(mem_ctx, &state,
3449 struct netlogon_creds_cli_GetForestTrustInformation_state);
3450 if (req == NULL) {
3451 return NULL;
3454 state->ev = ev;
3455 state->context = context;
3456 state->binding_handle = b;
3458 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3459 context->server.computer);
3460 if (tevent_req_nomem(state->srv_name_slash, req)) {
3461 return tevent_req_post(req, ev);
3464 state->flags = 0;
3466 dcerpc_binding_handle_auth_info(state->binding_handle,
3467 &state->auth_type,
3468 &state->auth_level);
3470 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3471 state->context);
3472 if (tevent_req_nomem(subreq, req)) {
3473 return tevent_req_post(req, ev);
3476 tevent_req_set_callback(subreq,
3477 netlogon_creds_cli_GetForestTrustInformation_locked,
3478 req);
3480 return req;
3483 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3484 NTSTATUS status)
3486 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3487 tevent_req_data(req,
3488 struct netlogon_creds_cli_GetForestTrustInformation_state);
3490 if (state->creds == NULL) {
3491 return;
3494 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3495 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3496 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3497 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3498 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3499 TALLOC_FREE(state->creds);
3500 return;
3503 netlogon_creds_cli_delete(state->context, state->creds);
3504 TALLOC_FREE(state->creds);
3507 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3509 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3511 struct tevent_req *req =
3512 tevent_req_callback_data(subreq,
3513 struct tevent_req);
3514 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3515 tevent_req_data(req,
3516 struct netlogon_creds_cli_GetForestTrustInformation_state);
3517 NTSTATUS status;
3519 status = netlogon_creds_cli_lock_recv(subreq, state,
3520 &state->creds);
3521 TALLOC_FREE(subreq);
3522 if (tevent_req_nterror(req, status)) {
3523 return;
3526 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3527 switch (state->auth_level) {
3528 case DCERPC_AUTH_LEVEL_INTEGRITY:
3529 case DCERPC_AUTH_LEVEL_PRIVACY:
3530 break;
3531 default:
3532 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3533 return;
3535 } else {
3536 uint32_t tmp = state->creds->negotiate_flags;
3538 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3540 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3541 * it should be used, which means
3542 * we had a chance to verify no downgrade
3543 * happened.
3545 * This relies on netlogon_creds_cli_check*
3546 * being called before, as first request after
3547 * the DCERPC bind.
3549 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3550 return;
3555 * we defer all callbacks in order to cleanup
3556 * the database record.
3558 tevent_req_defer_callback(req, state->ev);
3560 state->tmp_creds = *state->creds;
3561 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3562 &state->req_auth);
3563 if (tevent_req_nterror(req, status)) {
3564 return;
3566 ZERO_STRUCT(state->rep_auth);
3568 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3569 state->binding_handle,
3570 state->srv_name_slash,
3571 state->tmp_creds.computer_name,
3572 &state->req_auth,
3573 &state->rep_auth,
3574 state->flags,
3575 &state->forest_trust_info);
3576 if (tevent_req_nomem(subreq, req)) {
3577 status = NT_STATUS_NO_MEMORY;
3578 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3579 return;
3582 tevent_req_set_callback(subreq,
3583 netlogon_creds_cli_GetForestTrustInformation_done,
3584 req);
3587 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3589 struct tevent_req *req =
3590 tevent_req_callback_data(subreq,
3591 struct tevent_req);
3592 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3593 tevent_req_data(req,
3594 struct netlogon_creds_cli_GetForestTrustInformation_state);
3595 NTSTATUS status;
3596 NTSTATUS result;
3597 bool ok;
3600 * We use state->dns_names as the memory context, as this is
3601 * the only in/out variable and it has been overwritten by the
3602 * out parameter from the server.
3604 * We need to preserve the return value until the caller can use it.
3606 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3607 TALLOC_FREE(subreq);
3608 if (tevent_req_nterror(req, status)) {
3609 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3610 return;
3613 ok = netlogon_creds_client_check(&state->tmp_creds,
3614 &state->rep_auth.cred);
3615 if (!ok) {
3616 status = NT_STATUS_ACCESS_DENIED;
3617 tevent_req_nterror(req, status);
3618 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3619 return;
3622 *state->creds = state->tmp_creds;
3623 status = netlogon_creds_cli_store(state->context,
3624 state->creds);
3625 TALLOC_FREE(state->creds);
3627 if (tevent_req_nterror(req, status)) {
3628 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3629 return;
3632 if (tevent_req_nterror(req, result)) {
3633 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3634 return;
3637 tevent_req_done(req);
3640 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3641 TALLOC_CTX *mem_ctx,
3642 struct lsa_ForestTrustInformation **forest_trust_info)
3644 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3645 tevent_req_data(req,
3646 struct netlogon_creds_cli_GetForestTrustInformation_state);
3647 NTSTATUS status;
3649 if (tevent_req_is_nterror(req, &status)) {
3650 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3651 tevent_req_received(req);
3652 return status;
3655 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3657 tevent_req_received(req);
3658 return NT_STATUS_OK;
3661 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3662 struct netlogon_creds_cli_context *context,
3663 struct dcerpc_binding_handle *b,
3664 TALLOC_CTX *mem_ctx,
3665 struct lsa_ForestTrustInformation **forest_trust_info)
3667 TALLOC_CTX *frame = talloc_stackframe();
3668 struct tevent_context *ev;
3669 struct tevent_req *req;
3670 NTSTATUS status = NT_STATUS_NO_MEMORY;
3672 ev = samba_tevent_context_init(frame);
3673 if (ev == NULL) {
3674 goto fail;
3676 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3677 if (req == NULL) {
3678 goto fail;
3680 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3681 goto fail;
3683 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3684 mem_ctx,
3685 forest_trust_info);
3686 fail:
3687 TALLOC_FREE(frame);
3688 return status;
3690 struct netlogon_creds_cli_SendToSam_state {
3691 struct tevent_context *ev;
3692 struct netlogon_creds_cli_context *context;
3693 struct dcerpc_binding_handle *binding_handle;
3695 char *srv_name_slash;
3696 enum dcerpc_AuthType auth_type;
3697 enum dcerpc_AuthLevel auth_level;
3699 DATA_BLOB opaque;
3701 struct netlogon_creds_CredentialState *creds;
3702 struct netlogon_creds_CredentialState tmp_creds;
3703 struct netr_Authenticator req_auth;
3704 struct netr_Authenticator rep_auth;
3707 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3708 NTSTATUS status);
3709 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3711 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3712 struct tevent_context *ev,
3713 struct netlogon_creds_cli_context *context,
3714 struct dcerpc_binding_handle *b,
3715 struct netr_SendToSamBase *message)
3717 struct tevent_req *req;
3718 struct netlogon_creds_cli_SendToSam_state *state;
3719 struct tevent_req *subreq;
3720 enum ndr_err_code ndr_err;
3722 req = tevent_req_create(mem_ctx, &state,
3723 struct netlogon_creds_cli_SendToSam_state);
3724 if (req == NULL) {
3725 return NULL;
3728 state->ev = ev;
3729 state->context = context;
3730 state->binding_handle = b;
3732 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3733 context->server.computer);
3734 if (tevent_req_nomem(state->srv_name_slash, req)) {
3735 return tevent_req_post(req, ev);
3738 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3739 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3740 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3741 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3742 tevent_req_nterror(req, status);
3743 return tevent_req_post(req, ev);
3746 dcerpc_binding_handle_auth_info(state->binding_handle,
3747 &state->auth_type,
3748 &state->auth_level);
3750 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3751 state->context);
3752 if (tevent_req_nomem(subreq, req)) {
3753 return tevent_req_post(req, ev);
3756 tevent_req_set_callback(subreq,
3757 netlogon_creds_cli_SendToSam_locked,
3758 req);
3760 return req;
3763 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3764 NTSTATUS status)
3766 struct netlogon_creds_cli_SendToSam_state *state =
3767 tevent_req_data(req,
3768 struct netlogon_creds_cli_SendToSam_state);
3770 if (state->creds == NULL) {
3771 return;
3774 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3775 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3776 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3777 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3778 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3779 TALLOC_FREE(state->creds);
3780 return;
3783 netlogon_creds_cli_delete(state->context, state->creds);
3784 TALLOC_FREE(state->creds);
3787 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3789 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3791 struct tevent_req *req =
3792 tevent_req_callback_data(subreq,
3793 struct tevent_req);
3794 struct netlogon_creds_cli_SendToSam_state *state =
3795 tevent_req_data(req,
3796 struct netlogon_creds_cli_SendToSam_state);
3797 NTSTATUS status;
3799 status = netlogon_creds_cli_lock_recv(subreq, state,
3800 &state->creds);
3801 TALLOC_FREE(subreq);
3802 if (tevent_req_nterror(req, status)) {
3803 return;
3806 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3807 switch (state->auth_level) {
3808 case DCERPC_AUTH_LEVEL_INTEGRITY:
3809 case DCERPC_AUTH_LEVEL_PRIVACY:
3810 break;
3811 default:
3812 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3813 return;
3815 } else {
3816 uint32_t tmp = state->creds->negotiate_flags;
3818 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3820 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3821 * it should be used, which means
3822 * we had a chance to verify no downgrade
3823 * happened.
3825 * This relies on netlogon_creds_cli_check*
3826 * being called before, as first request after
3827 * the DCERPC bind.
3829 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3830 return;
3835 * we defer all callbacks in order to cleanup
3836 * the database record.
3838 tevent_req_defer_callback(req, state->ev);
3840 state->tmp_creds = *state->creds;
3841 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3842 &state->req_auth);
3843 if (tevent_req_nterror(req, status)) {
3844 return;
3846 ZERO_STRUCT(state->rep_auth);
3848 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3849 status = netlogon_creds_aes_encrypt(&state->tmp_creds,
3850 state->opaque.data,
3851 state->opaque.length);
3852 if (tevent_req_nterror(req, status)) {
3853 netlogon_creds_cli_SendToSam_cleanup(req, status);
3854 return;
3856 } else {
3857 status = netlogon_creds_arcfour_crypt(&state->tmp_creds,
3858 state->opaque.data,
3859 state->opaque.length);
3860 if (tevent_req_nterror(req, status)) {
3861 netlogon_creds_cli_SendToSam_cleanup(req, status);
3862 return;
3866 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3867 state->binding_handle,
3868 state->srv_name_slash,
3869 state->tmp_creds.computer_name,
3870 &state->req_auth,
3871 &state->rep_auth,
3872 state->opaque.data,
3873 state->opaque.length);
3874 if (tevent_req_nomem(subreq, req)) {
3875 status = NT_STATUS_NO_MEMORY;
3876 netlogon_creds_cli_SendToSam_cleanup(req, status);
3877 return;
3880 tevent_req_set_callback(subreq,
3881 netlogon_creds_cli_SendToSam_done,
3882 req);
3885 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3887 struct tevent_req *req =
3888 tevent_req_callback_data(subreq,
3889 struct tevent_req);
3890 struct netlogon_creds_cli_SendToSam_state *state =
3891 tevent_req_data(req,
3892 struct netlogon_creds_cli_SendToSam_state);
3893 NTSTATUS status;
3894 NTSTATUS result;
3895 bool ok;
3897 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3898 TALLOC_FREE(subreq);
3899 if (tevent_req_nterror(req, status)) {
3900 netlogon_creds_cli_SendToSam_cleanup(req, status);
3901 return;
3904 ok = netlogon_creds_client_check(&state->tmp_creds,
3905 &state->rep_auth.cred);
3906 if (!ok) {
3907 status = NT_STATUS_ACCESS_DENIED;
3908 tevent_req_nterror(req, status);
3909 netlogon_creds_cli_SendToSam_cleanup(req, status);
3910 return;
3913 *state->creds = state->tmp_creds;
3914 status = netlogon_creds_cli_store(state->context,
3915 state->creds);
3916 TALLOC_FREE(state->creds);
3918 if (tevent_req_nterror(req, status)) {
3919 netlogon_creds_cli_SendToSam_cleanup(req, status);
3920 return;
3924 * Creds must be stored before we send back application errors
3925 * e.g. NT_STATUS_NOT_IMPLEMENTED
3927 if (tevent_req_nterror(req, result)) {
3928 netlogon_creds_cli_SendToSam_cleanup(req, result);
3929 return;
3932 tevent_req_done(req);
3935 NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
3937 NTSTATUS status;
3939 if (tevent_req_is_nterror(req, &status)) {
3940 netlogon_creds_cli_SendToSam_cleanup(req, status);
3941 tevent_req_received(req);
3942 return status;
3945 tevent_req_received(req);
3946 return NT_STATUS_OK;
3949 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3950 struct dcerpc_binding_handle *b,
3951 struct netr_SendToSamBase *message)
3953 TALLOC_CTX *frame = talloc_stackframe();
3954 struct tevent_context *ev;
3955 struct tevent_req *req;
3956 NTSTATUS status = NT_STATUS_NO_MEMORY;
3958 ev = samba_tevent_context_init(frame);
3959 if (ev == NULL) {
3960 goto fail;
3962 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3963 if (req == NULL) {
3964 goto fail;
3966 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3967 goto fail;
3969 status = netlogon_creds_cli_SendToSam_recv(req);
3970 fail:
3971 TALLOC_FREE(frame);
3972 return status;
3975 struct netlogon_creds_cli_LogonGetDomainInfo_state {
3976 struct tevent_context *ev;
3977 struct netlogon_creds_cli_context *context;
3978 struct dcerpc_binding_handle *binding_handle;
3980 char *srv_name_slash;
3981 enum dcerpc_AuthType auth_type;
3982 enum dcerpc_AuthLevel auth_level;
3984 uint32_t level;
3985 union netr_WorkstationInfo *query;
3986 union netr_DomainInfo *info;
3988 struct netlogon_creds_CredentialState *creds;
3989 struct netlogon_creds_CredentialState tmp_creds;
3990 struct netr_Authenticator req_auth;
3991 struct netr_Authenticator rep_auth;
3994 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
3995 NTSTATUS status);
3996 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
3998 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
3999 struct tevent_context *ev,
4000 struct netlogon_creds_cli_context *context,
4001 struct dcerpc_binding_handle *b,
4002 uint32_t level,
4003 union netr_WorkstationInfo *query)
4005 struct tevent_req *req;
4006 struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
4007 struct tevent_req *subreq;
4009 req = tevent_req_create(mem_ctx, &state,
4010 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4011 if (req == NULL) {
4012 return NULL;
4015 state->ev = ev;
4016 state->context = context;
4017 state->binding_handle = b;
4019 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
4020 context->server.computer);
4021 if (tevent_req_nomem(state->srv_name_slash, req)) {
4022 return tevent_req_post(req, ev);
4025 state->level = level;
4026 state->query = query;
4027 state->info = talloc_zero(state, union netr_DomainInfo);
4028 if (tevent_req_nomem(state->info, req)) {
4029 return tevent_req_post(req, ev);
4032 dcerpc_binding_handle_auth_info(state->binding_handle,
4033 &state->auth_type,
4034 &state->auth_level);
4036 subreq = netlogon_creds_cli_lock_send(state, state->ev,
4037 state->context);
4038 if (tevent_req_nomem(subreq, req)) {
4039 return tevent_req_post(req, ev);
4042 tevent_req_set_callback(subreq,
4043 netlogon_creds_cli_LogonGetDomainInfo_locked,
4044 req);
4046 return req;
4049 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4050 NTSTATUS status)
4052 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4053 tevent_req_data(req,
4054 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4056 if (state->creds == NULL) {
4057 return;
4060 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
4061 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
4062 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
4063 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
4064 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
4065 TALLOC_FREE(state->creds);
4066 return;
4069 netlogon_creds_cli_delete(state->context, state->creds);
4072 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
4074 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
4076 struct tevent_req *req =
4077 tevent_req_callback_data(subreq,
4078 struct tevent_req);
4079 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4080 tevent_req_data(req,
4081 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4082 NTSTATUS status;
4084 status = netlogon_creds_cli_lock_recv(subreq, state,
4085 &state->creds);
4086 TALLOC_FREE(subreq);
4087 if (tevent_req_nterror(req, status)) {
4088 return;
4091 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
4092 switch (state->auth_level) {
4093 case DCERPC_AUTH_LEVEL_INTEGRITY:
4094 case DCERPC_AUTH_LEVEL_PRIVACY:
4095 break;
4096 default:
4097 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4098 return;
4100 } else {
4101 uint32_t tmp = state->creds->negotiate_flags;
4103 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
4105 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
4106 * it should be used, which means
4107 * we had a chance to verify no downgrade
4108 * happened.
4110 * This relies on netlogon_creds_cli_check*
4111 * being called before, as first request after
4112 * the DCERPC bind.
4114 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
4115 return;
4120 * we defer all callbacks in order to cleanup
4121 * the database record.
4123 tevent_req_defer_callback(req, state->ev);
4125 state->tmp_creds = *state->creds;
4126 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4127 &state->req_auth);
4128 if (tevent_req_nterror(req, status)) {
4129 return;
4131 ZERO_STRUCT(state->rep_auth);
4133 subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
4134 state->binding_handle,
4135 state->srv_name_slash,
4136 state->tmp_creds.computer_name,
4137 &state->req_auth,
4138 &state->rep_auth,
4139 state->level,
4140 state->query,
4141 state->info);
4142 if (tevent_req_nomem(subreq, req)) {
4143 status = NT_STATUS_NO_MEMORY;
4144 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4145 return;
4148 tevent_req_set_callback(subreq,
4149 netlogon_creds_cli_LogonGetDomainInfo_done,
4150 req);
4153 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4155 struct tevent_req *req =
4156 tevent_req_callback_data(subreq,
4157 struct tevent_req);
4158 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4159 tevent_req_data(req,
4160 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4161 NTSTATUS status;
4162 NTSTATUS result;
4163 bool ok;
4166 * We use state->dns_names as the memory context, as this is
4167 * the only in/out variable and it has been overwritten by the
4168 * out parameter from the server.
4170 * We need to preserve the return value until the caller can use it.
4172 status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4173 TALLOC_FREE(subreq);
4174 if (tevent_req_nterror(req, status)) {
4175 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4176 return;
4179 ok = netlogon_creds_client_check(&state->tmp_creds,
4180 &state->rep_auth.cred);
4181 if (!ok) {
4182 status = NT_STATUS_ACCESS_DENIED;
4183 tevent_req_nterror(req, status);
4184 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4185 return;
4188 if (tevent_req_nterror(req, result)) {
4189 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4190 return;
4193 *state->creds = state->tmp_creds;
4194 status = netlogon_creds_cli_store(state->context,
4195 state->creds);
4196 if (tevent_req_nterror(req, status)) {
4197 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4198 return;
4201 tevent_req_done(req);
4204 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4205 TALLOC_CTX *mem_ctx,
4206 union netr_DomainInfo **info)
4208 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4209 tevent_req_data(req,
4210 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4211 NTSTATUS status;
4213 if (tevent_req_is_nterror(req, &status)) {
4214 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4215 tevent_req_received(req);
4216 return status;
4219 *info = talloc_move(mem_ctx, &state->info);
4221 tevent_req_received(req);
4222 return NT_STATUS_OK;
4225 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4226 struct netlogon_creds_cli_context *context,
4227 struct dcerpc_binding_handle *b,
4228 TALLOC_CTX *mem_ctx,
4229 uint32_t level,
4230 union netr_WorkstationInfo *query,
4231 union netr_DomainInfo **info)
4233 TALLOC_CTX *frame = talloc_stackframe();
4234 struct tevent_context *ev;
4235 struct tevent_req *req;
4236 NTSTATUS status = NT_STATUS_OK;
4238 ev = samba_tevent_context_init(frame);
4239 if (ev == NULL) {
4240 goto fail;
4242 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4243 level, query);
4244 if (req == NULL) {
4245 goto fail;
4247 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4248 goto fail;
4250 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4251 mem_ctx,
4252 info);
4253 fail:
4254 TALLOC_FREE(frame);
4255 return status;