drsuapi.idl: fix source_dsa spelling
[samba4-gss.git] / libcli / auth / netlogon_creds_cli.c
blob879f79c5400730f258d94a8f13f846c1d3da9262
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 bool reject_aes_servers = true;
362 int require_sign_or_seal = true;
363 bool seal_secure_channel = true;
364 bool trust_support_kerberos = false;
365 #if defined(HAVE_ADS) && defined(HAVE_KRB5_INIT_CREDS_STEP)
366 const bool support_krb5_netlogon = true;
367 #else
368 const bool support_krb5_netlogon = false;
369 #endif
370 int global_client_use_krb5_netlogon = true;
371 bool client_use_krb5_netlogon = true;
372 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
373 bool neutralize_nt4_emulation = false;
375 *_context = NULL;
377 if (msg_ctx == NULL) {
378 TALLOC_FREE(frame);
379 return NT_STATUS_INVALID_PARAMETER_MIX;
382 client_computer = lpcfg_netbios_name(lp_ctx);
383 if (strlen(client_computer) > 15) {
384 TALLOC_FREE(frame);
385 return NT_STATUS_INVALID_PARAMETER_MIX;
389 * allow overwrite per domain
390 * reject md5 servers:<netbios_domain>
392 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
393 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
394 "reject md5 servers",
395 server_netbios_domain,
396 reject_md5_servers);
399 * allow overwrite per domain
400 * require strong key:<netbios_domain>
402 require_strong_key = lpcfg_require_strong_key(lp_ctx);
403 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
404 "require strong key",
405 server_netbios_domain,
406 require_strong_key);
409 * allow overwrite per domain
410 * client schannel:<netbios_domain>
412 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
413 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
414 "client schannel",
415 server_netbios_domain,
416 require_sign_or_seal);
419 * allow overwrite per domain
420 * winbind sealed pipes:<netbios_domain>
422 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
423 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
424 "winbind sealed pipes",
425 server_netbios_domain,
426 seal_secure_channel);
429 * allow overwrite per domain
430 * neutralize nt4 emulation:<netbios_domain>
432 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
433 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
434 "neutralize nt4 emulation",
435 server_netbios_domain,
436 neutralize_nt4_emulation);
439 * allow overwrite per domain
440 * reject aes netlogon servers:<netbios_domain>
442 reject_aes_servers = lpcfg_reject_aes_netlogon_servers(lp_ctx);
443 reject_aes_servers = lpcfg_parm_bool(lp_ctx, NULL,
444 "reject aes netlogon servers",
445 server_netbios_domain,
446 reject_aes_servers);
449 * allow overwrite per domain
450 * client use krb5 netlogon:<netbios_domain>
452 * See further below!
454 global_client_use_krb5_netlogon = lpcfg_client_use_krb5_netlogon(lp_ctx);
456 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
457 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
459 switch (type) {
460 case SEC_CHAN_WKSTA:
461 if (lpcfg_security(lp_ctx) == SEC_ADS) {
463 * AD domains should be secure
465 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
466 require_sign_or_seal = true;
467 require_strong_key = true;
468 trust_support_kerberos = true;
470 break;
472 case SEC_CHAN_DOMAIN:
473 break;
475 case SEC_CHAN_DNS_DOMAIN:
477 * AD domains should be secure
479 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
480 require_sign_or_seal = true;
481 require_strong_key = true;
482 neutralize_nt4_emulation = true;
483 trust_support_kerberos = true;
484 break;
486 case SEC_CHAN_BDC:
487 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
488 require_sign_or_seal = true;
489 require_strong_key = true;
490 if (lpcfg_server_role(lp_ctx) == ROLE_ACTIVE_DIRECTORY_DC) {
491 trust_support_kerberos = true;
493 break;
495 case SEC_CHAN_RODC:
496 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
497 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
498 require_sign_or_seal = true;
499 require_strong_key = true;
500 neutralize_nt4_emulation = true;
501 trust_support_kerberos = true;
502 break;
504 default:
505 TALLOC_FREE(frame);
506 return NT_STATUS_INVALID_PARAMETER;
509 if (global_client_use_krb5_netlogon == Auto) {
510 if (support_krb5_netlogon) {
511 global_client_use_krb5_netlogon = trust_support_kerberos;
512 } else {
513 global_client_use_krb5_netlogon = false;
516 client_use_krb5_netlogon = global_client_use_krb5_netlogon;
517 client_use_krb5_netlogon = lpcfg_parm_bool(lp_ctx, NULL,
518 "client use krb5 netlogon",
519 server_netbios_domain,
520 client_use_krb5_netlogon);
522 if (reject_aes_servers) {
523 client_use_krb5_netlogon = true;
526 if (client_use_krb5_netlogon) {
527 if (!support_krb5_netlogon) {
528 DBG_ERR("No support for ServerAuthenticateKerberos!\n");
529 TALLOC_FREE(frame);
530 return NT_STATUS_DEVICE_FEATURE_NOT_SUPPORTED;
532 proposed_flags |= NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH;
535 if (neutralize_nt4_emulation) {
536 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
539 if (require_sign_or_seal) {
540 required_flags |= NETLOGON_NEG_ARCFOUR;
541 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
542 } else {
543 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
546 if (reject_md5_servers) {
547 required_flags |= NETLOGON_NEG_ARCFOUR;
548 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
549 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
550 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
553 if (require_strong_key) {
554 required_flags |= NETLOGON_NEG_ARCFOUR;
555 required_flags |= NETLOGON_NEG_STRONG_KEYS;
556 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
559 if (reject_aes_servers) {
560 required_flags |= NETLOGON_NEG_ARCFOUR;
561 required_flags |= NETLOGON_NEG_STRONG_KEYS;
562 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
563 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
564 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
565 required_flags |= NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH;
569 * If weak crypto is disabled, do not announce that we support RC4 and
570 * require AES.
572 if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_DISALLOWED) {
573 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
576 proposed_flags |= required_flags;
578 if (required_flags & NETLOGON_NEG_SUPPORTS_AES) {
579 required_flags &= ~NETLOGON_NEG_ARCFOUR;
580 required_flags &= ~NETLOGON_NEG_STRONG_KEYS;
583 if (required_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
584 required_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
587 if (proposed_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
588 seal_secure_channel = true;
591 if (seal_secure_channel) {
592 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
593 } else {
594 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
597 if (server_dns_domain == NULL) {
598 server_dns_domain = "";
601 status = netlogon_creds_cli_context_common(client_computer,
602 client_account,
603 type,
604 auth_level,
605 proposed_flags,
606 required_flags,
607 server_computer,
608 server_netbios_domain,
609 server_dns_domain,
610 mem_ctx,
611 &context);
612 if (!NT_STATUS_IS_OK(status)) {
613 TALLOC_FREE(frame);
614 return status;
617 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
618 if (context->db.g_ctx == NULL) {
619 TALLOC_FREE(context);
620 TALLOC_FREE(frame);
621 return NT_STATUS_NO_MEMORY;
624 status = netlogon_creds_cli_open_global_db(lp_ctx);
625 if (!NT_STATUS_IS_OK(status)) {
626 TALLOC_FREE(context);
627 TALLOC_FREE(frame);
628 return NT_STATUS_NO_MEMORY;
631 context->db.ctx = netlogon_creds_cli_global_db;
632 *_context = context;
633 TALLOC_FREE(frame);
634 return NT_STATUS_OK;
637 NTSTATUS netlogon_creds_bind_cli_credentials(
638 struct netlogon_creds_cli_context *context, TALLOC_CTX *mem_ctx,
639 struct cli_credentials **pcli_creds)
641 struct cli_credentials *cli_creds;
642 struct netlogon_creds_CredentialState *ncreds;
643 NTSTATUS status;
645 cli_creds = cli_credentials_init(mem_ctx);
646 if (cli_creds == NULL) {
647 return NT_STATUS_NO_MEMORY;
649 cli_credentials_set_secure_channel_type(cli_creds,
650 context->client.type);
651 cli_credentials_set_username(cli_creds, context->client.account,
652 CRED_SPECIFIED);
653 cli_credentials_set_domain(cli_creds, context->server.netbios_domain,
654 CRED_SPECIFIED);
655 cli_credentials_set_realm(cli_creds, context->server.dns_domain,
656 CRED_SPECIFIED);
658 status = netlogon_creds_cli_get(context, cli_creds, &ncreds);
659 if (!NT_STATUS_IS_OK(status)) {
660 TALLOC_FREE(cli_creds);
661 return status;
663 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
665 *pcli_creds = cli_creds;
666 return NT_STATUS_OK;
669 char *netlogon_creds_cli_debug_string(
670 const struct netlogon_creds_cli_context *context,
671 TALLOC_CTX *mem_ctx)
673 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
674 context->db.key_name);
677 void netlogon_creds_cli_use_kerberos(
678 struct netlogon_creds_cli_context *context,
679 bool *client_use_krb5_netlogon,
680 bool *reject_aes_servers)
682 *client_use_krb5_netlogon = false;
683 *reject_aes_servers = false;
685 if (context->client.required_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
686 *client_use_krb5_netlogon = true;
687 *reject_aes_servers = true;
690 if (context->client.proposed_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
691 *client_use_krb5_netlogon = true;
695 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
696 struct netlogon_creds_cli_context *context)
698 return context->client.auth_level;
701 static bool netlogon_creds_cli_downgraded(uint32_t negotiated_flags,
702 bool authenticate_kerberos,
703 uint32_t proposed_flags,
704 uint32_t required_flags)
706 uint32_t req_flags = required_flags;
707 uint32_t tmp_flags;
709 req_flags = required_flags;
710 if (authenticate_kerberos) {
711 if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) &&
712 (proposed_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH))
714 req_flags &= ~NETLOGON_NEG_ARCFOUR;
715 req_flags &= ~NETLOGON_NEG_STRONG_KEYS;
716 req_flags &= ~NETLOGON_NEG_SUPPORTS_AES;
717 } else {
718 return true;
720 } else {
721 if (req_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
722 return true;
724 if (negotiated_flags & NETLOGON_NEG_SUPPORTS_KERBEROS_AUTH) {
725 return true;
728 if ((negotiated_flags & NETLOGON_NEG_SUPPORTS_AES) &&
729 (proposed_flags & NETLOGON_NEG_SUPPORTS_AES))
731 req_flags &= ~NETLOGON_NEG_ARCFOUR|NETLOGON_NEG_STRONG_KEYS;
734 tmp_flags = negotiated_flags;
735 tmp_flags &= req_flags;
736 if (tmp_flags != req_flags) {
737 return true;
740 return false;
743 struct netlogon_creds_cli_fetch_state {
744 TALLOC_CTX *mem_ctx;
745 struct netlogon_creds_CredentialState *creds;
746 uint32_t proposed_flags;
747 uint32_t required_flags;
748 NTSTATUS status;
751 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
752 void *private_data)
754 struct netlogon_creds_cli_fetch_state *state =
755 (struct netlogon_creds_cli_fetch_state *)private_data;
756 enum ndr_err_code ndr_err;
757 DATA_BLOB blob;
758 bool downgraded;
760 state->creds = talloc_zero(state->mem_ctx,
761 struct netlogon_creds_CredentialState);
762 if (state->creds == NULL) {
763 state->status = NT_STATUS_NO_MEMORY;
764 return;
767 blob.data = data.dptr;
768 blob.length = data.dsize;
770 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
771 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
772 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
773 TALLOC_FREE(state->creds);
774 state->status = ndr_map_error2ntstatus(ndr_err);
775 return;
778 if (DEBUGLEVEL >= 10) {
779 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, state->creds);
782 if (state->proposed_flags != state->creds->client_requested_flags) {
783 TALLOC_FREE(state->creds);
784 state->status = NT_STATUS_RESOURCE_REQUIREMENTS_CHANGED;
785 return;
788 downgraded = netlogon_creds_cli_downgraded(
789 state->creds->negotiate_flags,
790 state->creds->authenticate_kerberos,
791 state->proposed_flags,
792 state->required_flags);
793 if (downgraded) {
794 TALLOC_FREE(state->creds);
795 state->status = NT_STATUS_DOWNGRADE_DETECTED;
796 return;
799 state->status = NT_STATUS_OK;
802 static NTSTATUS netlogon_creds_cli_get_internal(
803 struct netlogon_creds_cli_context *context,
804 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds);
806 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
807 TALLOC_CTX *mem_ctx,
808 struct netlogon_creds_CredentialState **_creds)
810 NTSTATUS status;
811 struct netlogon_creds_CredentialState *creds;
813 *_creds = NULL;
815 status = netlogon_creds_cli_get_internal(context, mem_ctx, &creds);
816 if (!NT_STATUS_IS_OK(status)) {
817 return status;
821 * mark it as invalid for step operations.
823 creds->sequence = 0;
824 creds->seed = (struct netr_Credential) {{0}};
825 creds->client = (struct netr_Credential) {{0}};
826 creds->server = (struct netr_Credential) {{0}};
828 *_creds = creds;
829 return NT_STATUS_OK;
832 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
833 const struct netlogon_creds_CredentialState *creds1)
835 TALLOC_CTX *frame = talloc_stackframe();
836 struct netlogon_creds_CredentialState *creds2;
837 DATA_BLOB blob1;
838 DATA_BLOB blob2;
839 NTSTATUS status;
840 enum ndr_err_code ndr_err;
841 bool equal;
843 status = netlogon_creds_cli_get(context, frame, &creds2);
844 if (!NT_STATUS_IS_OK(status)) {
845 TALLOC_FREE(frame);
846 return false;
849 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
850 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
851 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
852 TALLOC_FREE(frame);
853 return false;
856 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
857 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
858 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
859 TALLOC_FREE(frame);
860 return false;
863 equal = data_blob_equal_const_time(&blob1, &blob2);
865 TALLOC_FREE(frame);
867 return equal;
870 static NTSTATUS netlogon_creds_cli_store_internal(
871 struct netlogon_creds_cli_context *context,
872 struct netlogon_creds_CredentialState *creds)
874 TALLOC_CTX *frame = talloc_stackframe();
875 NTSTATUS status;
876 enum ndr_err_code ndr_err;
877 DATA_BLOB blob;
878 TDB_DATA data;
880 if (DEBUGLEVEL >= 10) {
881 NDR_PRINT_DEBUG(netlogon_creds_CredentialState, creds);
884 ndr_err = ndr_push_struct_blob(&blob, frame, creds,
885 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
886 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
887 status = ndr_map_error2ntstatus(ndr_err);
888 TALLOC_FREE(frame);
889 return status;
892 data.dptr = blob.data;
893 data.dsize = blob.length;
895 status = dbwrap_store(context->db.ctx,
896 context->db.key_data,
897 data, TDB_REPLACE);
898 if (!NT_STATUS_IS_OK(status)) {
899 TALLOC_FREE(frame);
900 return status;
903 TALLOC_FREE(frame);
904 return NT_STATUS_OK;
907 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
908 struct netlogon_creds_CredentialState *creds)
910 NTSTATUS status;
912 if (context->db.locked_state == NULL) {
914 * this was not the result of netlogon_creds_cli_lock*()
916 return NT_STATUS_INVALID_PAGE_PROTECTION;
919 if (context->db.locked_state->creds != creds) {
921 * this was not the result of netlogon_creds_cli_lock*()
923 return NT_STATUS_INVALID_PAGE_PROTECTION;
926 status = netlogon_creds_cli_store_internal(context, creds);
927 return status;
930 static NTSTATUS netlogon_creds_cli_delete_internal(
931 struct netlogon_creds_cli_context *context)
933 NTSTATUS status;
934 status = dbwrap_delete(context->db.ctx, context->db.key_data);
935 return status;
938 NTSTATUS netlogon_creds_cli_delete_lck(
939 struct netlogon_creds_cli_context *context)
941 NTSTATUS status;
943 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
944 return NT_STATUS_NOT_LOCKED;
947 status = netlogon_creds_cli_delete_internal(context);
948 return status;
951 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
952 struct netlogon_creds_CredentialState *creds)
954 NTSTATUS status;
956 if (context->db.locked_state == NULL) {
958 * this was not the result of netlogon_creds_cli_lock*()
960 return NT_STATUS_INVALID_PAGE_PROTECTION;
963 if (context->db.locked_state->creds != creds) {
965 * this was not the result of netlogon_creds_cli_lock*()
967 return NT_STATUS_INVALID_PAGE_PROTECTION;
970 status = netlogon_creds_cli_delete_internal(context);
971 return status;
974 struct netlogon_creds_cli_lock_state {
975 struct netlogon_creds_cli_locked_state *locked_state;
976 struct netlogon_creds_CredentialState *creds;
979 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
981 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
982 struct tevent_context *ev,
983 struct netlogon_creds_cli_context *context)
985 struct tevent_req *req;
986 struct netlogon_creds_cli_lock_state *state;
987 struct netlogon_creds_cli_locked_state *locked_state;
988 struct tevent_req *subreq;
990 req = tevent_req_create(mem_ctx, &state,
991 struct netlogon_creds_cli_lock_state);
992 if (req == NULL) {
993 return NULL;
996 if (context->db.locked_state != NULL) {
997 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
998 return tevent_req_post(req, ev);
1001 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1002 if (tevent_req_nomem(locked_state, req)) {
1003 return tevent_req_post(req, ev);
1005 talloc_set_destructor(locked_state,
1006 netlogon_creds_cli_locked_state_destructor);
1007 locked_state->context = context;
1009 context->db.locked_state = locked_state;
1010 state->locked_state = locked_state;
1012 if (context->db.g_ctx == NULL) {
1013 NTSTATUS status;
1015 status = netlogon_creds_cli_get_internal(
1016 context, state, &state->creds);
1017 if (tevent_req_nterror(req, status)) {
1018 return tevent_req_post(req, ev);
1021 return req;
1024 subreq = g_lock_lock_send(state, ev,
1025 context->db.g_ctx,
1026 string_term_tdb_data(context->db.key_name),
1027 G_LOCK_WRITE,
1028 NULL, NULL);
1029 if (tevent_req_nomem(subreq, req)) {
1030 return tevent_req_post(req, ev);
1032 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
1034 return req;
1037 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
1039 struct tevent_req *req =
1040 tevent_req_callback_data(subreq,
1041 struct tevent_req);
1042 struct netlogon_creds_cli_lock_state *state =
1043 tevent_req_data(req,
1044 struct netlogon_creds_cli_lock_state);
1045 NTSTATUS status;
1047 status = g_lock_lock_recv(subreq);
1048 TALLOC_FREE(subreq);
1049 if (tevent_req_nterror(req, status)) {
1050 return;
1052 state->locked_state->is_glocked = true;
1054 status = netlogon_creds_cli_get_internal(state->locked_state->context,
1055 state, &state->creds);
1056 if (tevent_req_nterror(req, status)) {
1057 return;
1059 tevent_req_done(req);
1062 static NTSTATUS netlogon_creds_cli_get_internal(
1063 struct netlogon_creds_cli_context *context,
1064 TALLOC_CTX *mem_ctx, struct netlogon_creds_CredentialState **pcreds)
1066 struct netlogon_creds_cli_fetch_state fstate = {
1067 .status = NT_STATUS_INTERNAL_ERROR,
1068 .proposed_flags = context->client.proposed_flags,
1069 .required_flags = context->client.required_flags,
1071 NTSTATUS status;
1073 fstate.mem_ctx = mem_ctx;
1074 status = dbwrap_parse_record(context->db.ctx,
1075 context->db.key_data,
1076 netlogon_creds_cli_fetch_parser,
1077 &fstate);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 return status;
1081 if (!NT_STATUS_IS_OK(fstate.status)) {
1082 return fstate.status;
1085 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
1086 *pcreds = fstate.creds;
1087 return NT_STATUS_OK;
1091 * It is really important to try SamLogonEx here,
1092 * because multiple processes can talk to the same
1093 * domain controller, without using the credential
1094 * chain.
1096 * With a normal SamLogon call, we must keep the
1097 * credentials chain updated and intact between all
1098 * users of the machine account (which would imply
1099 * cross-node communication for every NTLM logon).
1101 * The credentials chain is not per NETLOGON pipe
1102 * connection, but globally on the server/client pair
1103 * by computer name.
1105 * It's also important to use NetlogonValidationSamInfo4 (6),
1106 * because it relies on the rpc transport encryption
1107 * and avoids using the global netlogon schannel
1108 * session key to en/decrypt secret information
1109 * like the user_session_key for network logons.
1111 * [MS-APDS] 3.1.5.2 NTLM Network Logon
1112 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
1113 * NETLOGON_NEG_AUTHENTICATED_RPC set together
1114 * are the indication that the server supports
1115 * NetlogonValidationSamInfo4 (6). And it must only
1116 * be used if "SealSecureChannel" is used.
1118 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
1119 * check is done in netlogon_creds_cli_LogonSamLogon*().
1122 context->server.cached_flags = fstate.creds->negotiate_flags;
1123 context->server.try_validation6 = true;
1124 context->server.try_logon_ex = true;
1125 context->server.try_logon_with = true;
1127 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
1128 context->server.try_validation6 = false;
1129 context->server.try_logon_ex = false;
1131 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
1132 context->server.try_validation6 = false;
1135 *pcreds = fstate.creds;
1136 return NT_STATUS_OK;
1139 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
1140 TALLOC_CTX *mem_ctx,
1141 struct netlogon_creds_CredentialState **creds)
1143 struct netlogon_creds_cli_lock_state *state =
1144 tevent_req_data(req,
1145 struct netlogon_creds_cli_lock_state);
1146 NTSTATUS status;
1148 if (tevent_req_is_nterror(req, &status)) {
1149 tevent_req_received(req);
1150 return status;
1153 talloc_steal(state->creds, state->locked_state);
1154 state->locked_state->creds = state->creds;
1155 *creds = talloc_move(mem_ctx, &state->creds);
1156 tevent_req_received(req);
1157 return NT_STATUS_OK;
1160 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
1161 TALLOC_CTX *mem_ctx,
1162 struct netlogon_creds_CredentialState **creds)
1164 TALLOC_CTX *frame = talloc_stackframe();
1165 struct tevent_context *ev;
1166 struct tevent_req *req;
1167 NTSTATUS status = NT_STATUS_NO_MEMORY;
1169 ev = samba_tevent_context_init(frame);
1170 if (ev == NULL) {
1171 goto fail;
1173 req = netlogon_creds_cli_lock_send(frame, ev, context);
1174 if (req == NULL) {
1175 goto fail;
1177 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1178 goto fail;
1180 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
1181 fail:
1182 TALLOC_FREE(frame);
1183 return status;
1186 struct netlogon_creds_cli_lck {
1187 struct netlogon_creds_cli_context *context;
1190 struct netlogon_creds_cli_lck_state {
1191 struct netlogon_creds_cli_lck *lck;
1192 enum netlogon_creds_cli_lck_type type;
1195 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
1196 static int netlogon_creds_cli_lck_destructor(
1197 struct netlogon_creds_cli_lck *lck);
1199 struct tevent_req *netlogon_creds_cli_lck_send(
1200 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1201 struct netlogon_creds_cli_context *context,
1202 enum netlogon_creds_cli_lck_type type)
1204 struct tevent_req *req, *subreq;
1205 struct netlogon_creds_cli_lck_state *state;
1206 enum g_lock_type gtype;
1208 req = tevent_req_create(mem_ctx, &state,
1209 struct netlogon_creds_cli_lck_state);
1210 if (req == NULL) {
1211 return NULL;
1214 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
1215 DBG_DEBUG("context already locked\n");
1216 tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
1217 return tevent_req_post(req, ev);
1220 switch (type) {
1221 case NETLOGON_CREDS_CLI_LCK_SHARED:
1222 gtype = G_LOCK_READ;
1223 break;
1224 case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
1225 gtype = G_LOCK_WRITE;
1226 break;
1227 default:
1228 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1229 return tevent_req_post(req, ev);
1232 state->lck = talloc(state, struct netlogon_creds_cli_lck);
1233 if (tevent_req_nomem(state->lck, req)) {
1234 return tevent_req_post(req, ev);
1236 state->lck->context = context;
1237 state->type = type;
1239 subreq = g_lock_lock_send(state, ev,
1240 context->db.g_ctx,
1241 string_term_tdb_data(context->db.key_name),
1242 gtype,
1243 NULL, NULL);
1244 if (tevent_req_nomem(subreq, req)) {
1245 return tevent_req_post(req, ev);
1247 tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
1249 return req;
1252 static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
1254 struct tevent_req *req = tevent_req_callback_data(
1255 subreq, struct tevent_req);
1256 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1257 req, struct netlogon_creds_cli_lck_state);
1258 NTSTATUS status;
1260 status = g_lock_lock_recv(subreq);
1261 TALLOC_FREE(subreq);
1262 if (tevent_req_nterror(req, status)) {
1263 return;
1266 state->lck->context->db.lock = state->type;
1267 talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
1269 tevent_req_done(req);
1272 static int netlogon_creds_cli_lck_destructor(
1273 struct netlogon_creds_cli_lck *lck)
1275 struct netlogon_creds_cli_context *ctx = lck->context;
1276 NTSTATUS status;
1278 status = g_lock_unlock(ctx->db.g_ctx,
1279 string_term_tdb_data(ctx->db.key_name));
1280 if (!NT_STATUS_IS_OK(status)) {
1281 DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
1282 smb_panic("g_lock_unlock failed");
1284 ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
1285 return 0;
1288 NTSTATUS netlogon_creds_cli_lck_recv(
1289 struct tevent_req *req, TALLOC_CTX *mem_ctx,
1290 struct netlogon_creds_cli_lck **lck)
1292 struct netlogon_creds_cli_lck_state *state = tevent_req_data(
1293 req, struct netlogon_creds_cli_lck_state);
1294 NTSTATUS status;
1296 if (tevent_req_is_nterror(req, &status)) {
1297 return status;
1299 *lck = talloc_move(mem_ctx, &state->lck);
1300 return NT_STATUS_OK;
1303 NTSTATUS netlogon_creds_cli_lck(
1304 struct netlogon_creds_cli_context *context,
1305 enum netlogon_creds_cli_lck_type type,
1306 TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
1308 TALLOC_CTX *frame = talloc_stackframe();
1309 struct tevent_context *ev;
1310 struct tevent_req *req;
1311 NTSTATUS status = NT_STATUS_NO_MEMORY;
1313 ev = samba_tevent_context_init(frame);
1314 if (ev == NULL) {
1315 goto fail;
1317 req = netlogon_creds_cli_lck_send(frame, ev, context, type);
1318 if (req == NULL) {
1319 goto fail;
1321 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1322 goto fail;
1324 status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
1325 fail:
1326 TALLOC_FREE(frame);
1327 return status;
1330 static NTSTATUS netlogon_creds_cli_check_transport(
1331 enum dcerpc_AuthType auth_type,
1332 enum dcerpc_AuthLevel auth_level,
1333 const struct netlogon_creds_CredentialState *creds,
1334 enum dcerpc_AuthLevel min_auth_level)
1336 if (auth_level < min_auth_level) {
1337 return NT_STATUS_INVALID_PARAMETER_MIX;
1340 if (creds == NULL) {
1341 return NT_STATUS_INVALID_PARAMETER_MIX;
1344 if (creds->authenticate_kerberos) {
1345 if (auth_type == DCERPC_AUTH_TYPE_KRB5) {
1346 switch (auth_level) {
1347 case DCERPC_AUTH_LEVEL_PRIVACY:
1348 return NT_STATUS_OK;
1349 default:
1350 break;
1354 return NT_STATUS_INVALID_PARAMETER_MIX;
1357 if (auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1358 switch (auth_level) {
1359 case DCERPC_AUTH_LEVEL_INTEGRITY:
1360 case DCERPC_AUTH_LEVEL_PRIVACY:
1361 return NT_STATUS_OK;
1362 default:
1363 break;
1366 return NT_STATUS_INVALID_PARAMETER_MIX;
1369 if (creds->negotiate_flags & NETLOGON_NEG_AUTHENTICATED_RPC) {
1371 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1372 * it should be used, which means
1373 * we had a chance to verify no downgrade
1374 * happened.
1376 * This relies on netlogon_creds_cli_check*
1377 * being called before, as first request after
1378 * the DCERPC bind.
1380 return NT_STATUS_INVALID_PARAMETER_MIX;
1383 return NT_STATUS_OK;
1386 struct netlogon_creds_cli_auth_state {
1387 struct tevent_context *ev;
1388 struct netlogon_creds_cli_context *context;
1389 struct dcerpc_binding_handle *binding_handle;
1390 enum dcerpc_AuthType auth_type;
1391 enum dcerpc_AuthLevel auth_level;
1392 uint8_t num_nt_hashes;
1393 uint8_t idx_nt_hashes;
1394 const struct samr_Password * const *nt_hashes;
1395 const struct samr_Password *used_nt_hash;
1396 char *srv_name_slash;
1397 uint32_t current_flags;
1398 struct netr_Credential client_challenge;
1399 struct netr_Credential server_challenge;
1400 struct netlogon_creds_CredentialState *creds;
1401 struct netr_Credential client_credential;
1402 struct netr_Credential server_credential;
1403 uint32_t negotiate_flags;
1404 uint32_t rid;
1405 bool try_krb5;
1406 bool require_krb5;
1407 bool try_auth3;
1408 bool try_auth2;
1409 bool require_auth2;
1412 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1414 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
1416 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
1417 struct tevent_context *ev,
1418 struct netlogon_creds_cli_context *context,
1419 struct dcerpc_binding_handle *b,
1420 uint8_t num_nt_hashes,
1421 const struct samr_Password * const *nt_hashes)
1423 struct tevent_req *req;
1424 struct netlogon_creds_cli_auth_state *state;
1425 NTSTATUS status;
1426 bool client_use_krb5_netlogon = false;
1427 bool reject_aes_servers = false;
1429 req = tevent_req_create(mem_ctx, &state,
1430 struct netlogon_creds_cli_auth_state);
1431 if (req == NULL) {
1432 return NULL;
1435 state->ev = ev;
1436 state->context = context;
1437 state->binding_handle = b;
1438 if (num_nt_hashes < 1) {
1439 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1440 return tevent_req_post(req, ev);
1442 if (num_nt_hashes > 4) {
1443 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1444 return tevent_req_post(req, ev);
1447 state->num_nt_hashes = num_nt_hashes;
1448 state->idx_nt_hashes = 0;
1449 state->nt_hashes = nt_hashes;
1451 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1452 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1453 return tevent_req_post(req, ev);
1456 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1457 context->server.computer);
1458 if (tevent_req_nomem(state->srv_name_slash, req)) {
1459 return tevent_req_post(req, ev);
1462 dcerpc_binding_handle_auth_info(state->binding_handle,
1463 &state->auth_type,
1464 &state->auth_level);
1466 state->try_auth3 = true;
1467 state->try_auth2 = true;
1469 if (context->client.required_flags != 0) {
1470 state->require_auth2 = true;
1473 netlogon_creds_cli_use_kerberos(context,
1474 &client_use_krb5_netlogon,
1475 &reject_aes_servers);
1476 if (client_use_krb5_netlogon) {
1477 if (state->auth_type == DCERPC_AUTH_TYPE_KRB5 &&
1478 state->auth_level == DCERPC_AUTH_LEVEL_PRIVACY)
1480 state->try_krb5 = true;
1484 if (reject_aes_servers) {
1485 if (!state->try_krb5) {
1486 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1487 return tevent_req_post(req, ev);
1489 state->require_krb5 = true;
1492 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1493 state->current_flags = context->client.proposed_flags;
1495 status = dbwrap_purge(state->context->db.ctx,
1496 state->context->db.key_data);
1497 if (tevent_req_nterror(req, status)) {
1498 return tevent_req_post(req, ev);
1501 if (state->try_krb5) {
1502 struct tevent_req *subreq = NULL;
1504 state->creds = netlogon_creds_kerberos_init(state,
1505 state->context->client.account,
1506 state->context->client.computer,
1507 state->context->client.type,
1508 state->context->client.proposed_flags,
1509 NULL, /* client_sid */
1510 state->current_flags);
1511 if (tevent_req_nomem(state->creds, req)) {
1512 return tevent_req_post(req, ev);
1515 state->negotiate_flags = state->context->client.proposed_flags;
1517 subreq = dcerpc_netr_ServerAuthenticateKerberos_send(state,
1518 state->ev,
1519 state->binding_handle,
1520 state->srv_name_slash,
1521 state->context->client.account,
1522 state->context->client.type,
1523 state->context->client.computer,
1524 &state->negotiate_flags,
1525 &state->rid);
1526 if (tevent_req_nomem(subreq, req)) {
1527 return tevent_req_post(req, ev);
1529 tevent_req_set_callback(subreq,
1530 netlogon_creds_cli_auth_srvauth_done,
1531 req);
1532 return req;
1535 netlogon_creds_cli_auth_challenge_start(req);
1536 if (!tevent_req_is_in_progress(req)) {
1537 return tevent_req_post(req, ev);
1540 return req;
1543 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1545 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1547 struct netlogon_creds_cli_auth_state *state =
1548 tevent_req_data(req,
1549 struct netlogon_creds_cli_auth_state);
1550 struct tevent_req *subreq;
1552 TALLOC_FREE(state->creds);
1554 netlogon_creds_random_challenge(&state->client_challenge);
1556 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1557 state->binding_handle,
1558 state->srv_name_slash,
1559 state->context->client.computer,
1560 &state->client_challenge,
1561 &state->server_challenge);
1562 if (tevent_req_nomem(subreq, req)) {
1563 return;
1565 tevent_req_set_callback(subreq,
1566 netlogon_creds_cli_auth_challenge_done,
1567 req);
1570 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1572 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1574 struct tevent_req *req =
1575 tevent_req_callback_data(subreq,
1576 struct tevent_req);
1577 struct netlogon_creds_cli_auth_state *state =
1578 tevent_req_data(req,
1579 struct netlogon_creds_cli_auth_state);
1580 NTSTATUS status;
1581 NTSTATUS result;
1583 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1584 TALLOC_FREE(subreq);
1585 if (tevent_req_nterror(req, status)) {
1586 return;
1588 if (tevent_req_nterror(req, result)) {
1589 return;
1592 if (!state->try_krb5 && !state->try_auth3 && !state->try_auth2) {
1593 state->current_flags = 0;
1596 /* Calculate the session key and client credentials */
1598 state->creds = netlogon_creds_client_init(state,
1599 state->context->client.account,
1600 state->context->client.computer,
1601 state->context->client.type,
1602 &state->client_challenge,
1603 &state->server_challenge,
1604 state->used_nt_hash,
1605 &state->client_credential,
1606 state->context->client.proposed_flags,
1607 state->current_flags);
1608 if (tevent_req_nomem(state->creds, req)) {
1609 return;
1612 if (state->try_auth3) {
1614 * We always need to send our proposed flags,
1615 * even if state->current_flags we passed to
1616 * netlogon_creds_client_init() is already downgraded,
1618 * An old server will just ignore the bits it doesn't
1619 * know about, but LogonGetCapabilities(level=2) will
1620 * report what we proposed.
1622 state->negotiate_flags = state->context->client.proposed_flags;
1624 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1625 state->binding_handle,
1626 state->srv_name_slash,
1627 state->context->client.account,
1628 state->context->client.type,
1629 state->context->client.computer,
1630 &state->client_credential,
1631 &state->server_credential,
1632 &state->negotiate_flags,
1633 &state->rid);
1634 if (tevent_req_nomem(subreq, req)) {
1635 return;
1637 } else if (state->try_auth2) {
1639 * We always need to send our proposed flags,
1640 * even if state->current_flags we passed to
1641 * netlogon_creds_client_init() is already downgraded,
1643 * An old server will just ignore the bits it doesn't
1644 * know about, but LogonGetCapabilities(level=2) will
1645 * report what we proposed.
1647 state->negotiate_flags = state->context->client.proposed_flags;
1648 state->rid = 0;
1650 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1651 state->binding_handle,
1652 state->srv_name_slash,
1653 state->context->client.account,
1654 state->context->client.type,
1655 state->context->client.computer,
1656 &state->client_credential,
1657 &state->server_credential,
1658 &state->negotiate_flags);
1659 if (tevent_req_nomem(subreq, req)) {
1660 return;
1662 } else {
1663 state->negotiate_flags = 0;
1664 state->rid = 0;
1666 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1667 state->binding_handle,
1668 state->srv_name_slash,
1669 state->context->client.account,
1670 state->context->client.type,
1671 state->context->client.computer,
1672 &state->client_credential,
1673 &state->server_credential);
1674 if (tevent_req_nomem(subreq, req)) {
1675 return;
1678 tevent_req_set_callback(subreq,
1679 netlogon_creds_cli_auth_srvauth_done,
1680 req);
1683 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1685 struct tevent_req *req =
1686 tevent_req_callback_data(subreq,
1687 struct tevent_req);
1688 struct netlogon_creds_cli_auth_state *state =
1689 tevent_req_data(req,
1690 struct netlogon_creds_cli_auth_state);
1691 NTSTATUS status;
1692 NTSTATUS result;
1693 bool downgraded;
1695 if (state->try_krb5) {
1696 status = dcerpc_netr_ServerAuthenticateKerberos_recv(subreq, state,
1697 &result);
1698 TALLOC_FREE(subreq);
1699 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1700 if (state->require_krb5) {
1701 status = NT_STATUS_DOWNGRADE_DETECTED;
1702 tevent_req_nterror(req, status);
1703 return;
1705 state->try_krb5 = false;
1706 netlogon_creds_cli_auth_challenge_start(req);
1707 return;
1709 if (tevent_req_nterror(req, status)) {
1710 return;
1713 * We don't downgrade if this fails
1714 * without PROCNUM_OUT_OF_RANGE.
1716 if (tevent_req_nterror(req, result)) {
1717 return;
1719 } else if (state->try_auth3) {
1720 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1721 &result);
1722 TALLOC_FREE(subreq);
1723 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1724 state->try_auth3 = false;
1725 netlogon_creds_cli_auth_challenge_start(req);
1726 return;
1728 if (tevent_req_nterror(req, status)) {
1729 return;
1731 } else if (state->try_auth2) {
1732 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1733 &result);
1734 TALLOC_FREE(subreq);
1735 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1736 state->try_auth2 = false;
1737 if (state->require_auth2) {
1738 status = NT_STATUS_DOWNGRADE_DETECTED;
1739 tevent_req_nterror(req, status);
1740 return;
1742 netlogon_creds_cli_auth_challenge_start(req);
1743 return;
1745 if (tevent_req_nterror(req, status)) {
1746 return;
1748 } else {
1749 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1750 &result);
1751 TALLOC_FREE(subreq);
1752 if (tevent_req_nterror(req, status)) {
1753 return;
1757 if (!NT_STATUS_IS_OK(result) &&
1758 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1760 tevent_req_nterror(req, result);
1761 return;
1764 downgraded = netlogon_creds_cli_downgraded(
1765 state->negotiate_flags,
1766 state->creds->authenticate_kerberos,
1767 state->context->client.proposed_flags,
1768 state->context->client.required_flags);
1769 if (downgraded) {
1770 if (NT_STATUS_IS_OK(result)) {
1771 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1772 return;
1774 tevent_req_nterror(req, result);
1775 return;
1778 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1779 uint32_t prop_f = state->context->client.proposed_flags;
1780 uint32_t cli_f = state->current_flags;
1781 uint32_t srv_f = state->negotiate_flags;
1782 uint32_t nego_f = cli_f & srv_f;
1784 if (cli_f == prop_f && nego_f != prop_f) {
1786 * lets retry with the negotiated flags
1788 state->current_flags = nego_f;
1789 netlogon_creds_cli_auth_challenge_start(req);
1790 return;
1793 state->idx_nt_hashes += 1;
1794 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1796 * we already retried, giving up...
1798 tevent_req_nterror(req, result);
1799 return;
1803 * lets retry with the old nt hash.
1805 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1806 state->current_flags = state->context->client.proposed_flags;
1807 netlogon_creds_cli_auth_challenge_start(req);
1808 return;
1811 status = netlogon_creds_client_verify(state->creds,
1812 &state->server_credential,
1813 state->auth_type,
1814 state->auth_level);
1815 if (tevent_req_nterror(req, status)) {
1816 return;
1819 if (state->current_flags == state->context->client.proposed_flags) {
1821 * Without a downgrade in the crypto we proposed
1822 * we can adjust the otherwise downgraded flags
1823 * before storing.
1825 state->creds->negotiate_flags &= state->negotiate_flags;
1826 } else if (state->current_flags != state->negotiate_flags) {
1828 * We downgraded our crypto once, we should not
1829 * allow any additional downgrade!
1831 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1832 return;
1835 state->creds->client_sid.sub_auths[0] = state->rid;
1836 status = netlogon_creds_cli_store_internal(state->context,
1837 state->creds);
1838 if (tevent_req_nterror(req, status)) {
1839 return;
1842 tevent_req_done(req);
1845 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1846 uint8_t *idx_nt_hashes)
1848 struct netlogon_creds_cli_auth_state *state =
1849 tevent_req_data(req,
1850 struct netlogon_creds_cli_auth_state);
1851 NTSTATUS status;
1853 *idx_nt_hashes = 0;
1855 if (tevent_req_is_nterror(req, &status)) {
1856 tevent_req_received(req);
1857 return status;
1860 *idx_nt_hashes = state->idx_nt_hashes;
1861 tevent_req_received(req);
1862 return NT_STATUS_OK;
1865 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1866 struct dcerpc_binding_handle *b,
1867 uint8_t num_nt_hashes,
1868 const struct samr_Password * const *nt_hashes,
1869 uint8_t *idx_nt_hashes)
1871 TALLOC_CTX *frame = talloc_stackframe();
1872 struct tevent_context *ev;
1873 struct tevent_req *req;
1874 NTSTATUS status = NT_STATUS_NO_MEMORY;
1876 *idx_nt_hashes = 0;
1878 ev = samba_tevent_context_init(frame);
1879 if (ev == NULL) {
1880 goto fail;
1882 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1883 num_nt_hashes, nt_hashes);
1884 if (req == NULL) {
1885 goto fail;
1887 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1888 goto fail;
1890 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1891 fail:
1892 TALLOC_FREE(frame);
1893 return status;
1896 struct netlogon_creds_cli_check_state {
1897 struct tevent_context *ev;
1898 struct netlogon_creds_cli_context *context;
1899 struct dcerpc_binding_handle *binding_handle;
1900 enum dcerpc_AuthType auth_type;
1901 enum dcerpc_AuthLevel auth_level;
1903 char *srv_name_slash;
1905 union netr_Capabilities caps;
1906 union netr_Capabilities client_caps;
1908 struct netlogon_creds_CredentialState *creds;
1909 struct netr_Authenticator req_auth;
1910 struct netr_Authenticator rep_auth;
1912 union netr_CONTROL_QUERY_INFORMATION ctrl_info;
1915 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1916 NTSTATUS status);
1917 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req *subreq);
1918 static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq);
1920 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1921 struct tevent_context *ev,
1922 struct netlogon_creds_cli_context *context,
1923 struct dcerpc_binding_handle *b)
1925 struct tevent_req *req;
1926 struct netlogon_creds_cli_check_state *state;
1927 struct tevent_req *subreq;
1928 NTSTATUS status;
1930 req = tevent_req_create(mem_ctx, &state,
1931 struct netlogon_creds_cli_check_state);
1932 if (req == NULL) {
1933 return NULL;
1936 state->ev = ev;
1937 state->context = context;
1938 state->binding_handle = b;
1940 if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
1941 tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
1942 return tevent_req_post(req, ev);
1945 status = netlogon_creds_cli_get_internal(context, state,
1946 &state->creds);
1947 if (tevent_req_nterror(req, status)) {
1948 return tevent_req_post(req, ev);
1951 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1952 context->server.computer);
1953 if (tevent_req_nomem(state->srv_name_slash, req)) {
1954 return tevent_req_post(req, ev);
1957 dcerpc_binding_handle_auth_info(state->binding_handle,
1958 &state->auth_type,
1959 &state->auth_level);
1961 status = netlogon_creds_cli_check_transport(state->auth_type,
1962 state->auth_level,
1963 state->creds,
1964 DCERPC_AUTH_LEVEL_INTEGRITY);
1965 if (tevent_req_nterror(req, status)) {
1966 return tevent_req_post(req, ev);
1970 * we defer all callbacks in order to cleanup
1971 * the database record.
1973 tevent_req_defer_callback(req, state->ev);
1975 status = netlogon_creds_client_authenticator(state->creds,
1976 &state->req_auth);
1977 if (tevent_req_nterror(req, status)) {
1978 return tevent_req_post(req, ev);
1980 ZERO_STRUCT(state->rep_auth);
1982 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1983 state->binding_handle,
1984 state->srv_name_slash,
1985 state->context->client.computer,
1986 &state->req_auth,
1987 &state->rep_auth,
1989 &state->caps);
1990 if (tevent_req_nomem(subreq, req)) {
1991 return tevent_req_post(req, ev);
1994 tevent_req_set_callback(subreq,
1995 netlogon_creds_cli_check_negotiate_caps,
1996 req);
1998 return req;
2001 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
2002 NTSTATUS status)
2004 struct netlogon_creds_cli_check_state *state =
2005 tevent_req_data(req,
2006 struct netlogon_creds_cli_check_state);
2008 if (state->creds == NULL) {
2009 return;
2012 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2013 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2014 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2015 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2016 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2017 TALLOC_FREE(state->creds);
2018 return;
2021 netlogon_creds_cli_delete_lck(state->context);
2022 TALLOC_FREE(state->creds);
2025 static void netlogon_creds_cli_check_control_do(struct tevent_req *req);
2027 static void netlogon_creds_cli_check_negotiate_caps(struct tevent_req *subreq)
2029 struct tevent_req *req =
2030 tevent_req_callback_data(subreq,
2031 struct tevent_req);
2032 struct netlogon_creds_cli_check_state *state =
2033 tevent_req_data(req,
2034 struct netlogon_creds_cli_check_state);
2035 NTSTATUS status;
2036 NTSTATUS result;
2038 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
2039 &result);
2040 TALLOC_FREE(subreq);
2041 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2043 * Note that the negotiated flags are already checked
2044 * for our required flags after the ServerAuthenticate3/2 call.
2046 uint32_t negotiated = state->creds->negotiate_flags;
2048 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
2050 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
2051 * already, we expect this to work!
2053 status = NT_STATUS_DOWNGRADE_DETECTED;
2054 tevent_req_nterror(req, status);
2055 netlogon_creds_cli_check_cleanup(req, status);
2056 return;
2059 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
2061 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
2062 * we expect this to work at least as far as the
2063 * NOT_SUPPORTED error handled below!
2065 * NT 4.0 and Old Samba servers are not
2066 * allowed without "require strong key = no"
2068 status = NT_STATUS_DOWNGRADE_DETECTED;
2069 tevent_req_nterror(req, status);
2070 netlogon_creds_cli_check_cleanup(req, status);
2071 return;
2075 * If we not require NETLOGON_NEG_SUPPORTS_AES or
2076 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
2077 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2079 * This is needed against NT 4.0 and old Samba servers.
2081 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
2082 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
2083 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
2084 * with the next request as the sequence number processing
2085 * gets out of sync.
2087 * So we'll do a LogonControl message to check that...
2089 netlogon_creds_cli_check_control_do(req);
2090 return;
2092 if (tevent_req_nterror(req, status)) {
2093 netlogon_creds_cli_check_cleanup(req, status);
2094 return;
2097 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
2099 * Note that the negotiated flags are already checked
2100 * for our required flags after the ServerAuthenticate3/2 call.
2102 uint32_t negotiated = state->creds->negotiate_flags;
2104 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
2106 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
2107 * already, we expect this to work!
2109 status = NT_STATUS_DOWNGRADE_DETECTED;
2110 tevent_req_nterror(req, status);
2111 netlogon_creds_cli_check_cleanup(req, status);
2112 return;
2116 * This is ok, the server does not support
2117 * NETLOGON_NEG_SUPPORTS_AES.
2119 * netr_LogonGetCapabilities() was
2120 * netr_LogonDummyRoutine1() before
2121 * NETLOGON_NEG_SUPPORTS_AES was invented.
2123 netlogon_creds_cli_check_cleanup(req, result);
2124 tevent_req_done(req);
2125 return;
2128 status = netlogon_creds_client_verify(state->creds,
2129 &state->rep_auth.cred,
2130 state->auth_type,
2131 state->auth_level);
2132 if (tevent_req_nterror(req, status)) {
2133 netlogon_creds_cli_check_cleanup(req, status);
2134 return;
2137 if (tevent_req_nterror(req, result)) {
2138 netlogon_creds_cli_check_cleanup(req, result);
2139 return;
2142 if (state->caps.server_capabilities != state->creds->negotiate_flags) {
2143 status = NT_STATUS_DOWNGRADE_DETECTED;
2144 tevent_req_nterror(req, status);
2145 netlogon_creds_cli_check_cleanup(req, status);
2146 return;
2150 * This is the key check that makes this check secure. If we
2151 * get OK here (rather than NOT_SUPPORTED), then the server
2152 * did support AES. If the server only proposed STRONG_KEYS
2153 * and not AES, then it should have failed with
2154 * NOT_IMPLEMENTED. We always send AES as a client, so the
2155 * server should always have returned it.
2157 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
2158 status = NT_STATUS_DOWNGRADE_DETECTED;
2159 tevent_req_nterror(req, status);
2160 netlogon_creds_cli_check_cleanup(req, status);
2161 return;
2164 status = netlogon_creds_cli_store_internal(state->context,
2165 state->creds);
2166 if (tevent_req_nterror(req, status)) {
2167 return;
2171 * Now try to verify our client proposed flags
2172 * arrived at the server, using query_level = 2
2175 status = netlogon_creds_client_authenticator(state->creds,
2176 &state->req_auth);
2177 if (tevent_req_nterror(req, status)) {
2178 return;
2180 ZERO_STRUCT(state->rep_auth);
2182 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
2183 state->binding_handle,
2184 state->srv_name_slash,
2185 state->context->client.computer,
2186 &state->req_auth,
2187 &state->rep_auth,
2189 &state->client_caps);
2190 if (tevent_req_nomem(subreq, req)) {
2191 return;
2194 tevent_req_set_callback(subreq,
2195 netlogon_creds_cli_check_client_caps,
2196 req);
2197 return;
2200 static void netlogon_creds_cli_check_client_caps(struct tevent_req *subreq)
2202 struct tevent_req *req =
2203 tevent_req_callback_data(subreq,
2204 struct tevent_req);
2205 struct netlogon_creds_cli_check_state *state =
2206 tevent_req_data(req,
2207 struct netlogon_creds_cli_check_state);
2208 uint32_t requested_flags;
2209 NTSTATUS status;
2210 NTSTATUS result;
2212 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
2213 &result);
2214 TALLOC_FREE(subreq);
2215 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_BAD_STUB_DATA)) {
2217 * unpatched Samba server, see
2218 * https://bugzilla.samba.org/show_bug.cgi?id=15418
2220 status = NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE;
2222 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
2224 * Here we know the negotiated flags were already
2225 * verified with query_level=1, which means
2226 * the server supported NETLOGON_NEG_SUPPORTS_AES
2227 * and also NETLOGON_NEG_AUTHENTICATED_RPC
2229 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
2230 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
2231 * we should detect a faked
2232 * NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE
2233 * with the next request as the sequence number processing
2234 * gets out of sync.
2236 * So we'll do a LogonControl message to check that...
2238 netlogon_creds_cli_check_control_do(req);
2239 return;
2241 if (tevent_req_nterror(req, status)) {
2242 netlogon_creds_cli_check_cleanup(req, status);
2243 return;
2246 status = netlogon_creds_client_verify(state->creds,
2247 &state->rep_auth.cred,
2248 state->auth_type,
2249 state->auth_level);
2250 if (tevent_req_nterror(req, status)) {
2251 netlogon_creds_cli_check_cleanup(req, status);
2252 return;
2254 if (tevent_req_nterror(req, result)) {
2255 netlogon_creds_cli_check_cleanup(req, result);
2256 return;
2259 requested_flags = state->creds->client_requested_flags;
2261 if (state->client_caps.requested_flags != requested_flags) {
2262 status = NT_STATUS_DOWNGRADE_DETECTED;
2263 tevent_req_nterror(req, status);
2264 netlogon_creds_cli_check_cleanup(req, status);
2265 return;
2268 status = netlogon_creds_cli_store_internal(state->context,
2269 state->creds);
2270 if (tevent_req_nterror(req, status)) {
2271 return;
2274 tevent_req_done(req);
2277 static void netlogon_creds_cli_check_control_done(struct tevent_req *subreq);
2279 static void netlogon_creds_cli_check_control_do(struct tevent_req *req)
2281 struct netlogon_creds_cli_check_state *state =
2282 tevent_req_data(req,
2283 struct netlogon_creds_cli_check_state);
2284 struct tevent_req *subreq = NULL;
2287 * In case we got a downgrade based on a FAULT
2288 * we use a LogonControl that is supposed to
2289 * return WERR_NOT_SUPPORTED (without a DCERPC FAULT)
2290 * to verify that the connection is still ok and didn't
2291 * get out of sync.
2293 subreq = dcerpc_netr_LogonControl_send(state,
2294 state->ev,
2295 state->binding_handle,
2296 state->srv_name_slash,
2297 NETLOGON_CONTROL_QUERY,
2299 &state->ctrl_info);
2300 if (tevent_req_nomem(subreq, req)) {
2301 return;
2304 tevent_req_set_callback(subreq,
2305 netlogon_creds_cli_check_control_done,
2306 req);
2307 return;
2310 static void netlogon_creds_cli_check_control_done(struct tevent_req *subreq)
2312 struct tevent_req *req =
2313 tevent_req_callback_data(subreq,
2314 struct tevent_req);
2315 struct netlogon_creds_cli_check_state *state =
2316 tevent_req_data(req,
2317 struct netlogon_creds_cli_check_state);
2318 NTSTATUS status;
2319 WERROR result;
2321 status = dcerpc_netr_LogonControl_recv(subreq, state, &result);
2322 TALLOC_FREE(subreq);
2323 if (tevent_req_nterror(req, status)) {
2325 * We want to delete the creds,
2326 * so we pass NT_STATUS_DOWNGRADE_DETECTED
2327 * to netlogon_creds_cli_check_cleanup()
2329 status = NT_STATUS_DOWNGRADE_DETECTED;
2330 netlogon_creds_cli_check_cleanup(req, status);
2331 return;
2334 if (!W_ERROR_EQUAL(result, WERR_NOT_SUPPORTED)) {
2335 status = NT_STATUS_DOWNGRADE_DETECTED;
2336 tevent_req_nterror(req, status);
2337 netlogon_creds_cli_check_cleanup(req, status);
2338 return;
2341 tevent_req_done(req);
2344 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req,
2345 union netr_Capabilities *capabilities)
2347 struct netlogon_creds_cli_check_state *state = tevent_req_data(
2348 req, struct netlogon_creds_cli_check_state);
2349 NTSTATUS status;
2351 if (tevent_req_is_nterror(req, &status)) {
2352 netlogon_creds_cli_check_cleanup(req, status);
2353 tevent_req_received(req);
2354 return status;
2357 if (capabilities != NULL) {
2358 *capabilities = state->caps;
2361 tevent_req_received(req);
2362 return NT_STATUS_OK;
2365 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
2366 struct dcerpc_binding_handle *b,
2367 union netr_Capabilities *capabilities)
2369 TALLOC_CTX *frame = talloc_stackframe();
2370 struct tevent_context *ev;
2371 struct tevent_req *req;
2372 NTSTATUS status = NT_STATUS_NO_MEMORY;
2374 ev = samba_tevent_context_init(frame);
2375 if (ev == NULL) {
2376 goto fail;
2378 req = netlogon_creds_cli_check_send(frame, ev, context, b);
2379 if (req == NULL) {
2380 goto fail;
2382 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2383 goto fail;
2385 status = netlogon_creds_cli_check_recv(req, capabilities);
2386 fail:
2387 TALLOC_FREE(frame);
2388 return status;
2391 struct netlogon_creds_cli_ServerPasswordSet_state {
2392 struct tevent_context *ev;
2393 struct netlogon_creds_cli_context *context;
2394 struct dcerpc_binding_handle *binding_handle;
2395 uint32_t old_timeout;
2397 char *srv_name_slash;
2398 enum dcerpc_AuthType auth_type;
2399 enum dcerpc_AuthLevel auth_level;
2401 struct samr_CryptPassword samr_crypt_password;
2402 struct netr_CryptPassword netr_crypt_password;
2403 struct samr_Password samr_password;
2405 struct netlogon_creds_CredentialState *creds;
2406 struct netlogon_creds_CredentialState tmp_creds;
2407 struct netr_Authenticator req_auth;
2408 struct netr_Authenticator rep_auth;
2411 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2412 NTSTATUS status);
2413 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
2415 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
2416 struct tevent_context *ev,
2417 struct netlogon_creds_cli_context *context,
2418 struct dcerpc_binding_handle *b,
2419 const DATA_BLOB *new_password,
2420 const uint32_t *new_version)
2422 struct tevent_req *req;
2423 struct netlogon_creds_cli_ServerPasswordSet_state *state;
2424 struct tevent_req *subreq;
2425 bool ok;
2427 req = tevent_req_create(mem_ctx, &state,
2428 struct netlogon_creds_cli_ServerPasswordSet_state);
2429 if (req == NULL) {
2430 return NULL;
2433 state->ev = ev;
2434 state->context = context;
2435 state->binding_handle = b;
2437 if (new_password->length < 14) {
2438 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2439 return tevent_req_post(req, ev);
2443 * netr_ServerPasswordSet
2445 mdfour(state->samr_password.hash, new_password->data, new_password->length);
2448 * netr_ServerPasswordSet2
2450 ok = set_pw_in_buffer(state->samr_crypt_password.data,
2451 new_password);
2452 if (!ok) {
2453 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2454 return tevent_req_post(req, ev);
2457 if (new_version != NULL) {
2458 struct NL_PASSWORD_VERSION version;
2459 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
2460 uint32_t ofs = 512 - len;
2461 uint8_t *p;
2463 if (len > 500) {
2464 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2465 return tevent_req_post(req, ev);
2467 ofs -= 12;
2469 version.ReservedField = 0;
2470 version.PasswordVersionNumber = *new_version;
2471 version.PasswordVersionPresent =
2472 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
2474 p = state->samr_crypt_password.data + ofs;
2475 SIVAL(p, 0, version.ReservedField);
2476 SIVAL(p, 4, version.PasswordVersionNumber);
2477 SIVAL(p, 8, version.PasswordVersionPresent);
2480 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2481 context->server.computer);
2482 if (tevent_req_nomem(state->srv_name_slash, req)) {
2483 return tevent_req_post(req, ev);
2486 dcerpc_binding_handle_auth_info(state->binding_handle,
2487 &state->auth_type,
2488 &state->auth_level);
2490 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2491 state->context);
2492 if (tevent_req_nomem(subreq, req)) {
2493 return tevent_req_post(req, ev);
2496 tevent_req_set_callback(subreq,
2497 netlogon_creds_cli_ServerPasswordSet_locked,
2498 req);
2500 return req;
2503 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
2504 NTSTATUS status)
2506 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2507 tevent_req_data(req,
2508 struct netlogon_creds_cli_ServerPasswordSet_state);
2510 if (state->creds == NULL) {
2511 return;
2514 dcerpc_binding_handle_set_timeout(state->binding_handle,
2515 state->old_timeout);
2517 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2518 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2519 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2520 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2521 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2522 TALLOC_FREE(state->creds);
2523 return;
2526 netlogon_creds_cli_delete(state->context, state->creds);
2527 TALLOC_FREE(state->creds);
2530 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
2532 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
2534 struct tevent_req *req =
2535 tevent_req_callback_data(subreq,
2536 struct tevent_req);
2537 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2538 tevent_req_data(req,
2539 struct netlogon_creds_cli_ServerPasswordSet_state);
2540 NTSTATUS status;
2542 status = netlogon_creds_cli_lock_recv(subreq, state,
2543 &state->creds);
2544 TALLOC_FREE(subreq);
2545 if (tevent_req_nterror(req, status)) {
2546 return;
2549 status = netlogon_creds_cli_check_transport(state->auth_type,
2550 state->auth_level,
2551 state->creds,
2552 DCERPC_AUTH_LEVEL_NONE);
2553 if (tevent_req_nterror(req, status)) {
2554 return;
2557 state->old_timeout = dcerpc_binding_handle_set_timeout(
2558 state->binding_handle, 600000);
2561 * we defer all callbacks in order to cleanup
2562 * the database record.
2564 tevent_req_defer_callback(req, state->ev);
2566 state->tmp_creds = *state->creds;
2567 status = netlogon_creds_client_authenticator(&state->tmp_creds,
2568 &state->req_auth);
2569 if (tevent_req_nterror(req, status)) {
2570 return;
2572 ZERO_STRUCT(state->rep_auth);
2574 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2576 status = netlogon_creds_encrypt_samr_CryptPassword(&state->tmp_creds,
2577 &state->samr_crypt_password,
2578 state->auth_type,
2579 state->auth_level);
2580 if (tevent_req_nterror(req, status)) {
2581 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2582 return;
2585 memcpy(state->netr_crypt_password.data,
2586 state->samr_crypt_password.data, 512);
2587 state->netr_crypt_password.length =
2588 IVAL(state->samr_crypt_password.data, 512);
2590 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
2591 state->binding_handle,
2592 state->srv_name_slash,
2593 state->tmp_creds.account_name,
2594 state->tmp_creds.secure_channel_type,
2595 state->tmp_creds.computer_name,
2596 &state->req_auth,
2597 &state->rep_auth,
2598 &state->netr_crypt_password);
2599 if (tevent_req_nomem(subreq, req)) {
2600 status = NT_STATUS_NO_MEMORY;
2601 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2602 return;
2604 } else {
2605 status = netlogon_creds_encrypt_samr_Password(&state->tmp_creds,
2606 &state->samr_password,
2607 state->auth_type,
2608 state->auth_level);
2609 if (tevent_req_nterror(req, status)) {
2610 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2611 return;
2614 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
2615 state->binding_handle,
2616 state->srv_name_slash,
2617 state->tmp_creds.account_name,
2618 state->tmp_creds.secure_channel_type,
2619 state->tmp_creds.computer_name,
2620 &state->req_auth,
2621 &state->rep_auth,
2622 &state->samr_password);
2623 if (tevent_req_nomem(subreq, req)) {
2624 status = NT_STATUS_NO_MEMORY;
2625 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2626 return;
2630 tevent_req_set_callback(subreq,
2631 netlogon_creds_cli_ServerPasswordSet_done,
2632 req);
2635 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
2637 struct tevent_req *req =
2638 tevent_req_callback_data(subreq,
2639 struct tevent_req);
2640 struct netlogon_creds_cli_ServerPasswordSet_state *state =
2641 tevent_req_data(req,
2642 struct netlogon_creds_cli_ServerPasswordSet_state);
2643 NTSTATUS status;
2644 NTSTATUS result;
2646 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2647 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2648 &result);
2649 TALLOC_FREE(subreq);
2650 if (tevent_req_nterror(req, status)) {
2651 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2652 return;
2654 } else {
2655 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2656 &result);
2657 TALLOC_FREE(subreq);
2658 if (tevent_req_nterror(req, status)) {
2659 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2660 return;
2664 status = netlogon_creds_client_verify(&state->tmp_creds,
2665 &state->rep_auth.cred,
2666 state->auth_type,
2667 state->auth_level);
2668 if (tevent_req_nterror(req, status)) {
2669 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2670 return;
2673 if (tevent_req_nterror(req, result)) {
2674 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2675 return;
2678 dcerpc_binding_handle_set_timeout(state->binding_handle,
2679 state->old_timeout);
2681 *state->creds = state->tmp_creds;
2682 status = netlogon_creds_cli_store(state->context,
2683 state->creds);
2684 TALLOC_FREE(state->creds);
2685 if (tevent_req_nterror(req, status)) {
2686 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2687 return;
2690 tevent_req_done(req);
2693 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2695 NTSTATUS status;
2697 if (tevent_req_is_nterror(req, &status)) {
2698 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2699 tevent_req_received(req);
2700 return status;
2703 tevent_req_received(req);
2704 return NT_STATUS_OK;
2707 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2708 struct netlogon_creds_cli_context *context,
2709 struct dcerpc_binding_handle *b,
2710 const DATA_BLOB *new_password,
2711 const uint32_t *new_version)
2713 TALLOC_CTX *frame = talloc_stackframe();
2714 struct tevent_context *ev;
2715 struct tevent_req *req;
2716 NTSTATUS status = NT_STATUS_NO_MEMORY;
2718 ev = samba_tevent_context_init(frame);
2719 if (ev == NULL) {
2720 goto fail;
2722 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2723 new_password,
2724 new_version);
2725 if (req == NULL) {
2726 goto fail;
2728 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2729 goto fail;
2731 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2732 fail:
2733 TALLOC_FREE(frame);
2734 return status;
2737 struct netlogon_creds_cli_LogonSamLogon_state {
2738 struct tevent_context *ev;
2739 struct netlogon_creds_cli_context *context;
2740 struct dcerpc_binding_handle *binding_handle;
2742 char *srv_name_slash;
2744 enum netr_LogonInfoClass logon_level;
2745 const union netr_LogonLevel *const_logon;
2746 union netr_LogonLevel *logon;
2747 uint32_t flags;
2749 uint16_t validation_level;
2750 union netr_Validation *validation;
2751 uint8_t authoritative;
2754 * do we need encryption at the application layer?
2756 bool user_encrypt;
2757 bool try_logon_ex;
2758 bool try_validation6;
2761 * the read only credentials before we started the operation
2762 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2764 struct netlogon_creds_CredentialState *ro_creds;
2767 * The (locked) credentials used for the credential chain
2768 * used for netr_LogonSamLogonWithFlags() or
2769 * netr_LogonSamLogonWith().
2771 struct netlogon_creds_CredentialState *lk_creds;
2774 * While we have locked the global credentials (lk_creds above)
2775 * we operate an a temporary copy, because a server
2776 * may not support netr_LogonSamLogonWithFlags() and
2777 * didn't process our netr_Authenticator, so we need to
2778 * restart from lk_creds.
2780 struct netlogon_creds_CredentialState tmp_creds;
2781 struct netr_Authenticator req_auth;
2782 struct netr_Authenticator rep_auth;
2785 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2786 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2787 NTSTATUS status);
2789 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2790 struct tevent_context *ev,
2791 struct netlogon_creds_cli_context *context,
2792 struct dcerpc_binding_handle *b,
2793 enum netr_LogonInfoClass logon_level,
2794 const union netr_LogonLevel *logon,
2795 uint32_t flags)
2797 struct tevent_req *req;
2798 struct netlogon_creds_cli_LogonSamLogon_state *state;
2800 req = tevent_req_create(mem_ctx, &state,
2801 struct netlogon_creds_cli_LogonSamLogon_state);
2802 if (req == NULL) {
2803 return NULL;
2806 state->ev = ev;
2807 state->context = context;
2808 state->binding_handle = b;
2810 state->logon_level = logon_level;
2811 state->const_logon = logon;
2812 state->flags = flags;
2814 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2815 context->server.computer);
2816 if (tevent_req_nomem(state->srv_name_slash, req)) {
2817 return tevent_req_post(req, ev);
2820 switch (logon_level) {
2821 case NetlogonInteractiveInformation:
2822 case NetlogonInteractiveTransitiveInformation:
2823 case NetlogonServiceInformation:
2824 case NetlogonServiceTransitiveInformation:
2825 case NetlogonGenericInformation:
2826 state->user_encrypt = true;
2827 break;
2829 case NetlogonNetworkInformation:
2830 case NetlogonNetworkTransitiveInformation:
2831 case NetlogonTicketLogonInformation:
2832 break;
2835 state->validation = talloc_zero(state, union netr_Validation);
2836 if (tevent_req_nomem(state->validation, req)) {
2837 return tevent_req_post(req, ev);
2840 netlogon_creds_cli_LogonSamLogon_start(req);
2841 if (!tevent_req_is_in_progress(req)) {
2842 return tevent_req_post(req, ev);
2846 * we defer all callbacks in order to cleanup
2847 * the database record.
2849 tevent_req_defer_callback(req, state->ev);
2850 return req;
2853 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2854 NTSTATUS status)
2856 struct netlogon_creds_cli_LogonSamLogon_state *state =
2857 tevent_req_data(req,
2858 struct netlogon_creds_cli_LogonSamLogon_state);
2860 if (state->lk_creds == NULL) {
2861 return;
2864 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2866 * This is a hack to recover from a bug in old
2867 * Samba servers, when LogonSamLogonEx() fails:
2869 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2871 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2873 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2874 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2875 * If the sign/seal check fails.
2877 * In that case we need to cleanup the netlogon session.
2879 * It's the job of the caller to disconnect the current
2880 * connection, if netlogon_creds_cli_LogonSamLogon()
2881 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2883 if (!state->context->server.try_logon_with) {
2884 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2888 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2889 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2890 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2891 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2892 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2893 TALLOC_FREE(state->lk_creds);
2894 return;
2897 netlogon_creds_cli_delete(state->context, state->lk_creds);
2898 TALLOC_FREE(state->lk_creds);
2901 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2903 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2905 struct netlogon_creds_cli_LogonSamLogon_state *state =
2906 tevent_req_data(req,
2907 struct netlogon_creds_cli_LogonSamLogon_state);
2908 struct tevent_req *subreq;
2909 NTSTATUS status;
2910 enum dcerpc_AuthType auth_type;
2911 enum dcerpc_AuthLevel auth_level;
2913 TALLOC_FREE(state->ro_creds);
2914 TALLOC_FREE(state->logon);
2915 ZERO_STRUCTP(state->validation);
2917 dcerpc_binding_handle_auth_info(state->binding_handle,
2918 &auth_type, &auth_level);
2920 state->try_logon_ex = state->context->server.try_logon_ex;
2921 state->try_validation6 = state->context->server.try_validation6;
2923 if (auth_type != DCERPC_AUTH_TYPE_KRB5 &&
2924 auth_type != DCERPC_AUTH_TYPE_SCHANNEL)
2926 state->try_logon_ex = false;
2929 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2930 state->try_validation6 = false;
2933 if (state->try_logon_ex) {
2934 if (state->try_validation6) {
2935 state->validation_level = 6;
2936 } else {
2937 state->validation_level = 3;
2938 state->user_encrypt = true;
2941 state->logon = netlogon_creds_shallow_copy_logon(state,
2942 state->logon_level,
2943 state->const_logon);
2944 if (tevent_req_nomem(state->logon, req)) {
2945 status = NT_STATUS_NO_MEMORY;
2946 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2947 return;
2950 if (state->user_encrypt) {
2951 status = netlogon_creds_cli_get(state->context,
2952 state,
2953 &state->ro_creds);
2954 if (!NT_STATUS_IS_OK(status)) {
2955 status = NT_STATUS_ACCESS_DENIED;
2956 tevent_req_nterror(req, status);
2957 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2958 return;
2961 status = netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2962 state->logon_level,
2963 state->logon,
2964 auth_type,
2965 auth_level);
2966 if (!NT_STATUS_IS_OK(status)) {
2967 status = NT_STATUS_ACCESS_DENIED;
2968 tevent_req_nterror(req, status);
2969 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2970 return;
2974 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2975 state->binding_handle,
2976 state->srv_name_slash,
2977 state->context->client.computer,
2978 state->logon_level,
2979 state->logon,
2980 state->validation_level,
2981 state->validation,
2982 &state->authoritative,
2983 &state->flags);
2984 if (tevent_req_nomem(subreq, req)) {
2985 status = NT_STATUS_NO_MEMORY;
2986 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2987 return;
2989 tevent_req_set_callback(subreq,
2990 netlogon_creds_cli_LogonSamLogon_done,
2991 req);
2992 return;
2995 if (state->lk_creds == NULL) {
2996 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2997 state->context);
2998 if (tevent_req_nomem(subreq, req)) {
2999 status = NT_STATUS_NO_MEMORY;
3000 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3001 return;
3003 tevent_req_set_callback(subreq,
3004 netlogon_creds_cli_LogonSamLogon_done,
3005 req);
3006 return;
3009 state->tmp_creds = *state->lk_creds;
3010 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3011 &state->req_auth);
3012 if (tevent_req_nterror(req, status)) {
3013 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3014 return;
3016 ZERO_STRUCT(state->rep_auth);
3018 state->logon = netlogon_creds_shallow_copy_logon(state,
3019 state->logon_level,
3020 state->const_logon);
3021 if (tevent_req_nomem(state->logon, req)) {
3022 status = NT_STATUS_NO_MEMORY;
3023 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3024 return;
3027 status = netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
3028 state->logon_level,
3029 state->logon,
3030 auth_type,
3031 auth_level);
3032 if (tevent_req_nterror(req, status)) {
3033 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3034 return;
3037 state->validation_level = 3;
3039 if (state->context->server.try_logon_with) {
3040 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
3041 state->binding_handle,
3042 state->srv_name_slash,
3043 state->context->client.computer,
3044 &state->req_auth,
3045 &state->rep_auth,
3046 state->logon_level,
3047 state->logon,
3048 state->validation_level,
3049 state->validation,
3050 &state->authoritative,
3051 &state->flags);
3052 if (tevent_req_nomem(subreq, req)) {
3053 status = NT_STATUS_NO_MEMORY;
3054 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3055 return;
3057 } else {
3058 state->flags = 0;
3060 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
3061 state->binding_handle,
3062 state->srv_name_slash,
3063 state->context->client.computer,
3064 &state->req_auth,
3065 &state->rep_auth,
3066 state->logon_level,
3067 state->logon,
3068 state->validation_level,
3069 state->validation,
3070 &state->authoritative);
3071 if (tevent_req_nomem(subreq, req)) {
3072 status = NT_STATUS_NO_MEMORY;
3073 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3074 return;
3078 tevent_req_set_callback(subreq,
3079 netlogon_creds_cli_LogonSamLogon_done,
3080 req);
3083 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
3085 struct tevent_req *req =
3086 tevent_req_callback_data(subreq,
3087 struct tevent_req);
3088 struct netlogon_creds_cli_LogonSamLogon_state *state =
3089 tevent_req_data(req,
3090 struct netlogon_creds_cli_LogonSamLogon_state);
3091 enum dcerpc_AuthType auth_type;
3092 enum dcerpc_AuthLevel auth_level;
3093 NTSTATUS status;
3094 NTSTATUS result;
3095 bool ok;
3097 dcerpc_binding_handle_auth_info(state->binding_handle,
3098 &auth_type,
3099 &auth_level);
3101 if (state->try_logon_ex) {
3102 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
3103 state->validation,
3104 &result);
3105 TALLOC_FREE(subreq);
3106 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
3107 state->context->server.try_validation6 = false;
3108 state->context->server.try_logon_ex = false;
3109 netlogon_creds_cli_LogonSamLogon_start(req);
3110 return;
3112 if (tevent_req_nterror(req, status)) {
3113 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3114 return;
3117 if ((state->validation_level == 6) &&
3118 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
3119 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
3120 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
3122 state->context->server.try_validation6 = false;
3123 netlogon_creds_cli_LogonSamLogon_start(req);
3124 return;
3127 if (tevent_req_nterror(req, result)) {
3128 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
3129 return;
3132 if (state->ro_creds == NULL) {
3133 tevent_req_done(req);
3134 return;
3137 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
3138 if (!ok) {
3140 * We got a race, lets retry with on authenticator
3141 * protection.
3143 * netlogon_creds_cli_LogonSamLogon_start()
3144 * will TALLOC_FREE(state->ro_creds);
3146 state->try_logon_ex = false;
3147 netlogon_creds_cli_LogonSamLogon_start(req);
3148 return;
3151 status = netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
3152 state->validation_level,
3153 state->validation,
3154 auth_type,
3155 auth_level);
3156 if (tevent_req_nterror(req, status)) {
3157 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3158 return;
3161 tevent_req_done(req);
3162 return;
3165 if (state->lk_creds == NULL) {
3166 status = netlogon_creds_cli_lock_recv(subreq, state,
3167 &state->lk_creds);
3168 TALLOC_FREE(subreq);
3169 if (tevent_req_nterror(req, status)) {
3170 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3171 return;
3174 netlogon_creds_cli_LogonSamLogon_start(req);
3175 return;
3178 if (state->context->server.try_logon_with) {
3179 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
3180 state->validation,
3181 &result);
3182 TALLOC_FREE(subreq);
3183 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
3184 state->context->server.try_logon_with = false;
3185 netlogon_creds_cli_LogonSamLogon_start(req);
3186 return;
3188 if (tevent_req_nterror(req, status)) {
3189 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3190 return;
3192 } else {
3193 status = dcerpc_netr_LogonSamLogon_recv(subreq,
3194 state->validation,
3195 &result);
3196 TALLOC_FREE(subreq);
3197 if (tevent_req_nterror(req, status)) {
3198 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3199 return;
3203 status = netlogon_creds_client_verify(&state->tmp_creds,
3204 &state->rep_auth.cred,
3205 auth_type,
3206 auth_level);
3207 if (tevent_req_nterror(req, status)) {
3208 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3209 return;
3212 *state->lk_creds = state->tmp_creds;
3213 status = netlogon_creds_cli_store(state->context,
3214 state->lk_creds);
3215 TALLOC_FREE(state->lk_creds);
3217 if (tevent_req_nterror(req, status)) {
3218 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3219 return;
3222 if (tevent_req_nterror(req, result)) {
3223 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
3224 return;
3227 status = netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
3228 state->validation_level,
3229 state->validation,
3230 auth_type,
3231 auth_level);
3232 if (tevent_req_nterror(req, status)) {
3233 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
3234 return;
3237 tevent_req_done(req);
3240 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
3241 TALLOC_CTX *mem_ctx,
3242 uint16_t *validation_level,
3243 union netr_Validation **validation,
3244 uint8_t *authoritative,
3245 uint32_t *flags)
3247 struct netlogon_creds_cli_LogonSamLogon_state *state =
3248 tevent_req_data(req,
3249 struct netlogon_creds_cli_LogonSamLogon_state);
3250 NTSTATUS status;
3252 /* authoritative is also returned on error */
3253 *authoritative = state->authoritative;
3255 if (tevent_req_is_nterror(req, &status)) {
3256 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
3257 tevent_req_received(req);
3258 return status;
3261 *validation_level = state->validation_level;
3262 *validation = talloc_move(mem_ctx, &state->validation);
3263 *flags = state->flags;
3265 tevent_req_received(req);
3266 return NT_STATUS_OK;
3269 NTSTATUS netlogon_creds_cli_LogonSamLogon(
3270 struct netlogon_creds_cli_context *context,
3271 struct dcerpc_binding_handle *b,
3272 enum netr_LogonInfoClass logon_level,
3273 const union netr_LogonLevel *logon,
3274 TALLOC_CTX *mem_ctx,
3275 uint16_t *validation_level,
3276 union netr_Validation **validation,
3277 uint8_t *authoritative,
3278 uint32_t *flags)
3280 TALLOC_CTX *frame = talloc_stackframe();
3281 struct tevent_context *ev;
3282 struct tevent_req *req;
3283 NTSTATUS status = NT_STATUS_NO_MEMORY;
3285 ev = samba_tevent_context_init(frame);
3286 if (ev == NULL) {
3287 goto fail;
3289 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
3290 logon_level, logon,
3291 *flags);
3292 if (req == NULL) {
3293 goto fail;
3295 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3296 goto fail;
3298 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
3299 validation_level,
3300 validation,
3301 authoritative,
3302 flags);
3303 fail:
3304 TALLOC_FREE(frame);
3305 return status;
3308 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
3309 struct tevent_context *ev;
3310 struct netlogon_creds_cli_context *context;
3311 struct dcerpc_binding_handle *binding_handle;
3313 char *srv_name_slash;
3314 enum dcerpc_AuthType auth_type;
3315 enum dcerpc_AuthLevel auth_level;
3317 const char *site_name;
3318 uint32_t dns_ttl;
3319 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
3321 struct netlogon_creds_CredentialState *creds;
3322 struct netlogon_creds_CredentialState tmp_creds;
3323 struct netr_Authenticator req_auth;
3324 struct netr_Authenticator rep_auth;
3327 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
3328 NTSTATUS status);
3329 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
3331 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
3332 struct tevent_context *ev,
3333 struct netlogon_creds_cli_context *context,
3334 struct dcerpc_binding_handle *b,
3335 const char *site_name,
3336 uint32_t dns_ttl,
3337 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3339 struct tevent_req *req;
3340 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
3341 struct tevent_req *subreq;
3343 req = tevent_req_create(mem_ctx, &state,
3344 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3345 if (req == NULL) {
3346 return NULL;
3349 state->ev = ev;
3350 state->context = context;
3351 state->binding_handle = b;
3353 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3354 context->server.computer);
3355 if (tevent_req_nomem(state->srv_name_slash, req)) {
3356 return tevent_req_post(req, ev);
3359 state->site_name = site_name;
3360 state->dns_ttl = dns_ttl;
3361 state->dns_names = dns_names;
3363 dcerpc_binding_handle_auth_info(state->binding_handle,
3364 &state->auth_type,
3365 &state->auth_level);
3367 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3368 state->context);
3369 if (tevent_req_nomem(subreq, req)) {
3370 return tevent_req_post(req, ev);
3373 tevent_req_set_callback(subreq,
3374 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
3375 req);
3377 return req;
3380 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
3381 NTSTATUS status)
3383 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3384 tevent_req_data(req,
3385 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3387 if (state->creds == NULL) {
3388 return;
3391 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3392 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3393 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3394 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3395 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3396 TALLOC_FREE(state->creds);
3397 return;
3400 netlogon_creds_cli_delete(state->context, state->creds);
3401 TALLOC_FREE(state->creds);
3404 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
3406 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
3408 struct tevent_req *req =
3409 tevent_req_callback_data(subreq,
3410 struct tevent_req);
3411 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3412 tevent_req_data(req,
3413 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3414 NTSTATUS status;
3416 status = netlogon_creds_cli_lock_recv(subreq, state,
3417 &state->creds);
3418 TALLOC_FREE(subreq);
3419 if (tevent_req_nterror(req, status)) {
3420 return;
3423 status = netlogon_creds_cli_check_transport(state->auth_type,
3424 state->auth_level,
3425 state->creds,
3426 DCERPC_AUTH_LEVEL_NONE);
3427 if (tevent_req_nterror(req, status)) {
3428 return;
3432 * we defer all callbacks in order to cleanup
3433 * the database record.
3435 tevent_req_defer_callback(req, state->ev);
3437 state->tmp_creds = *state->creds;
3438 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3439 &state->req_auth);
3440 if (tevent_req_nterror(req, status)) {
3441 return;
3443 ZERO_STRUCT(state->rep_auth);
3445 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
3446 state->binding_handle,
3447 state->srv_name_slash,
3448 state->tmp_creds.computer_name,
3449 &state->req_auth,
3450 &state->rep_auth,
3451 state->site_name,
3452 state->dns_ttl,
3453 state->dns_names);
3454 if (tevent_req_nomem(subreq, req)) {
3455 status = NT_STATUS_NO_MEMORY;
3456 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3457 return;
3460 tevent_req_set_callback(subreq,
3461 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
3462 req);
3465 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
3467 struct tevent_req *req =
3468 tevent_req_callback_data(subreq,
3469 struct tevent_req);
3470 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
3471 tevent_req_data(req,
3472 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
3473 NTSTATUS status;
3474 NTSTATUS result;
3477 * We use state->dns_names as the memory context, as this is
3478 * the only in/out variable and it has been overwritten by the
3479 * out parameter from the server.
3481 * We need to preserve the return value until the caller can use it.
3483 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
3484 &result);
3485 TALLOC_FREE(subreq);
3486 if (tevent_req_nterror(req, status)) {
3487 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3488 return;
3491 status = netlogon_creds_client_verify(&state->tmp_creds,
3492 &state->rep_auth.cred,
3493 state->auth_type,
3494 state->auth_level);
3495 if (tevent_req_nterror(req, status)) {
3496 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3497 return;
3500 *state->creds = state->tmp_creds;
3501 status = netlogon_creds_cli_store(state->context,
3502 state->creds);
3503 TALLOC_FREE(state->creds);
3505 if (tevent_req_nterror(req, status)) {
3506 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3507 return;
3510 if (tevent_req_nterror(req, result)) {
3511 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
3512 return;
3515 tevent_req_done(req);
3518 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
3520 NTSTATUS status;
3522 if (tevent_req_is_nterror(req, &status)) {
3523 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
3524 tevent_req_received(req);
3525 return status;
3528 tevent_req_received(req);
3529 return NT_STATUS_OK;
3532 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
3533 struct netlogon_creds_cli_context *context,
3534 struct dcerpc_binding_handle *b,
3535 const char *site_name,
3536 uint32_t dns_ttl,
3537 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
3539 TALLOC_CTX *frame = talloc_stackframe();
3540 struct tevent_context *ev;
3541 struct tevent_req *req;
3542 NTSTATUS status = NT_STATUS_NO_MEMORY;
3544 ev = samba_tevent_context_init(frame);
3545 if (ev == NULL) {
3546 goto fail;
3548 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
3549 site_name,
3550 dns_ttl,
3551 dns_names);
3552 if (req == NULL) {
3553 goto fail;
3555 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3556 goto fail;
3558 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
3559 fail:
3560 TALLOC_FREE(frame);
3561 return status;
3564 struct netlogon_creds_cli_ServerGetTrustInfo_state {
3565 struct tevent_context *ev;
3566 struct netlogon_creds_cli_context *context;
3567 struct dcerpc_binding_handle *binding_handle;
3569 char *srv_name_slash;
3570 enum dcerpc_AuthType auth_type;
3571 enum dcerpc_AuthLevel auth_level;
3573 struct samr_Password new_owf_password;
3574 struct samr_Password old_owf_password;
3575 struct netr_TrustInfo *trust_info;
3577 struct netlogon_creds_CredentialState *creds;
3578 struct netlogon_creds_CredentialState tmp_creds;
3579 struct netr_Authenticator req_auth;
3580 struct netr_Authenticator rep_auth;
3583 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3584 NTSTATUS status);
3585 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
3587 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
3588 struct tevent_context *ev,
3589 struct netlogon_creds_cli_context *context,
3590 struct dcerpc_binding_handle *b)
3592 struct tevent_req *req;
3593 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
3594 struct tevent_req *subreq;
3596 req = tevent_req_create(mem_ctx, &state,
3597 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3598 if (req == NULL) {
3599 return NULL;
3602 state->ev = ev;
3603 state->context = context;
3604 state->binding_handle = b;
3606 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3607 context->server.computer);
3608 if (tevent_req_nomem(state->srv_name_slash, req)) {
3609 return tevent_req_post(req, ev);
3612 dcerpc_binding_handle_auth_info(state->binding_handle,
3613 &state->auth_type,
3614 &state->auth_level);
3616 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3617 state->context);
3618 if (tevent_req_nomem(subreq, req)) {
3619 return tevent_req_post(req, ev);
3622 tevent_req_set_callback(subreq,
3623 netlogon_creds_cli_ServerGetTrustInfo_locked,
3624 req);
3626 return req;
3629 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
3630 NTSTATUS status)
3632 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3633 tevent_req_data(req,
3634 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3636 if (state->creds == NULL) {
3637 return;
3640 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3641 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3642 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3643 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3644 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3645 TALLOC_FREE(state->creds);
3646 return;
3649 netlogon_creds_cli_delete(state->context, state->creds);
3650 TALLOC_FREE(state->creds);
3653 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
3655 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
3657 struct tevent_req *req =
3658 tevent_req_callback_data(subreq,
3659 struct tevent_req);
3660 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3661 tevent_req_data(req,
3662 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3663 NTSTATUS status;
3665 status = netlogon_creds_cli_lock_recv(subreq, state,
3666 &state->creds);
3667 TALLOC_FREE(subreq);
3668 if (tevent_req_nterror(req, status)) {
3669 return;
3672 status = netlogon_creds_cli_check_transport(state->auth_type,
3673 state->auth_level,
3674 state->creds,
3675 DCERPC_AUTH_LEVEL_PRIVACY);
3676 if (tevent_req_nterror(req, status)) {
3677 return;
3681 * we defer all callbacks in order to cleanup
3682 * the database record.
3684 tevent_req_defer_callback(req, state->ev);
3686 state->tmp_creds = *state->creds;
3687 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3688 &state->req_auth);
3689 if (tevent_req_nterror(req, status)) {
3690 return;
3692 ZERO_STRUCT(state->rep_auth);
3694 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3695 state->binding_handle,
3696 state->srv_name_slash,
3697 state->tmp_creds.account_name,
3698 state->tmp_creds.secure_channel_type,
3699 state->tmp_creds.computer_name,
3700 &state->req_auth,
3701 &state->rep_auth,
3702 &state->new_owf_password,
3703 &state->old_owf_password,
3704 &state->trust_info);
3705 if (tevent_req_nomem(subreq, req)) {
3706 status = NT_STATUS_NO_MEMORY;
3707 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3708 return;
3711 tevent_req_set_callback(subreq,
3712 netlogon_creds_cli_ServerGetTrustInfo_done,
3713 req);
3716 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3718 struct tevent_req *req =
3719 tevent_req_callback_data(subreq,
3720 struct tevent_req);
3721 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3722 tevent_req_data(req,
3723 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3724 NTSTATUS status;
3725 NTSTATUS result;
3728 * We use state->dns_names as the memory context, as this is
3729 * the only in/out variable and it has been overwritten by the
3730 * out parameter from the server.
3732 * We need to preserve the return value until the caller can use it.
3734 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3735 TALLOC_FREE(subreq);
3736 if (tevent_req_nterror(req, status)) {
3737 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3738 return;
3741 status = netlogon_creds_client_verify(&state->tmp_creds,
3742 &state->rep_auth.cred,
3743 state->auth_type,
3744 state->auth_level);
3745 if (tevent_req_nterror(req, status)) {
3746 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3747 return;
3750 status = netlogon_creds_decrypt_samr_Password(&state->tmp_creds,
3751 &state->new_owf_password,
3752 state->auth_type,
3753 state->auth_level);
3754 if (tevent_req_nterror(req, status)) {
3755 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3756 return;
3758 status = netlogon_creds_decrypt_samr_Password(&state->tmp_creds,
3759 &state->old_owf_password,
3760 state->auth_type,
3761 state->auth_level);
3762 if (tevent_req_nterror(req, status)) {
3763 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3764 return;
3767 *state->creds = state->tmp_creds;
3768 status = netlogon_creds_cli_store(state->context,
3769 state->creds);
3770 TALLOC_FREE(state->creds);
3771 if (tevent_req_nterror(req, status)) {
3772 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3773 return;
3776 if (tevent_req_nterror(req, result)) {
3777 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3778 return;
3781 tevent_req_done(req);
3784 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3785 TALLOC_CTX *mem_ctx,
3786 struct samr_Password *new_owf_password,
3787 struct samr_Password *old_owf_password,
3788 struct netr_TrustInfo **trust_info)
3790 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3791 tevent_req_data(req,
3792 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3793 NTSTATUS status;
3795 if (tevent_req_is_nterror(req, &status)) {
3796 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3797 tevent_req_received(req);
3798 return status;
3801 if (new_owf_password != NULL) {
3802 *new_owf_password = state->new_owf_password;
3804 if (old_owf_password != NULL) {
3805 *old_owf_password = state->old_owf_password;
3807 if (trust_info != NULL) {
3808 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3811 tevent_req_received(req);
3812 return NT_STATUS_OK;
3815 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3816 struct netlogon_creds_cli_context *context,
3817 struct dcerpc_binding_handle *b,
3818 TALLOC_CTX *mem_ctx,
3819 struct samr_Password *new_owf_password,
3820 struct samr_Password *old_owf_password,
3821 struct netr_TrustInfo **trust_info)
3823 TALLOC_CTX *frame = talloc_stackframe();
3824 struct tevent_context *ev;
3825 struct tevent_req *req;
3826 NTSTATUS status = NT_STATUS_NO_MEMORY;
3828 ev = samba_tevent_context_init(frame);
3829 if (ev == NULL) {
3830 goto fail;
3832 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3833 if (req == NULL) {
3834 goto fail;
3836 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3837 goto fail;
3839 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3840 mem_ctx,
3841 new_owf_password,
3842 old_owf_password,
3843 trust_info);
3844 fail:
3845 TALLOC_FREE(frame);
3846 return status;
3849 struct netlogon_creds_cli_GetForestTrustInformation_state {
3850 struct tevent_context *ev;
3851 struct netlogon_creds_cli_context *context;
3852 struct dcerpc_binding_handle *binding_handle;
3854 char *srv_name_slash;
3855 enum dcerpc_AuthType auth_type;
3856 enum dcerpc_AuthLevel auth_level;
3858 uint32_t flags;
3859 struct lsa_ForestTrustInformation *forest_trust_info;
3861 struct netlogon_creds_CredentialState *creds;
3862 struct netlogon_creds_CredentialState tmp_creds;
3863 struct netr_Authenticator req_auth;
3864 struct netr_Authenticator rep_auth;
3867 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3868 NTSTATUS status);
3869 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3871 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3872 struct tevent_context *ev,
3873 struct netlogon_creds_cli_context *context,
3874 struct dcerpc_binding_handle *b)
3876 struct tevent_req *req;
3877 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3878 struct tevent_req *subreq;
3880 req = tevent_req_create(mem_ctx, &state,
3881 struct netlogon_creds_cli_GetForestTrustInformation_state);
3882 if (req == NULL) {
3883 return NULL;
3886 state->ev = ev;
3887 state->context = context;
3888 state->binding_handle = b;
3890 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3891 context->server.computer);
3892 if (tevent_req_nomem(state->srv_name_slash, req)) {
3893 return tevent_req_post(req, ev);
3896 state->flags = 0;
3898 dcerpc_binding_handle_auth_info(state->binding_handle,
3899 &state->auth_type,
3900 &state->auth_level);
3902 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3903 state->context);
3904 if (tevent_req_nomem(subreq, req)) {
3905 return tevent_req_post(req, ev);
3908 tevent_req_set_callback(subreq,
3909 netlogon_creds_cli_GetForestTrustInformation_locked,
3910 req);
3912 return req;
3915 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3916 NTSTATUS status)
3918 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3919 tevent_req_data(req,
3920 struct netlogon_creds_cli_GetForestTrustInformation_state);
3922 if (state->creds == NULL) {
3923 return;
3926 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3927 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3928 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3929 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3930 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3931 TALLOC_FREE(state->creds);
3932 return;
3935 netlogon_creds_cli_delete(state->context, state->creds);
3936 TALLOC_FREE(state->creds);
3939 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3941 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3943 struct tevent_req *req =
3944 tevent_req_callback_data(subreq,
3945 struct tevent_req);
3946 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3947 tevent_req_data(req,
3948 struct netlogon_creds_cli_GetForestTrustInformation_state);
3949 NTSTATUS status;
3951 status = netlogon_creds_cli_lock_recv(subreq, state,
3952 &state->creds);
3953 TALLOC_FREE(subreq);
3954 if (tevent_req_nterror(req, status)) {
3955 return;
3958 status = netlogon_creds_cli_check_transport(state->auth_type,
3959 state->auth_level,
3960 state->creds,
3961 DCERPC_AUTH_LEVEL_NONE);
3962 if (tevent_req_nterror(req, status)) {
3963 return;
3967 * we defer all callbacks in order to cleanup
3968 * the database record.
3970 tevent_req_defer_callback(req, state->ev);
3972 state->tmp_creds = *state->creds;
3973 status = netlogon_creds_client_authenticator(&state->tmp_creds,
3974 &state->req_auth);
3975 if (tevent_req_nterror(req, status)) {
3976 return;
3978 ZERO_STRUCT(state->rep_auth);
3980 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3981 state->binding_handle,
3982 state->srv_name_slash,
3983 state->tmp_creds.computer_name,
3984 &state->req_auth,
3985 &state->rep_auth,
3986 state->flags,
3987 &state->forest_trust_info);
3988 if (tevent_req_nomem(subreq, req)) {
3989 status = NT_STATUS_NO_MEMORY;
3990 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3991 return;
3994 tevent_req_set_callback(subreq,
3995 netlogon_creds_cli_GetForestTrustInformation_done,
3996 req);
3999 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
4001 struct tevent_req *req =
4002 tevent_req_callback_data(subreq,
4003 struct tevent_req);
4004 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
4005 tevent_req_data(req,
4006 struct netlogon_creds_cli_GetForestTrustInformation_state);
4007 NTSTATUS status;
4008 NTSTATUS result;
4011 * We use state->dns_names as the memory context, as this is
4012 * the only in/out variable and it has been overwritten by the
4013 * out parameter from the server.
4015 * We need to preserve the return value until the caller can use it.
4017 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
4018 TALLOC_FREE(subreq);
4019 if (tevent_req_nterror(req, status)) {
4020 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
4021 return;
4024 status = netlogon_creds_client_verify(&state->tmp_creds,
4025 &state->rep_auth.cred,
4026 state->auth_type,
4027 state->auth_level);
4028 if (tevent_req_nterror(req, status)) {
4029 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
4030 return;
4033 *state->creds = state->tmp_creds;
4034 status = netlogon_creds_cli_store(state->context,
4035 state->creds);
4036 TALLOC_FREE(state->creds);
4038 if (tevent_req_nterror(req, status)) {
4039 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
4040 return;
4043 if (tevent_req_nterror(req, result)) {
4044 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
4045 return;
4048 tevent_req_done(req);
4051 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
4052 TALLOC_CTX *mem_ctx,
4053 struct lsa_ForestTrustInformation **forest_trust_info)
4055 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
4056 tevent_req_data(req,
4057 struct netlogon_creds_cli_GetForestTrustInformation_state);
4058 NTSTATUS status;
4060 if (tevent_req_is_nterror(req, &status)) {
4061 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
4062 tevent_req_received(req);
4063 return status;
4066 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
4068 tevent_req_received(req);
4069 return NT_STATUS_OK;
4072 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
4073 struct netlogon_creds_cli_context *context,
4074 struct dcerpc_binding_handle *b,
4075 TALLOC_CTX *mem_ctx,
4076 struct lsa_ForestTrustInformation **forest_trust_info)
4078 TALLOC_CTX *frame = talloc_stackframe();
4079 struct tevent_context *ev;
4080 struct tevent_req *req;
4081 NTSTATUS status = NT_STATUS_NO_MEMORY;
4083 ev = samba_tevent_context_init(frame);
4084 if (ev == NULL) {
4085 goto fail;
4087 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
4088 if (req == NULL) {
4089 goto fail;
4091 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4092 goto fail;
4094 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
4095 mem_ctx,
4096 forest_trust_info);
4097 fail:
4098 TALLOC_FREE(frame);
4099 return status;
4101 struct netlogon_creds_cli_SendToSam_state {
4102 struct tevent_context *ev;
4103 struct netlogon_creds_cli_context *context;
4104 struct dcerpc_binding_handle *binding_handle;
4106 char *srv_name_slash;
4107 enum dcerpc_AuthType auth_type;
4108 enum dcerpc_AuthLevel auth_level;
4110 DATA_BLOB opaque;
4112 struct netlogon_creds_CredentialState *creds;
4113 struct netlogon_creds_CredentialState tmp_creds;
4114 struct netr_Authenticator req_auth;
4115 struct netr_Authenticator rep_auth;
4118 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
4119 NTSTATUS status);
4120 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
4122 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
4123 struct tevent_context *ev,
4124 struct netlogon_creds_cli_context *context,
4125 struct dcerpc_binding_handle *b,
4126 struct netr_SendToSamBase *message)
4128 struct tevent_req *req;
4129 struct netlogon_creds_cli_SendToSam_state *state;
4130 struct tevent_req *subreq;
4131 enum ndr_err_code ndr_err;
4133 req = tevent_req_create(mem_ctx, &state,
4134 struct netlogon_creds_cli_SendToSam_state);
4135 if (req == NULL) {
4136 return NULL;
4139 state->ev = ev;
4140 state->context = context;
4141 state->binding_handle = b;
4143 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
4144 context->server.computer);
4145 if (tevent_req_nomem(state->srv_name_slash, req)) {
4146 return tevent_req_post(req, ev);
4149 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
4150 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
4151 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4152 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
4153 tevent_req_nterror(req, status);
4154 return tevent_req_post(req, ev);
4157 dcerpc_binding_handle_auth_info(state->binding_handle,
4158 &state->auth_type,
4159 &state->auth_level);
4161 subreq = netlogon_creds_cli_lock_send(state, state->ev,
4162 state->context);
4163 if (tevent_req_nomem(subreq, req)) {
4164 return tevent_req_post(req, ev);
4167 tevent_req_set_callback(subreq,
4168 netlogon_creds_cli_SendToSam_locked,
4169 req);
4171 return req;
4174 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
4175 NTSTATUS status)
4177 struct netlogon_creds_cli_SendToSam_state *state =
4178 tevent_req_data(req,
4179 struct netlogon_creds_cli_SendToSam_state);
4181 if (state->creds == NULL) {
4182 return;
4185 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
4186 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
4187 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
4188 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
4189 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
4190 TALLOC_FREE(state->creds);
4191 return;
4194 netlogon_creds_cli_delete(state->context, state->creds);
4195 TALLOC_FREE(state->creds);
4198 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
4200 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
4202 struct tevent_req *req =
4203 tevent_req_callback_data(subreq,
4204 struct tevent_req);
4205 struct netlogon_creds_cli_SendToSam_state *state =
4206 tevent_req_data(req,
4207 struct netlogon_creds_cli_SendToSam_state);
4208 NTSTATUS status;
4210 status = netlogon_creds_cli_lock_recv(subreq, state,
4211 &state->creds);
4212 TALLOC_FREE(subreq);
4213 if (tevent_req_nterror(req, status)) {
4214 return;
4217 status = netlogon_creds_cli_check_transport(state->auth_type,
4218 state->auth_level,
4219 state->creds,
4220 DCERPC_AUTH_LEVEL_NONE);
4221 if (tevent_req_nterror(req, status)) {
4222 return;
4226 * we defer all callbacks in order to cleanup
4227 * the database record.
4229 tevent_req_defer_callback(req, state->ev);
4231 state->tmp_creds = *state->creds;
4232 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4233 &state->req_auth);
4234 if (tevent_req_nterror(req, status)) {
4235 return;
4237 ZERO_STRUCT(state->rep_auth);
4239 status = netlogon_creds_encrypt_SendToSam(&state->tmp_creds,
4240 state->opaque.data,
4241 state->opaque.length,
4242 state->auth_type,
4243 state->auth_level);
4244 if (tevent_req_nterror(req, status)) {
4245 netlogon_creds_cli_SendToSam_cleanup(req, status);
4246 return;
4249 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
4250 state->binding_handle,
4251 state->srv_name_slash,
4252 state->tmp_creds.computer_name,
4253 &state->req_auth,
4254 &state->rep_auth,
4255 state->opaque.data,
4256 state->opaque.length);
4257 if (tevent_req_nomem(subreq, req)) {
4258 status = NT_STATUS_NO_MEMORY;
4259 netlogon_creds_cli_SendToSam_cleanup(req, status);
4260 return;
4263 tevent_req_set_callback(subreq,
4264 netlogon_creds_cli_SendToSam_done,
4265 req);
4268 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
4270 struct tevent_req *req =
4271 tevent_req_callback_data(subreq,
4272 struct tevent_req);
4273 struct netlogon_creds_cli_SendToSam_state *state =
4274 tevent_req_data(req,
4275 struct netlogon_creds_cli_SendToSam_state);
4276 NTSTATUS status;
4277 NTSTATUS result;
4279 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
4280 TALLOC_FREE(subreq);
4281 if (tevent_req_nterror(req, status)) {
4282 netlogon_creds_cli_SendToSam_cleanup(req, status);
4283 return;
4286 status = netlogon_creds_client_verify(&state->tmp_creds,
4287 &state->rep_auth.cred,
4288 state->auth_type,
4289 state->auth_level);
4290 if (tevent_req_nterror(req, status)) {
4291 netlogon_creds_cli_SendToSam_cleanup(req, status);
4292 return;
4295 *state->creds = state->tmp_creds;
4296 status = netlogon_creds_cli_store(state->context,
4297 state->creds);
4298 TALLOC_FREE(state->creds);
4300 if (tevent_req_nterror(req, status)) {
4301 netlogon_creds_cli_SendToSam_cleanup(req, status);
4302 return;
4306 * Creds must be stored before we send back application errors
4307 * e.g. NT_STATUS_NOT_IMPLEMENTED
4309 if (tevent_req_nterror(req, result)) {
4310 netlogon_creds_cli_SendToSam_cleanup(req, result);
4311 return;
4314 tevent_req_done(req);
4317 NTSTATUS netlogon_creds_cli_SendToSam_recv(struct tevent_req *req)
4319 NTSTATUS status;
4321 if (tevent_req_is_nterror(req, &status)) {
4322 netlogon_creds_cli_SendToSam_cleanup(req, status);
4323 tevent_req_received(req);
4324 return status;
4327 tevent_req_received(req);
4328 return NT_STATUS_OK;
4331 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
4332 struct dcerpc_binding_handle *b,
4333 struct netr_SendToSamBase *message)
4335 TALLOC_CTX *frame = talloc_stackframe();
4336 struct tevent_context *ev;
4337 struct tevent_req *req;
4338 NTSTATUS status = NT_STATUS_NO_MEMORY;
4340 ev = samba_tevent_context_init(frame);
4341 if (ev == NULL) {
4342 goto fail;
4344 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
4345 if (req == NULL) {
4346 goto fail;
4348 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4349 goto fail;
4351 status = netlogon_creds_cli_SendToSam_recv(req);
4352 fail:
4353 TALLOC_FREE(frame);
4354 return status;
4357 struct netlogon_creds_cli_LogonGetDomainInfo_state {
4358 struct tevent_context *ev;
4359 struct netlogon_creds_cli_context *context;
4360 struct dcerpc_binding_handle *binding_handle;
4362 char *srv_name_slash;
4363 enum dcerpc_AuthType auth_type;
4364 enum dcerpc_AuthLevel auth_level;
4366 uint32_t level;
4367 union netr_WorkstationInfo *query;
4368 union netr_DomainInfo *info;
4370 struct netlogon_creds_CredentialState *creds;
4371 struct netlogon_creds_CredentialState tmp_creds;
4372 struct netr_Authenticator req_auth;
4373 struct netr_Authenticator rep_auth;
4376 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4377 NTSTATUS status);
4378 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq);
4380 struct tevent_req *netlogon_creds_cli_LogonGetDomainInfo_send(TALLOC_CTX *mem_ctx,
4381 struct tevent_context *ev,
4382 struct netlogon_creds_cli_context *context,
4383 struct dcerpc_binding_handle *b,
4384 uint32_t level,
4385 union netr_WorkstationInfo *query)
4387 struct tevent_req *req;
4388 struct netlogon_creds_cli_LogonGetDomainInfo_state *state;
4389 struct tevent_req *subreq;
4391 req = tevent_req_create(mem_ctx, &state,
4392 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4393 if (req == NULL) {
4394 return NULL;
4397 state->ev = ev;
4398 state->context = context;
4399 state->binding_handle = b;
4401 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
4402 context->server.computer);
4403 if (tevent_req_nomem(state->srv_name_slash, req)) {
4404 return tevent_req_post(req, ev);
4407 state->level = level;
4408 state->query = query;
4409 state->info = talloc_zero(state, union netr_DomainInfo);
4410 if (tevent_req_nomem(state->info, req)) {
4411 return tevent_req_post(req, ev);
4414 dcerpc_binding_handle_auth_info(state->binding_handle,
4415 &state->auth_type,
4416 &state->auth_level);
4418 subreq = netlogon_creds_cli_lock_send(state, state->ev,
4419 state->context);
4420 if (tevent_req_nomem(subreq, req)) {
4421 return tevent_req_post(req, ev);
4424 tevent_req_set_callback(subreq,
4425 netlogon_creds_cli_LogonGetDomainInfo_locked,
4426 req);
4428 return req;
4431 static void netlogon_creds_cli_LogonGetDomainInfo_cleanup(struct tevent_req *req,
4432 NTSTATUS status)
4434 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4435 tevent_req_data(req,
4436 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4438 if (state->creds == NULL) {
4439 return;
4442 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
4443 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
4444 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
4445 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
4446 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
4447 TALLOC_FREE(state->creds);
4448 return;
4451 netlogon_creds_cli_delete(state->context, state->creds);
4454 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq);
4456 static void netlogon_creds_cli_LogonGetDomainInfo_locked(struct tevent_req *subreq)
4458 struct tevent_req *req =
4459 tevent_req_callback_data(subreq,
4460 struct tevent_req);
4461 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4462 tevent_req_data(req,
4463 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4464 NTSTATUS status;
4466 status = netlogon_creds_cli_lock_recv(subreq, state,
4467 &state->creds);
4468 TALLOC_FREE(subreq);
4469 if (tevent_req_nterror(req, status)) {
4470 return;
4473 status = netlogon_creds_cli_check_transport(state->auth_type,
4474 state->auth_level,
4475 state->creds,
4476 DCERPC_AUTH_LEVEL_NONE);
4477 if (tevent_req_nterror(req, status)) {
4478 return;
4482 * we defer all callbacks in order to cleanup
4483 * the database record.
4485 tevent_req_defer_callback(req, state->ev);
4487 state->tmp_creds = *state->creds;
4488 status = netlogon_creds_client_authenticator(&state->tmp_creds,
4489 &state->req_auth);
4490 if (tevent_req_nterror(req, status)) {
4491 return;
4493 ZERO_STRUCT(state->rep_auth);
4495 subreq = dcerpc_netr_LogonGetDomainInfo_send(state, state->ev,
4496 state->binding_handle,
4497 state->srv_name_slash,
4498 state->tmp_creds.computer_name,
4499 &state->req_auth,
4500 &state->rep_auth,
4501 state->level,
4502 state->query,
4503 state->info);
4504 if (tevent_req_nomem(subreq, req)) {
4505 status = NT_STATUS_NO_MEMORY;
4506 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4507 return;
4510 tevent_req_set_callback(subreq,
4511 netlogon_creds_cli_LogonGetDomainInfo_done,
4512 req);
4515 static void netlogon_creds_cli_LogonGetDomainInfo_done(struct tevent_req *subreq)
4517 struct tevent_req *req =
4518 tevent_req_callback_data(subreq,
4519 struct tevent_req);
4520 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4521 tevent_req_data(req,
4522 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4523 NTSTATUS status;
4524 NTSTATUS result;
4527 * We use state->dns_names as the memory context, as this is
4528 * the only in/out variable and it has been overwritten by the
4529 * out parameter from the server.
4531 * We need to preserve the return value until the caller can use it.
4533 status = dcerpc_netr_LogonGetDomainInfo_recv(subreq, state->info, &result);
4534 TALLOC_FREE(subreq);
4535 if (tevent_req_nterror(req, status)) {
4536 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4537 return;
4540 status = netlogon_creds_client_verify(&state->tmp_creds,
4541 &state->rep_auth.cred,
4542 state->auth_type,
4543 state->auth_level);
4544 if (tevent_req_nterror(req, status)) {
4545 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4546 return;
4549 if (tevent_req_nterror(req, result)) {
4550 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, result);
4551 return;
4554 *state->creds = state->tmp_creds;
4555 status = netlogon_creds_cli_store(state->context,
4556 state->creds);
4557 if (tevent_req_nterror(req, status)) {
4558 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4559 return;
4562 tevent_req_done(req);
4565 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo_recv(struct tevent_req *req,
4566 TALLOC_CTX *mem_ctx,
4567 union netr_DomainInfo **info)
4569 struct netlogon_creds_cli_LogonGetDomainInfo_state *state =
4570 tevent_req_data(req,
4571 struct netlogon_creds_cli_LogonGetDomainInfo_state);
4572 NTSTATUS status;
4574 if (tevent_req_is_nterror(req, &status)) {
4575 netlogon_creds_cli_LogonGetDomainInfo_cleanup(req, status);
4576 tevent_req_received(req);
4577 return status;
4580 *info = talloc_move(mem_ctx, &state->info);
4582 tevent_req_received(req);
4583 return NT_STATUS_OK;
4586 NTSTATUS netlogon_creds_cli_LogonGetDomainInfo(
4587 struct netlogon_creds_cli_context *context,
4588 struct dcerpc_binding_handle *b,
4589 TALLOC_CTX *mem_ctx,
4590 uint32_t level,
4591 union netr_WorkstationInfo *query,
4592 union netr_DomainInfo **info)
4594 TALLOC_CTX *frame = talloc_stackframe();
4595 struct tevent_context *ev;
4596 struct tevent_req *req;
4597 NTSTATUS status = NT_STATUS_OK;
4599 ev = samba_tevent_context_init(frame);
4600 if (ev == NULL) {
4601 goto fail;
4603 req = netlogon_creds_cli_LogonGetDomainInfo_send(frame, ev, context, b,
4604 level, query);
4605 if (req == NULL) {
4606 goto fail;
4608 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
4609 goto fail;
4611 status = netlogon_creds_cli_LogonGetDomainInfo_recv(req,
4612 mem_ctx,
4613 info);
4614 fail:
4615 TALLOC_FREE(frame);
4616 return status;