s3:libsmb: let get_ipc_connect() use CLI_FULL_CONNECTION_FORCE_SMB1
[Samba.git] / libcli / auth / netlogon_creds_cli.c
blob526ee3962fcc22876c8aff8ad0ae45b0abb1dca1
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/crypto.h"
42 struct netlogon_creds_cli_locked_state;
44 struct netlogon_creds_cli_context {
45 struct {
46 const char *computer;
47 const char *account;
48 uint32_t proposed_flags;
49 uint32_t required_flags;
50 enum netr_SchannelType type;
51 enum dcerpc_AuthLevel auth_level;
52 } client;
54 struct {
55 const char *computer;
56 const char *netbios_domain;
57 uint32_t cached_flags;
58 bool try_validation6;
59 bool try_logon_ex;
60 bool try_logon_with;
61 } server;
63 struct {
64 const char *key_name;
65 TDB_DATA key_data;
66 struct db_context *ctx;
67 struct g_lock_ctx *g_ctx;
68 struct netlogon_creds_cli_locked_state *locked_state;
69 } db;
72 struct netlogon_creds_cli_locked_state {
73 struct netlogon_creds_cli_context *context;
74 bool is_glocked;
75 struct netlogon_creds_CredentialState *creds;
78 static int netlogon_creds_cli_locked_state_destructor(
79 struct netlogon_creds_cli_locked_state *state)
81 struct netlogon_creds_cli_context *context = state->context;
83 if (context == NULL) {
84 return 0;
87 if (context->db.locked_state == state) {
88 context->db.locked_state = NULL;
91 if (state->is_glocked) {
92 g_lock_unlock(context->db.g_ctx,
93 context->db.key_name);
96 return 0;
99 static NTSTATUS netlogon_creds_cli_context_common(
100 const char *client_computer,
101 const char *client_account,
102 enum netr_SchannelType type,
103 enum dcerpc_AuthLevel auth_level,
104 uint32_t proposed_flags,
105 uint32_t required_flags,
106 const char *server_computer,
107 const char *server_netbios_domain,
108 TALLOC_CTX *mem_ctx,
109 struct netlogon_creds_cli_context **_context)
111 struct netlogon_creds_cli_context *context = NULL;
112 TALLOC_CTX *frame = talloc_stackframe();
113 char *_key_name = NULL;
114 char *server_netbios_name = NULL;
115 char *p = NULL;
117 *_context = NULL;
119 context = talloc_zero(mem_ctx, struct netlogon_creds_cli_context);
120 if (context == NULL) {
121 TALLOC_FREE(frame);
122 return NT_STATUS_NO_MEMORY;
125 context->client.computer = talloc_strdup(context, client_computer);
126 if (context->client.computer == NULL) {
127 TALLOC_FREE(context);
128 TALLOC_FREE(frame);
129 return NT_STATUS_NO_MEMORY;
132 context->client.account = talloc_strdup(context, client_account);
133 if (context->client.account == NULL) {
134 TALLOC_FREE(context);
135 TALLOC_FREE(frame);
136 return NT_STATUS_NO_MEMORY;
139 context->client.proposed_flags = proposed_flags;
140 context->client.required_flags = required_flags;
141 context->client.type = type;
142 context->client.auth_level = auth_level;
144 context->server.computer = talloc_strdup(context, server_computer);
145 if (context->server.computer == NULL) {
146 TALLOC_FREE(context);
147 TALLOC_FREE(frame);
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 TALLOC_FREE(frame);
155 return NT_STATUS_NO_MEMORY;
159 * TODO:
160 * Force the callers to provide a unique
161 * value for server_computer and use this directly.
163 * For now we have to deal with
164 * "HOSTNAME" vs. "hostname.example.com".
166 server_netbios_name = talloc_strdup(frame, server_computer);
167 if (server_netbios_name == NULL) {
168 TALLOC_FREE(context);
169 TALLOC_FREE(frame);
170 return NT_STATUS_NO_MEMORY;
173 p = strchr(server_netbios_name, '.');
174 if (p != NULL) {
175 p[0] = '\0';
178 _key_name = talloc_asprintf(frame, "CLI[%s/%s]/SRV[%s/%s]",
179 client_computer,
180 client_account,
181 server_netbios_name,
182 server_netbios_domain);
183 if (_key_name == NULL) {
184 TALLOC_FREE(context);
185 TALLOC_FREE(frame);
186 return NT_STATUS_NO_MEMORY;
189 context->db.key_name = talloc_strdup_upper(context, _key_name);
190 if (context->db.key_name == NULL) {
191 TALLOC_FREE(context);
192 TALLOC_FREE(frame);
193 return NT_STATUS_NO_MEMORY;
196 context->db.key_data = string_term_tdb_data(context->db.key_name);
198 *_context = context;
199 TALLOC_FREE(frame);
200 return NT_STATUS_OK;
203 static struct db_context *netlogon_creds_cli_global_db;
205 NTSTATUS netlogon_creds_cli_set_global_db(struct db_context **db)
207 if (netlogon_creds_cli_global_db != NULL) {
208 return NT_STATUS_INVALID_PARAMETER_MIX;
211 netlogon_creds_cli_global_db = talloc_move(NULL, db);
212 return NT_STATUS_OK;
215 NTSTATUS netlogon_creds_cli_open_global_db(struct loadparm_context *lp_ctx)
217 char *fname;
218 struct db_context *global_db;
220 if (netlogon_creds_cli_global_db != NULL) {
221 return NT_STATUS_OK;
224 fname = lpcfg_private_db_path(NULL, lp_ctx, "netlogon_creds_cli");
225 if (fname == NULL) {
226 return NT_STATUS_NO_MEMORY;
229 global_db = dbwrap_local_open(NULL, lp_ctx,
230 fname, 0,
231 TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
232 O_RDWR|O_CREAT,
233 0600, DBWRAP_LOCK_ORDER_2,
234 DBWRAP_FLAG_NONE);
235 if (global_db == NULL) {
236 DEBUG(0,("netlogon_creds_cli_open_global_db: Failed to open %s - %s\n",
237 fname, strerror(errno)));
238 talloc_free(fname);
239 return NT_STATUS_NO_MEMORY;
241 TALLOC_FREE(fname);
243 netlogon_creds_cli_global_db = global_db;
244 return NT_STATUS_OK;
247 void netlogon_creds_cli_close_global_db(void)
249 TALLOC_FREE(netlogon_creds_cli_global_db);
252 NTSTATUS netlogon_creds_cli_context_global(struct loadparm_context *lp_ctx,
253 struct messaging_context *msg_ctx,
254 const char *client_account,
255 enum netr_SchannelType type,
256 const char *server_computer,
257 const char *server_netbios_domain,
258 TALLOC_CTX *mem_ctx,
259 struct netlogon_creds_cli_context **_context)
261 TALLOC_CTX *frame = talloc_stackframe();
262 NTSTATUS status;
263 struct netlogon_creds_cli_context *context = NULL;
264 const char *client_computer;
265 uint32_t proposed_flags;
266 uint32_t required_flags = 0;
267 bool reject_md5_servers = false;
268 bool require_strong_key = false;
269 int require_sign_or_seal = true;
270 bool seal_secure_channel = true;
271 enum dcerpc_AuthLevel auth_level = DCERPC_AUTH_LEVEL_NONE;
272 bool neutralize_nt4_emulation = false;
274 *_context = NULL;
276 client_computer = lpcfg_netbios_name(lp_ctx);
277 if (strlen(client_computer) > 15) {
278 return NT_STATUS_INVALID_PARAMETER_MIX;
282 * allow overwrite per domain
283 * reject md5 servers:<netbios_domain>
285 reject_md5_servers = lpcfg_reject_md5_servers(lp_ctx);
286 reject_md5_servers = lpcfg_parm_bool(lp_ctx, NULL,
287 "reject md5 servers",
288 server_netbios_domain,
289 reject_md5_servers);
292 * allow overwrite per domain
293 * require strong key:<netbios_domain>
295 require_strong_key = lpcfg_require_strong_key(lp_ctx);
296 require_strong_key = lpcfg_parm_bool(lp_ctx, NULL,
297 "require strong key",
298 server_netbios_domain,
299 require_strong_key);
302 * allow overwrite per domain
303 * client schannel:<netbios_domain>
305 require_sign_or_seal = lpcfg_client_schannel(lp_ctx);
306 require_sign_or_seal = lpcfg_parm_int(lp_ctx, NULL,
307 "client schannel",
308 server_netbios_domain,
309 require_sign_or_seal);
312 * allow overwrite per domain
313 * winbind sealed pipes:<netbios_domain>
315 seal_secure_channel = lpcfg_winbind_sealed_pipes(lp_ctx);
316 seal_secure_channel = lpcfg_parm_bool(lp_ctx, NULL,
317 "winbind sealed pipes",
318 server_netbios_domain,
319 seal_secure_channel);
322 * allow overwrite per domain
323 * neutralize nt4 emulation:<netbios_domain>
325 neutralize_nt4_emulation = lpcfg_neutralize_nt4_emulation(lp_ctx);
326 neutralize_nt4_emulation = lpcfg_parm_bool(lp_ctx, NULL,
327 "neutralize nt4 emulation",
328 server_netbios_domain,
329 neutralize_nt4_emulation);
331 proposed_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
332 proposed_flags |= NETLOGON_NEG_SUPPORTS_AES;
334 switch (type) {
335 case SEC_CHAN_WKSTA:
336 if (lpcfg_security(lp_ctx) == SEC_ADS) {
338 * AD domains should be secure
340 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
341 require_sign_or_seal = true;
342 require_strong_key = true;
344 break;
346 case SEC_CHAN_DOMAIN:
347 break;
349 case SEC_CHAN_DNS_DOMAIN:
351 * AD domains should be secure
353 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
354 require_sign_or_seal = true;
355 require_strong_key = true;
356 neutralize_nt4_emulation = true;
357 break;
359 case SEC_CHAN_BDC:
360 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
361 require_sign_or_seal = true;
362 require_strong_key = true;
363 break;
365 case SEC_CHAN_RODC:
366 required_flags |= NETLOGON_NEG_RODC_PASSTHROUGH;
367 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
368 require_sign_or_seal = true;
369 require_strong_key = true;
370 neutralize_nt4_emulation = true;
371 break;
373 default:
374 TALLOC_FREE(frame);
375 return NT_STATUS_INVALID_PARAMETER;
378 if (neutralize_nt4_emulation) {
379 proposed_flags |= NETLOGON_NEG_NEUTRALIZE_NT4_EMULATION;
382 if (require_sign_or_seal == false) {
383 proposed_flags &= ~NETLOGON_NEG_AUTHENTICATED_RPC;
384 } else {
385 required_flags |= NETLOGON_NEG_ARCFOUR;
386 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
389 if (reject_md5_servers) {
390 required_flags |= NETLOGON_NEG_ARCFOUR;
391 required_flags |= NETLOGON_NEG_PASSWORD_SET2;
392 required_flags |= NETLOGON_NEG_SUPPORTS_AES;
393 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
396 if (require_strong_key) {
397 required_flags |= NETLOGON_NEG_ARCFOUR;
398 required_flags |= NETLOGON_NEG_STRONG_KEYS;
399 required_flags |= NETLOGON_NEG_AUTHENTICATED_RPC;
402 proposed_flags |= required_flags;
404 if (seal_secure_channel) {
405 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
406 } else {
407 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
410 status = netlogon_creds_cli_context_common(client_computer,
411 client_account,
412 type,
413 auth_level,
414 proposed_flags,
415 required_flags,
416 server_computer,
417 server_netbios_domain,
418 mem_ctx,
419 &context);
420 if (!NT_STATUS_IS_OK(status)) {
421 TALLOC_FREE(frame);
422 return status;
425 if (msg_ctx != NULL) {
426 context->db.g_ctx = g_lock_ctx_init(context, msg_ctx);
427 if (context->db.g_ctx == NULL) {
428 TALLOC_FREE(context);
429 TALLOC_FREE(frame);
430 return NT_STATUS_NO_MEMORY;
434 if (netlogon_creds_cli_global_db != NULL) {
435 context->db.ctx = netlogon_creds_cli_global_db;
436 *_context = context;
437 TALLOC_FREE(frame);
438 return NT_STATUS_OK;
441 status = netlogon_creds_cli_open_global_db(lp_ctx);
442 if (!NT_STATUS_IS_OK(status)) {
443 TALLOC_FREE(context);
444 TALLOC_FREE(frame);
445 return NT_STATUS_NO_MEMORY;
448 context->db.ctx = netlogon_creds_cli_global_db;
449 *_context = context;
450 TALLOC_FREE(frame);
451 return NT_STATUS_OK;
454 NTSTATUS netlogon_creds_cli_context_tmp(const char *client_computer,
455 const char *client_account,
456 enum netr_SchannelType type,
457 uint32_t proposed_flags,
458 uint32_t required_flags,
459 enum dcerpc_AuthLevel auth_level,
460 const char *server_computer,
461 const char *server_netbios_domain,
462 TALLOC_CTX *mem_ctx,
463 struct netlogon_creds_cli_context **_context)
465 NTSTATUS status;
466 struct netlogon_creds_cli_context *context = NULL;
468 *_context = NULL;
470 status = netlogon_creds_cli_context_common(client_computer,
471 client_account,
472 type,
473 auth_level,
474 proposed_flags,
475 required_flags,
476 server_computer,
477 server_netbios_domain,
478 mem_ctx,
479 &context);
480 if (!NT_STATUS_IS_OK(status)) {
481 return status;
484 context->db.ctx = db_open_rbt(context);
485 if (context->db.ctx == NULL) {
486 talloc_free(context);
487 return NT_STATUS_NO_MEMORY;
490 *_context = context;
491 return NT_STATUS_OK;
494 char *netlogon_creds_cli_debug_string(
495 const struct netlogon_creds_cli_context *context,
496 TALLOC_CTX *mem_ctx)
498 return talloc_asprintf(mem_ctx, "netlogon_creds_cli:%s",
499 context->db.key_name);
502 enum dcerpc_AuthLevel netlogon_creds_cli_auth_level(
503 struct netlogon_creds_cli_context *context)
505 return context->client.auth_level;
508 struct netlogon_creds_cli_fetch_state {
509 TALLOC_CTX *mem_ctx;
510 struct netlogon_creds_CredentialState *creds;
511 uint32_t required_flags;
512 NTSTATUS status;
515 static void netlogon_creds_cli_fetch_parser(TDB_DATA key, TDB_DATA data,
516 void *private_data)
518 struct netlogon_creds_cli_fetch_state *state =
519 (struct netlogon_creds_cli_fetch_state *)private_data;
520 enum ndr_err_code ndr_err;
521 DATA_BLOB blob;
522 uint32_t tmp_flags;
524 state->creds = talloc_zero(state->mem_ctx,
525 struct netlogon_creds_CredentialState);
526 if (state->creds == NULL) {
527 state->status = NT_STATUS_NO_MEMORY;
528 return;
531 blob.data = data.dptr;
532 blob.length = data.dsize;
534 ndr_err = ndr_pull_struct_blob(&blob, state->creds, state->creds,
535 (ndr_pull_flags_fn_t)ndr_pull_netlogon_creds_CredentialState);
536 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
537 TALLOC_FREE(state->creds);
538 state->status = ndr_map_error2ntstatus(ndr_err);
539 return;
542 tmp_flags = state->creds->negotiate_flags;
543 tmp_flags &= state->required_flags;
544 if (tmp_flags != state->required_flags) {
545 TALLOC_FREE(state->creds);
546 state->status = NT_STATUS_DOWNGRADE_DETECTED;
547 return;
550 state->status = NT_STATUS_OK;
553 NTSTATUS netlogon_creds_cli_get(struct netlogon_creds_cli_context *context,
554 TALLOC_CTX *mem_ctx,
555 struct netlogon_creds_CredentialState **_creds)
557 NTSTATUS status;
558 struct netlogon_creds_cli_fetch_state fstate = {
559 .mem_ctx = mem_ctx,
560 .status = NT_STATUS_INTERNAL_ERROR,
561 .required_flags = context->client.required_flags,
563 static const struct netr_Credential zero_creds;
565 *_creds = NULL;
567 status = dbwrap_parse_record(context->db.ctx,
568 context->db.key_data,
569 netlogon_creds_cli_fetch_parser,
570 &fstate);
571 if (!NT_STATUS_IS_OK(status)) {
572 return status;
574 status = fstate.status;
575 if (!NT_STATUS_IS_OK(status)) {
576 return status;
580 * mark it as invalid for step operations.
582 fstate.creds->sequence = 0;
583 fstate.creds->seed = zero_creds;
584 fstate.creds->client = zero_creds;
585 fstate.creds->server = zero_creds;
587 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
588 *_creds = fstate.creds;
589 return NT_STATUS_OK;
593 * It is really important to try SamLogonEx here,
594 * because multiple processes can talk to the same
595 * domain controller, without using the credential
596 * chain.
598 * With a normal SamLogon call, we must keep the
599 * credentials chain updated and intact between all
600 * users of the machine account (which would imply
601 * cross-node communication for every NTLM logon).
603 * The credentials chain is not per NETLOGON pipe
604 * connection, but globally on the server/client pair
605 * by computer name, while the client is free to use
606 * any computer name. We include the cluster node number
607 * in our computer name in order to avoid cross node
608 * coordination of the credential chain.
610 * It's also important to use NetlogonValidationSamInfo4 (6),
611 * because it relies on the rpc transport encryption
612 * and avoids using the global netlogon schannel
613 * session key to en/decrypt secret information
614 * like the user_session_key for network logons.
616 * [MS-APDS] 3.1.5.2 NTLM Network Logon
617 * says NETLOGON_NEG_CROSS_FOREST_TRUSTS and
618 * NETLOGON_NEG_AUTHENTICATED_RPC set together
619 * are the indication that the server supports
620 * NetlogonValidationSamInfo4 (6). And it must only
621 * be used if "SealSecureChannel" is used.
623 * The "SealSecureChannel" AUTH_TYPE_SCHANNEL/AUTH_LEVEL_PRIVACY
624 * check is done in netlogon_creds_cli_LogonSamLogon*().
626 context->server.cached_flags = fstate.creds->negotiate_flags;
627 context->server.try_validation6 = true;
628 context->server.try_logon_ex = true;
629 context->server.try_logon_with = true;
631 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
632 context->server.try_validation6 = false;
633 context->server.try_logon_ex = false;
635 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
636 context->server.try_validation6 = false;
639 *_creds = fstate.creds;
640 return NT_STATUS_OK;
643 bool netlogon_creds_cli_validate(struct netlogon_creds_cli_context *context,
644 const struct netlogon_creds_CredentialState *creds1)
646 TALLOC_CTX *frame = talloc_stackframe();
647 struct netlogon_creds_CredentialState *creds2;
648 DATA_BLOB blob1;
649 DATA_BLOB blob2;
650 NTSTATUS status;
651 enum ndr_err_code ndr_err;
652 int cmp;
654 status = netlogon_creds_cli_get(context, frame, &creds2);
655 if (!NT_STATUS_IS_OK(status)) {
656 TALLOC_FREE(frame);
657 return false;
660 ndr_err = ndr_push_struct_blob(&blob1, frame, creds1,
661 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
662 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
663 TALLOC_FREE(frame);
664 return false;
667 ndr_err = ndr_push_struct_blob(&blob2, frame, creds2,
668 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
669 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
670 TALLOC_FREE(frame);
671 return false;
674 if (blob1.length != blob2.length) {
675 TALLOC_FREE(frame);
676 return false;
679 cmp = memcmp(blob1.data, blob2.data, blob1.length);
680 if (cmp != 0) {
681 TALLOC_FREE(frame);
682 return false;
685 TALLOC_FREE(frame);
686 return true;
689 NTSTATUS netlogon_creds_cli_store(struct netlogon_creds_cli_context *context,
690 struct netlogon_creds_CredentialState **_creds)
692 struct netlogon_creds_CredentialState *creds = *_creds;
693 NTSTATUS status;
694 enum ndr_err_code ndr_err;
695 DATA_BLOB blob;
696 TDB_DATA data;
698 *_creds = NULL;
700 if (context->db.locked_state == NULL) {
702 * this was not the result of netlogon_creds_cli_lock*()
704 TALLOC_FREE(creds);
705 return NT_STATUS_INVALID_PAGE_PROTECTION;
708 if (context->db.locked_state->creds != creds) {
710 * this was not the result of netlogon_creds_cli_lock*()
712 TALLOC_FREE(creds);
713 return NT_STATUS_INVALID_PAGE_PROTECTION;
716 ndr_err = ndr_push_struct_blob(&blob, creds, creds,
717 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
718 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
719 TALLOC_FREE(creds);
720 status = ndr_map_error2ntstatus(ndr_err);
721 return status;
724 data.dptr = blob.data;
725 data.dsize = blob.length;
727 status = dbwrap_store(context->db.ctx,
728 context->db.key_data,
729 data, TDB_REPLACE);
730 TALLOC_FREE(creds);
731 if (!NT_STATUS_IS_OK(status)) {
732 return status;
735 return NT_STATUS_OK;
738 NTSTATUS netlogon_creds_cli_delete(struct netlogon_creds_cli_context *context,
739 struct netlogon_creds_CredentialState **_creds)
741 struct netlogon_creds_CredentialState *creds = *_creds;
742 NTSTATUS status;
744 *_creds = NULL;
746 if (context->db.locked_state == NULL) {
748 * this was not the result of netlogon_creds_cli_lock*()
750 TALLOC_FREE(creds);
751 return NT_STATUS_INVALID_PAGE_PROTECTION;
754 if (context->db.locked_state->creds != creds) {
756 * this was not the result of netlogon_creds_cli_lock*()
758 TALLOC_FREE(creds);
759 return NT_STATUS_INVALID_PAGE_PROTECTION;
762 status = dbwrap_delete(context->db.ctx,
763 context->db.key_data);
764 TALLOC_FREE(creds);
765 if (!NT_STATUS_IS_OK(status)) {
766 return status;
769 return NT_STATUS_OK;
772 struct netlogon_creds_cli_lock_state {
773 struct netlogon_creds_cli_locked_state *locked_state;
774 struct netlogon_creds_CredentialState *creds;
777 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq);
778 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req);
780 struct tevent_req *netlogon_creds_cli_lock_send(TALLOC_CTX *mem_ctx,
781 struct tevent_context *ev,
782 struct netlogon_creds_cli_context *context)
784 struct tevent_req *req;
785 struct netlogon_creds_cli_lock_state *state;
786 struct netlogon_creds_cli_locked_state *locked_state;
787 struct tevent_req *subreq;
789 req = tevent_req_create(mem_ctx, &state,
790 struct netlogon_creds_cli_lock_state);
791 if (req == NULL) {
792 return NULL;
795 if (context->db.locked_state != NULL) {
796 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
797 return tevent_req_post(req, ev);
800 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
801 if (tevent_req_nomem(locked_state, req)) {
802 return tevent_req_post(req, ev);
804 talloc_set_destructor(locked_state,
805 netlogon_creds_cli_locked_state_destructor);
806 locked_state->context = context;
808 context->db.locked_state = locked_state;
809 state->locked_state = locked_state;
811 if (context->db.g_ctx == NULL) {
812 netlogon_creds_cli_lock_fetch(req);
813 if (!tevent_req_is_in_progress(req)) {
814 return tevent_req_post(req, ev);
817 return req;
820 subreq = g_lock_lock_send(state, ev,
821 context->db.g_ctx,
822 context->db.key_name,
823 G_LOCK_WRITE);
824 if (tevent_req_nomem(subreq, req)) {
825 return tevent_req_post(req, ev);
827 tevent_req_set_callback(subreq, netlogon_creds_cli_lock_done, req);
829 return req;
832 static void netlogon_creds_cli_lock_done(struct tevent_req *subreq)
834 struct tevent_req *req =
835 tevent_req_callback_data(subreq,
836 struct tevent_req);
837 struct netlogon_creds_cli_lock_state *state =
838 tevent_req_data(req,
839 struct netlogon_creds_cli_lock_state);
840 NTSTATUS status;
842 status = g_lock_lock_recv(subreq);
843 TALLOC_FREE(subreq);
844 if (tevent_req_nterror(req, status)) {
845 return;
847 state->locked_state->is_glocked = true;
849 netlogon_creds_cli_lock_fetch(req);
852 static void netlogon_creds_cli_lock_fetch(struct tevent_req *req)
854 struct netlogon_creds_cli_lock_state *state =
855 tevent_req_data(req,
856 struct netlogon_creds_cli_lock_state);
857 struct netlogon_creds_cli_context *context = state->locked_state->context;
858 struct netlogon_creds_cli_fetch_state fstate = {
859 .status = NT_STATUS_INTERNAL_ERROR,
860 .required_flags = context->client.required_flags,
862 NTSTATUS status;
864 fstate.mem_ctx = state;
865 status = dbwrap_parse_record(context->db.ctx,
866 context->db.key_data,
867 netlogon_creds_cli_fetch_parser,
868 &fstate);
869 if (tevent_req_nterror(req, status)) {
870 return;
872 status = fstate.status;
873 if (tevent_req_nterror(req, status)) {
874 return;
877 if (context->server.cached_flags == fstate.creds->negotiate_flags) {
878 state->creds = fstate.creds;
879 tevent_req_done(req);
880 return;
883 context->server.cached_flags = fstate.creds->negotiate_flags;
884 context->server.try_validation6 = true;
885 context->server.try_logon_ex = true;
886 context->server.try_logon_with = true;
888 if (!(context->server.cached_flags & NETLOGON_NEG_AUTHENTICATED_RPC)) {
889 context->server.try_validation6 = false;
890 context->server.try_logon_ex = false;
892 if (!(context->server.cached_flags & NETLOGON_NEG_CROSS_FOREST_TRUSTS)) {
893 context->server.try_validation6 = false;
896 state->creds = fstate.creds;
897 tevent_req_done(req);
898 return;
901 NTSTATUS netlogon_creds_cli_lock_recv(struct tevent_req *req,
902 TALLOC_CTX *mem_ctx,
903 struct netlogon_creds_CredentialState **creds)
905 struct netlogon_creds_cli_lock_state *state =
906 tevent_req_data(req,
907 struct netlogon_creds_cli_lock_state);
908 NTSTATUS status;
910 if (tevent_req_is_nterror(req, &status)) {
911 tevent_req_received(req);
912 return status;
915 talloc_steal(state->creds, state->locked_state);
916 state->locked_state->creds = state->creds;
917 *creds = talloc_move(mem_ctx, &state->creds);
918 tevent_req_received(req);
919 return NT_STATUS_OK;
922 NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
923 TALLOC_CTX *mem_ctx,
924 struct netlogon_creds_CredentialState **creds)
926 TALLOC_CTX *frame = talloc_stackframe();
927 struct tevent_context *ev;
928 struct tevent_req *req;
929 NTSTATUS status = NT_STATUS_NO_MEMORY;
931 ev = samba_tevent_context_init(frame);
932 if (ev == NULL) {
933 goto fail;
935 req = netlogon_creds_cli_lock_send(frame, ev, context);
936 if (req == NULL) {
937 goto fail;
939 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
940 goto fail;
942 status = netlogon_creds_cli_lock_recv(req, mem_ctx, creds);
943 fail:
944 TALLOC_FREE(frame);
945 return status;
948 struct netlogon_creds_cli_auth_state {
949 struct tevent_context *ev;
950 struct netlogon_creds_cli_context *context;
951 struct dcerpc_binding_handle *binding_handle;
952 uint8_t num_nt_hashes;
953 uint8_t idx_nt_hashes;
954 const struct samr_Password * const *nt_hashes;
955 const struct samr_Password *used_nt_hash;
956 char *srv_name_slash;
957 uint32_t current_flags;
958 struct netr_Credential client_challenge;
959 struct netr_Credential server_challenge;
960 struct netlogon_creds_CredentialState *creds;
961 struct netr_Credential client_credential;
962 struct netr_Credential server_credential;
963 uint32_t rid;
964 bool try_auth3;
965 bool try_auth2;
966 bool require_auth2;
967 struct netlogon_creds_cli_locked_state *locked_state;
970 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq);
971 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req);
973 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
974 struct tevent_context *ev,
975 struct netlogon_creds_cli_context *context,
976 struct dcerpc_binding_handle *b,
977 uint8_t num_nt_hashes,
978 const struct samr_Password * const *nt_hashes)
980 struct tevent_req *req;
981 struct netlogon_creds_cli_auth_state *state;
982 struct netlogon_creds_cli_locked_state *locked_state;
983 NTSTATUS status;
985 req = tevent_req_create(mem_ctx, &state,
986 struct netlogon_creds_cli_auth_state);
987 if (req == NULL) {
988 return NULL;
991 state->ev = ev;
992 state->context = context;
993 state->binding_handle = b;
994 if (num_nt_hashes < 1) {
995 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
996 return tevent_req_post(req, ev);
998 if (num_nt_hashes > 4) {
999 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1000 return tevent_req_post(req, ev);
1003 state->num_nt_hashes = num_nt_hashes;
1004 state->idx_nt_hashes = 0;
1005 state->nt_hashes = nt_hashes;
1007 if (context->db.locked_state != NULL) {
1008 tevent_req_nterror(req, NT_STATUS_LOCK_NOT_GRANTED);
1009 return tevent_req_post(req, ev);
1012 locked_state = talloc_zero(state, struct netlogon_creds_cli_locked_state);
1013 if (tevent_req_nomem(locked_state, req)) {
1014 return tevent_req_post(req, ev);
1016 talloc_set_destructor(locked_state,
1017 netlogon_creds_cli_locked_state_destructor);
1018 locked_state->context = context;
1020 context->db.locked_state = locked_state;
1021 state->locked_state = locked_state;
1023 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1024 context->server.computer);
1025 if (tevent_req_nomem(state->srv_name_slash, req)) {
1026 return tevent_req_post(req, ev);
1029 state->try_auth3 = true;
1030 state->try_auth2 = true;
1032 if (context->client.required_flags != 0) {
1033 state->require_auth2 = true;
1036 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1037 state->current_flags = context->client.proposed_flags;
1039 if (context->db.g_ctx != NULL) {
1040 struct tevent_req *subreq;
1042 subreq = g_lock_lock_send(state, ev,
1043 context->db.g_ctx,
1044 context->db.key_name,
1045 G_LOCK_WRITE);
1046 if (tevent_req_nomem(subreq, req)) {
1047 return tevent_req_post(req, ev);
1049 tevent_req_set_callback(subreq,
1050 netlogon_creds_cli_auth_locked,
1051 req);
1053 return req;
1056 status = dbwrap_purge(state->context->db.ctx,
1057 state->context->db.key_data);
1058 if (tevent_req_nterror(req, status)) {
1059 return tevent_req_post(req, ev);
1062 netlogon_creds_cli_auth_challenge_start(req);
1063 if (!tevent_req_is_in_progress(req)) {
1064 return tevent_req_post(req, ev);
1067 return req;
1070 static void netlogon_creds_cli_auth_locked(struct tevent_req *subreq)
1072 struct tevent_req *req =
1073 tevent_req_callback_data(subreq,
1074 struct tevent_req);
1075 struct netlogon_creds_cli_auth_state *state =
1076 tevent_req_data(req,
1077 struct netlogon_creds_cli_auth_state);
1078 NTSTATUS status;
1080 status = g_lock_lock_recv(subreq);
1081 TALLOC_FREE(subreq);
1082 if (tevent_req_nterror(req, status)) {
1083 return;
1085 state->locked_state->is_glocked = true;
1087 status = dbwrap_purge(state->context->db.ctx,
1088 state->context->db.key_data);
1089 if (tevent_req_nterror(req, status)) {
1090 return;
1093 netlogon_creds_cli_auth_challenge_start(req);
1096 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq);
1098 static void netlogon_creds_cli_auth_challenge_start(struct tevent_req *req)
1100 struct netlogon_creds_cli_auth_state *state =
1101 tevent_req_data(req,
1102 struct netlogon_creds_cli_auth_state);
1103 struct tevent_req *subreq;
1105 TALLOC_FREE(state->creds);
1107 generate_random_buffer(state->client_challenge.data,
1108 sizeof(state->client_challenge.data));
1110 subreq = dcerpc_netr_ServerReqChallenge_send(state, state->ev,
1111 state->binding_handle,
1112 state->srv_name_slash,
1113 state->context->client.computer,
1114 &state->client_challenge,
1115 &state->server_challenge);
1116 if (tevent_req_nomem(subreq, req)) {
1117 return;
1119 tevent_req_set_callback(subreq,
1120 netlogon_creds_cli_auth_challenge_done,
1121 req);
1124 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq);
1126 static void netlogon_creds_cli_auth_challenge_done(struct tevent_req *subreq)
1128 struct tevent_req *req =
1129 tevent_req_callback_data(subreq,
1130 struct tevent_req);
1131 struct netlogon_creds_cli_auth_state *state =
1132 tevent_req_data(req,
1133 struct netlogon_creds_cli_auth_state);
1134 NTSTATUS status;
1135 NTSTATUS result;
1137 status = dcerpc_netr_ServerReqChallenge_recv(subreq, state, &result);
1138 TALLOC_FREE(subreq);
1139 if (tevent_req_nterror(req, status)) {
1140 return;
1142 if (tevent_req_nterror(req, result)) {
1143 return;
1146 if (!state->try_auth3 && !state->try_auth2) {
1147 state->current_flags = 0;
1150 /* Calculate the session key and client credentials */
1152 state->creds = netlogon_creds_client_init(state,
1153 state->context->client.account,
1154 state->context->client.computer,
1155 state->context->client.type,
1156 &state->client_challenge,
1157 &state->server_challenge,
1158 state->used_nt_hash,
1159 &state->client_credential,
1160 state->current_flags);
1161 if (tevent_req_nomem(state->creds, req)) {
1162 return;
1165 if (state->try_auth3) {
1166 subreq = dcerpc_netr_ServerAuthenticate3_send(state, state->ev,
1167 state->binding_handle,
1168 state->srv_name_slash,
1169 state->context->client.account,
1170 state->context->client.type,
1171 state->context->client.computer,
1172 &state->client_credential,
1173 &state->server_credential,
1174 &state->creds->negotiate_flags,
1175 &state->rid);
1176 if (tevent_req_nomem(subreq, req)) {
1177 return;
1179 } else if (state->try_auth2) {
1180 state->rid = 0;
1182 subreq = dcerpc_netr_ServerAuthenticate2_send(state, state->ev,
1183 state->binding_handle,
1184 state->srv_name_slash,
1185 state->context->client.account,
1186 state->context->client.type,
1187 state->context->client.computer,
1188 &state->client_credential,
1189 &state->server_credential,
1190 &state->creds->negotiate_flags);
1191 if (tevent_req_nomem(subreq, req)) {
1192 return;
1194 } else {
1195 state->rid = 0;
1197 subreq = dcerpc_netr_ServerAuthenticate_send(state, state->ev,
1198 state->binding_handle,
1199 state->srv_name_slash,
1200 state->context->client.account,
1201 state->context->client.type,
1202 state->context->client.computer,
1203 &state->client_credential,
1204 &state->server_credential);
1205 if (tevent_req_nomem(subreq, req)) {
1206 return;
1209 tevent_req_set_callback(subreq,
1210 netlogon_creds_cli_auth_srvauth_done,
1211 req);
1214 static void netlogon_creds_cli_auth_srvauth_done(struct tevent_req *subreq)
1216 struct tevent_req *req =
1217 tevent_req_callback_data(subreq,
1218 struct tevent_req);
1219 struct netlogon_creds_cli_auth_state *state =
1220 tevent_req_data(req,
1221 struct netlogon_creds_cli_auth_state);
1222 NTSTATUS status;
1223 NTSTATUS result;
1224 bool ok;
1225 enum ndr_err_code ndr_err;
1226 DATA_BLOB blob;
1227 TDB_DATA data;
1228 uint32_t tmp_flags;
1230 if (state->try_auth3) {
1231 status = dcerpc_netr_ServerAuthenticate3_recv(subreq, state,
1232 &result);
1233 TALLOC_FREE(subreq);
1234 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1235 state->try_auth3 = false;
1236 netlogon_creds_cli_auth_challenge_start(req);
1237 return;
1239 if (tevent_req_nterror(req, status)) {
1240 return;
1242 } else if (state->try_auth2) {
1243 status = dcerpc_netr_ServerAuthenticate2_recv(subreq, state,
1244 &result);
1245 TALLOC_FREE(subreq);
1246 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1247 state->try_auth2 = false;
1248 if (state->require_auth2) {
1249 status = NT_STATUS_DOWNGRADE_DETECTED;
1250 tevent_req_nterror(req, status);
1251 return;
1253 netlogon_creds_cli_auth_challenge_start(req);
1254 return;
1256 if (tevent_req_nterror(req, status)) {
1257 return;
1259 } else {
1260 status = dcerpc_netr_ServerAuthenticate_recv(subreq, state,
1261 &result);
1262 TALLOC_FREE(subreq);
1263 if (tevent_req_nterror(req, status)) {
1264 return;
1268 if (!NT_STATUS_IS_OK(result) &&
1269 !NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED))
1271 tevent_req_nterror(req, result);
1272 return;
1275 tmp_flags = state->creds->negotiate_flags;
1276 tmp_flags &= state->context->client.required_flags;
1277 if (tmp_flags != state->context->client.required_flags) {
1278 if (NT_STATUS_IS_OK(result)) {
1279 tevent_req_nterror(req, NT_STATUS_DOWNGRADE_DETECTED);
1280 return;
1282 tevent_req_nterror(req, result);
1283 return;
1286 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
1288 tmp_flags = state->context->client.proposed_flags;
1289 if ((state->current_flags == tmp_flags) &&
1290 (state->creds->negotiate_flags != tmp_flags))
1293 * lets retry with the negotiated flags
1295 state->current_flags = state->creds->negotiate_flags;
1296 netlogon_creds_cli_auth_challenge_start(req);
1297 return;
1300 state->idx_nt_hashes += 1;
1301 if (state->idx_nt_hashes >= state->num_nt_hashes) {
1303 * we already retried, giving up...
1305 tevent_req_nterror(req, result);
1306 return;
1310 * lets retry with the old nt hash.
1312 state->used_nt_hash = state->nt_hashes[state->idx_nt_hashes];
1313 state->current_flags = state->context->client.proposed_flags;
1314 netlogon_creds_cli_auth_challenge_start(req);
1315 return;
1318 ok = netlogon_creds_client_check(state->creds,
1319 &state->server_credential);
1320 if (!ok) {
1321 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1322 return;
1325 ndr_err = ndr_push_struct_blob(&blob, state, state->creds,
1326 (ndr_push_flags_fn_t)ndr_push_netlogon_creds_CredentialState);
1327 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1328 status = ndr_map_error2ntstatus(ndr_err);
1329 tevent_req_nterror(req, status);
1330 return;
1333 data.dptr = blob.data;
1334 data.dsize = blob.length;
1336 status = dbwrap_store(state->context->db.ctx,
1337 state->context->db.key_data,
1338 data, TDB_REPLACE);
1339 TALLOC_FREE(state->locked_state);
1340 if (tevent_req_nterror(req, status)) {
1341 return;
1344 tevent_req_done(req);
1347 NTSTATUS netlogon_creds_cli_auth_recv(struct tevent_req *req,
1348 uint8_t *idx_nt_hashes)
1350 struct netlogon_creds_cli_auth_state *state =
1351 tevent_req_data(req,
1352 struct netlogon_creds_cli_auth_state);
1353 NTSTATUS status;
1355 *idx_nt_hashes = 0;
1357 if (tevent_req_is_nterror(req, &status)) {
1358 tevent_req_received(req);
1359 return status;
1362 *idx_nt_hashes = state->idx_nt_hashes;
1363 tevent_req_received(req);
1364 return NT_STATUS_OK;
1367 NTSTATUS netlogon_creds_cli_auth(struct netlogon_creds_cli_context *context,
1368 struct dcerpc_binding_handle *b,
1369 uint8_t num_nt_hashes,
1370 const struct samr_Password * const *nt_hashes,
1371 uint8_t *idx_nt_hashes)
1373 TALLOC_CTX *frame = talloc_stackframe();
1374 struct tevent_context *ev;
1375 struct tevent_req *req;
1376 NTSTATUS status = NT_STATUS_NO_MEMORY;
1378 *idx_nt_hashes = 0;
1380 ev = samba_tevent_context_init(frame);
1381 if (ev == NULL) {
1382 goto fail;
1384 req = netlogon_creds_cli_auth_send(frame, ev, context, b,
1385 num_nt_hashes, nt_hashes);
1386 if (req == NULL) {
1387 goto fail;
1389 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1390 goto fail;
1392 status = netlogon_creds_cli_auth_recv(req, idx_nt_hashes);
1393 fail:
1394 TALLOC_FREE(frame);
1395 return status;
1398 struct netlogon_creds_cli_check_state {
1399 struct tevent_context *ev;
1400 struct netlogon_creds_cli_context *context;
1401 struct dcerpc_binding_handle *binding_handle;
1403 char *srv_name_slash;
1405 union netr_Capabilities caps;
1407 struct netlogon_creds_CredentialState *creds;
1408 struct netlogon_creds_CredentialState tmp_creds;
1409 struct netr_Authenticator req_auth;
1410 struct netr_Authenticator rep_auth;
1413 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1414 NTSTATUS status);
1415 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
1417 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
1418 struct tevent_context *ev,
1419 struct netlogon_creds_cli_context *context,
1420 struct dcerpc_binding_handle *b)
1422 struct tevent_req *req;
1423 struct netlogon_creds_cli_check_state *state;
1424 struct tevent_req *subreq;
1425 enum dcerpc_AuthType auth_type;
1426 enum dcerpc_AuthLevel auth_level;
1428 req = tevent_req_create(mem_ctx, &state,
1429 struct netlogon_creds_cli_check_state);
1430 if (req == NULL) {
1431 return NULL;
1434 state->ev = ev;
1435 state->context = context;
1436 state->binding_handle = b;
1438 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1439 context->server.computer);
1440 if (tevent_req_nomem(state->srv_name_slash, req)) {
1441 return tevent_req_post(req, ev);
1444 dcerpc_binding_handle_auth_info(state->binding_handle,
1445 &auth_type, &auth_level);
1447 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
1448 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1449 return tevent_req_post(req, ev);
1452 switch (auth_level) {
1453 case DCERPC_AUTH_LEVEL_INTEGRITY:
1454 case DCERPC_AUTH_LEVEL_PRIVACY:
1455 break;
1456 default:
1457 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1458 return tevent_req_post(req, ev);
1461 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1462 state->context);
1463 if (tevent_req_nomem(subreq, req)) {
1464 return tevent_req_post(req, ev);
1467 tevent_req_set_callback(subreq,
1468 netlogon_creds_cli_check_locked,
1469 req);
1471 return req;
1474 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
1475 NTSTATUS status)
1477 struct netlogon_creds_cli_check_state *state =
1478 tevent_req_data(req,
1479 struct netlogon_creds_cli_check_state);
1481 if (state->creds == NULL) {
1482 return;
1485 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1486 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1487 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1488 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1489 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1490 TALLOC_FREE(state->creds);
1491 return;
1494 netlogon_creds_cli_delete(state->context, &state->creds);
1497 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
1499 static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
1501 struct tevent_req *req =
1502 tevent_req_callback_data(subreq,
1503 struct tevent_req);
1504 struct netlogon_creds_cli_check_state *state =
1505 tevent_req_data(req,
1506 struct netlogon_creds_cli_check_state);
1507 NTSTATUS status;
1509 status = netlogon_creds_cli_lock_recv(subreq, state,
1510 &state->creds);
1511 TALLOC_FREE(subreq);
1512 if (tevent_req_nterror(req, status)) {
1513 return;
1517 * we defer all callbacks in order to cleanup
1518 * the database record.
1520 tevent_req_defer_callback(req, state->ev);
1522 state->tmp_creds = *state->creds;
1523 netlogon_creds_client_authenticator(&state->tmp_creds,
1524 &state->req_auth);
1525 ZERO_STRUCT(state->rep_auth);
1527 subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
1528 state->binding_handle,
1529 state->srv_name_slash,
1530 state->context->client.computer,
1531 &state->req_auth,
1532 &state->rep_auth,
1534 &state->caps);
1535 if (tevent_req_nomem(subreq, req)) {
1536 status = NT_STATUS_NO_MEMORY;
1537 netlogon_creds_cli_check_cleanup(req, status);
1538 return;
1540 tevent_req_set_callback(subreq,
1541 netlogon_creds_cli_check_caps,
1542 req);
1545 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
1547 struct tevent_req *req =
1548 tevent_req_callback_data(subreq,
1549 struct tevent_req);
1550 struct netlogon_creds_cli_check_state *state =
1551 tevent_req_data(req,
1552 struct netlogon_creds_cli_check_state);
1553 NTSTATUS status;
1554 NTSTATUS result;
1555 bool ok;
1557 status = dcerpc_netr_LogonGetCapabilities_recv(subreq, state,
1558 &result);
1559 TALLOC_FREE(subreq);
1560 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1562 * Note that the negotiated flags are already checked
1563 * for our required flags after the ServerAuthenticate3/2 call.
1565 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1567 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1569 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1570 * already, we expect this to work!
1572 status = NT_STATUS_DOWNGRADE_DETECTED;
1573 tevent_req_nterror(req, status);
1574 netlogon_creds_cli_check_cleanup(req, status);
1575 return;
1578 if (negotiated & NETLOGON_NEG_STRONG_KEYS) {
1580 * If we have negotiated NETLOGON_NEG_STRONG_KEYS
1581 * we expect this to work at least as far as the
1582 * NOT_SUPPORTED error handled below!
1584 * NT 4.0 and Old Samba servers are not
1585 * allowed without "require strong key = no"
1587 status = NT_STATUS_DOWNGRADE_DETECTED;
1588 tevent_req_nterror(req, status);
1589 netlogon_creds_cli_check_cleanup(req, status);
1590 return;
1594 * If we not require NETLOGON_NEG_SUPPORTS_AES or
1595 * NETLOGON_NEG_STRONG_KEYS, it's ok to ignore
1596 * NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
1598 * This is needed against NT 4.0 and old Samba servers.
1600 * As we're using DCERPC_AUTH_TYPE_SCHANNEL with
1601 * DCERPC_AUTH_LEVEL_INTEGRITY or DCERPC_AUTH_LEVEL_PRIVACY
1602 * we should detect a faked NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
1603 * with the next request as the sequence number processing
1604 * gets out of sync.
1606 netlogon_creds_cli_check_cleanup(req, status);
1607 tevent_req_done(req);
1608 return;
1610 if (tevent_req_nterror(req, status)) {
1611 netlogon_creds_cli_check_cleanup(req, status);
1612 return;
1615 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
1617 * Note that the negotiated flags are already checked
1618 * for our required flags after the ServerAuthenticate3/2 call.
1620 uint32_t negotiated = state->tmp_creds.negotiate_flags;
1622 if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
1624 * If we have negotiated NETLOGON_NEG_SUPPORTS_AES
1625 * already, we expect this to work!
1627 status = NT_STATUS_DOWNGRADE_DETECTED;
1628 tevent_req_nterror(req, status);
1629 netlogon_creds_cli_check_cleanup(req, status);
1630 return;
1634 * This is ok, the server does not support
1635 * NETLOGON_NEG_SUPPORTS_AES.
1637 * netr_LogonGetCapabilities() was
1638 * netr_LogonDummyRoutine1() before
1639 * NETLOGON_NEG_SUPPORTS_AES was invented.
1641 netlogon_creds_cli_check_cleanup(req, result);
1642 tevent_req_done(req);
1643 return;
1646 ok = netlogon_creds_client_check(&state->tmp_creds,
1647 &state->rep_auth.cred);
1648 if (!ok) {
1649 status = NT_STATUS_ACCESS_DENIED;
1650 tevent_req_nterror(req, status);
1651 netlogon_creds_cli_check_cleanup(req, status);
1652 return;
1655 if (tevent_req_nterror(req, result)) {
1656 netlogon_creds_cli_check_cleanup(req, result);
1657 return;
1660 if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
1661 status = NT_STATUS_DOWNGRADE_DETECTED;
1662 tevent_req_nterror(req, status);
1663 netlogon_creds_cli_check_cleanup(req, status);
1664 return;
1668 * This is the key check that makes this check secure. If we
1669 * get OK here (rather than NOT_SUPPORTED), then the server
1670 * did support AES. If the server only proposed STRONG_KEYS
1671 * and not AES, then it should have failed with
1672 * NOT_IMPLEMENTED. We always send AES as a client, so the
1673 * server should always have returned it.
1675 if (!(state->caps.server_capabilities & NETLOGON_NEG_SUPPORTS_AES)) {
1676 status = NT_STATUS_DOWNGRADE_DETECTED;
1677 tevent_req_nterror(req, status);
1678 netlogon_creds_cli_check_cleanup(req, status);
1679 return;
1682 *state->creds = state->tmp_creds;
1683 status = netlogon_creds_cli_store(state->context,
1684 &state->creds);
1685 netlogon_creds_cli_check_cleanup(req, status);
1686 if (tevent_req_nterror(req, status)) {
1687 return;
1690 tevent_req_done(req);
1693 NTSTATUS netlogon_creds_cli_check_recv(struct tevent_req *req)
1695 NTSTATUS status;
1697 if (tevent_req_is_nterror(req, &status)) {
1698 netlogon_creds_cli_check_cleanup(req, status);
1699 tevent_req_received(req);
1700 return status;
1703 tevent_req_received(req);
1704 return NT_STATUS_OK;
1707 NTSTATUS netlogon_creds_cli_check(struct netlogon_creds_cli_context *context,
1708 struct dcerpc_binding_handle *b)
1710 TALLOC_CTX *frame = talloc_stackframe();
1711 struct tevent_context *ev;
1712 struct tevent_req *req;
1713 NTSTATUS status = NT_STATUS_NO_MEMORY;
1715 ev = samba_tevent_context_init(frame);
1716 if (ev == NULL) {
1717 goto fail;
1719 req = netlogon_creds_cli_check_send(frame, ev, context, b);
1720 if (req == NULL) {
1721 goto fail;
1723 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1724 goto fail;
1726 status = netlogon_creds_cli_check_recv(req);
1727 fail:
1728 TALLOC_FREE(frame);
1729 return status;
1732 struct netlogon_creds_cli_ServerPasswordSet_state {
1733 struct tevent_context *ev;
1734 struct netlogon_creds_cli_context *context;
1735 struct dcerpc_binding_handle *binding_handle;
1736 uint32_t old_timeout;
1738 char *srv_name_slash;
1739 enum dcerpc_AuthType auth_type;
1740 enum dcerpc_AuthLevel auth_level;
1742 struct samr_CryptPassword samr_crypt_password;
1743 struct netr_CryptPassword netr_crypt_password;
1744 struct samr_Password samr_password;
1746 struct netlogon_creds_CredentialState *creds;
1747 struct netlogon_creds_CredentialState tmp_creds;
1748 struct netr_Authenticator req_auth;
1749 struct netr_Authenticator rep_auth;
1752 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1753 NTSTATUS status);
1754 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq);
1756 struct tevent_req *netlogon_creds_cli_ServerPasswordSet_send(TALLOC_CTX *mem_ctx,
1757 struct tevent_context *ev,
1758 struct netlogon_creds_cli_context *context,
1759 struct dcerpc_binding_handle *b,
1760 const DATA_BLOB *new_password,
1761 const uint32_t *new_version)
1763 struct tevent_req *req;
1764 struct netlogon_creds_cli_ServerPasswordSet_state *state;
1765 struct tevent_req *subreq;
1766 bool ok;
1768 req = tevent_req_create(mem_ctx, &state,
1769 struct netlogon_creds_cli_ServerPasswordSet_state);
1770 if (req == NULL) {
1771 return NULL;
1774 state->ev = ev;
1775 state->context = context;
1776 state->binding_handle = b;
1778 if (new_password->length < 14) {
1779 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1780 return tevent_req_post(req, ev);
1784 * netr_ServerPasswordSet
1786 mdfour(state->samr_password.hash, new_password->data, new_password->length);
1789 * netr_ServerPasswordSet2
1791 ok = set_pw_in_buffer(state->samr_crypt_password.data,
1792 new_password);
1793 if (!ok) {
1794 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1795 return tevent_req_post(req, ev);
1798 if (new_version != NULL) {
1799 struct NL_PASSWORD_VERSION version;
1800 uint32_t len = IVAL(state->samr_crypt_password.data, 512);
1801 uint32_t ofs = 512 - len;
1802 uint8_t *p;
1804 if (len > 500) {
1805 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1806 return tevent_req_post(req, ev);
1808 ofs -= 12;
1810 version.ReservedField = 0;
1811 version.PasswordVersionNumber = *new_version;
1812 version.PasswordVersionPresent =
1813 NETLOGON_PASSWORD_VERSION_NUMBER_PRESENT;
1815 p = state->samr_crypt_password.data + ofs;
1816 SIVAL(p, 0, version.ReservedField);
1817 SIVAL(p, 4, version.PasswordVersionNumber);
1818 SIVAL(p, 8, version.PasswordVersionPresent);
1821 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
1822 context->server.computer);
1823 if (tevent_req_nomem(state->srv_name_slash, req)) {
1824 return tevent_req_post(req, ev);
1827 dcerpc_binding_handle_auth_info(state->binding_handle,
1828 &state->auth_type,
1829 &state->auth_level);
1831 subreq = netlogon_creds_cli_lock_send(state, state->ev,
1832 state->context);
1833 if (tevent_req_nomem(subreq, req)) {
1834 return tevent_req_post(req, ev);
1837 tevent_req_set_callback(subreq,
1838 netlogon_creds_cli_ServerPasswordSet_locked,
1839 req);
1841 return req;
1844 static void netlogon_creds_cli_ServerPasswordSet_cleanup(struct tevent_req *req,
1845 NTSTATUS status)
1847 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1848 tevent_req_data(req,
1849 struct netlogon_creds_cli_ServerPasswordSet_state);
1851 if (state->creds == NULL) {
1852 return;
1855 dcerpc_binding_handle_set_timeout(state->binding_handle,
1856 state->old_timeout);
1858 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
1859 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
1860 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
1861 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
1862 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1863 TALLOC_FREE(state->creds);
1864 return;
1867 netlogon_creds_cli_delete(state->context, &state->creds);
1870 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq);
1872 static void netlogon_creds_cli_ServerPasswordSet_locked(struct tevent_req *subreq)
1874 struct tevent_req *req =
1875 tevent_req_callback_data(subreq,
1876 struct tevent_req);
1877 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1878 tevent_req_data(req,
1879 struct netlogon_creds_cli_ServerPasswordSet_state);
1880 NTSTATUS status;
1882 status = netlogon_creds_cli_lock_recv(subreq, state,
1883 &state->creds);
1884 TALLOC_FREE(subreq);
1885 if (tevent_req_nterror(req, status)) {
1886 return;
1889 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
1890 switch (state->auth_level) {
1891 case DCERPC_AUTH_LEVEL_INTEGRITY:
1892 case DCERPC_AUTH_LEVEL_PRIVACY:
1893 break;
1894 default:
1895 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1896 return;
1898 } else {
1899 uint32_t tmp = state->creds->negotiate_flags;
1901 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
1903 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
1904 * it should be used, which means
1905 * we had a chance to verify no downgrade
1906 * happened.
1908 * This relies on netlogon_creds_cli_check*
1909 * being called before, as first request after
1910 * the DCERPC bind.
1912 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
1913 return;
1917 state->old_timeout = dcerpc_binding_handle_set_timeout(
1918 state->binding_handle, 600000);
1921 * we defer all callbacks in order to cleanup
1922 * the database record.
1924 tevent_req_defer_callback(req, state->ev);
1926 state->tmp_creds = *state->creds;
1927 netlogon_creds_client_authenticator(&state->tmp_creds,
1928 &state->req_auth);
1929 ZERO_STRUCT(state->rep_auth);
1931 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
1933 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
1934 netlogon_creds_aes_encrypt(&state->tmp_creds,
1935 state->samr_crypt_password.data,
1936 516);
1937 } else {
1938 netlogon_creds_arcfour_crypt(&state->tmp_creds,
1939 state->samr_crypt_password.data,
1940 516);
1943 memcpy(state->netr_crypt_password.data,
1944 state->samr_crypt_password.data, 512);
1945 state->netr_crypt_password.length =
1946 IVAL(state->samr_crypt_password.data, 512);
1948 subreq = dcerpc_netr_ServerPasswordSet2_send(state, state->ev,
1949 state->binding_handle,
1950 state->srv_name_slash,
1951 state->tmp_creds.account_name,
1952 state->tmp_creds.secure_channel_type,
1953 state->tmp_creds.computer_name,
1954 &state->req_auth,
1955 &state->rep_auth,
1956 &state->netr_crypt_password);
1957 if (tevent_req_nomem(subreq, req)) {
1958 status = NT_STATUS_NO_MEMORY;
1959 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1960 return;
1962 } else {
1963 netlogon_creds_des_encrypt(&state->tmp_creds,
1964 &state->samr_password);
1966 subreq = dcerpc_netr_ServerPasswordSet_send(state, state->ev,
1967 state->binding_handle,
1968 state->srv_name_slash,
1969 state->tmp_creds.account_name,
1970 state->tmp_creds.secure_channel_type,
1971 state->tmp_creds.computer_name,
1972 &state->req_auth,
1973 &state->rep_auth,
1974 &state->samr_password);
1975 if (tevent_req_nomem(subreq, req)) {
1976 status = NT_STATUS_NO_MEMORY;
1977 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
1978 return;
1982 tevent_req_set_callback(subreq,
1983 netlogon_creds_cli_ServerPasswordSet_done,
1984 req);
1987 static void netlogon_creds_cli_ServerPasswordSet_done(struct tevent_req *subreq)
1989 struct tevent_req *req =
1990 tevent_req_callback_data(subreq,
1991 struct tevent_req);
1992 struct netlogon_creds_cli_ServerPasswordSet_state *state =
1993 tevent_req_data(req,
1994 struct netlogon_creds_cli_ServerPasswordSet_state);
1995 NTSTATUS status;
1996 NTSTATUS result;
1997 bool ok;
1999 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_PASSWORD_SET2) {
2000 status = dcerpc_netr_ServerPasswordSet2_recv(subreq, state,
2001 &result);
2002 TALLOC_FREE(subreq);
2003 if (tevent_req_nterror(req, status)) {
2004 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2005 return;
2007 } else {
2008 status = dcerpc_netr_ServerPasswordSet_recv(subreq, state,
2009 &result);
2010 TALLOC_FREE(subreq);
2011 if (tevent_req_nterror(req, status)) {
2012 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2013 return;
2017 ok = netlogon_creds_client_check(&state->tmp_creds,
2018 &state->rep_auth.cred);
2019 if (!ok) {
2020 status = NT_STATUS_ACCESS_DENIED;
2021 tevent_req_nterror(req, status);
2022 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2023 return;
2026 if (tevent_req_nterror(req, result)) {
2027 netlogon_creds_cli_ServerPasswordSet_cleanup(req, result);
2028 return;
2031 dcerpc_binding_handle_set_timeout(state->binding_handle,
2032 state->old_timeout);
2034 *state->creds = state->tmp_creds;
2035 status = netlogon_creds_cli_store(state->context,
2036 &state->creds);
2037 if (tevent_req_nterror(req, status)) {
2038 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2039 return;
2042 tevent_req_done(req);
2045 NTSTATUS netlogon_creds_cli_ServerPasswordSet_recv(struct tevent_req *req)
2047 NTSTATUS status;
2049 if (tevent_req_is_nterror(req, &status)) {
2050 netlogon_creds_cli_ServerPasswordSet_cleanup(req, status);
2051 tevent_req_received(req);
2052 return status;
2055 tevent_req_received(req);
2056 return NT_STATUS_OK;
2059 NTSTATUS netlogon_creds_cli_ServerPasswordSet(
2060 struct netlogon_creds_cli_context *context,
2061 struct dcerpc_binding_handle *b,
2062 const DATA_BLOB *new_password,
2063 const uint32_t *new_version)
2065 TALLOC_CTX *frame = talloc_stackframe();
2066 struct tevent_context *ev;
2067 struct tevent_req *req;
2068 NTSTATUS status = NT_STATUS_NO_MEMORY;
2070 ev = samba_tevent_context_init(frame);
2071 if (ev == NULL) {
2072 goto fail;
2074 req = netlogon_creds_cli_ServerPasswordSet_send(frame, ev, context, b,
2075 new_password,
2076 new_version);
2077 if (req == NULL) {
2078 goto fail;
2080 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2081 goto fail;
2083 status = netlogon_creds_cli_ServerPasswordSet_recv(req);
2084 fail:
2085 TALLOC_FREE(frame);
2086 return status;
2089 struct netlogon_creds_cli_LogonSamLogon_state {
2090 struct tevent_context *ev;
2091 struct netlogon_creds_cli_context *context;
2092 struct dcerpc_binding_handle *binding_handle;
2094 char *srv_name_slash;
2096 enum netr_LogonInfoClass logon_level;
2097 const union netr_LogonLevel *const_logon;
2098 union netr_LogonLevel *logon;
2099 uint32_t flags;
2101 uint16_t validation_level;
2102 union netr_Validation *validation;
2103 uint8_t authoritative;
2106 * do we need encryption at the application layer?
2108 bool user_encrypt;
2109 bool try_logon_ex;
2110 bool try_validation6;
2113 * the read only credentials before we started the operation
2114 * used for netr_LogonSamLogonEx() if required (validation_level = 3).
2116 struct netlogon_creds_CredentialState *ro_creds;
2119 * The (locked) credentials used for the credential chain
2120 * used for netr_LogonSamLogonWithFlags() or
2121 * netr_LogonSamLogonWith().
2123 struct netlogon_creds_CredentialState *lk_creds;
2126 * While we have locked the global credentials (lk_creds above)
2127 * we operate an a temporary copy, because a server
2128 * may not support netr_LogonSamLogonWithFlags() and
2129 * didn't process our netr_Authenticator, so we need to
2130 * restart from lk_creds.
2132 struct netlogon_creds_CredentialState tmp_creds;
2133 struct netr_Authenticator req_auth;
2134 struct netr_Authenticator rep_auth;
2137 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req);
2138 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2139 NTSTATUS status);
2141 struct tevent_req *netlogon_creds_cli_LogonSamLogon_send(TALLOC_CTX *mem_ctx,
2142 struct tevent_context *ev,
2143 struct netlogon_creds_cli_context *context,
2144 struct dcerpc_binding_handle *b,
2145 enum netr_LogonInfoClass logon_level,
2146 const union netr_LogonLevel *logon,
2147 uint32_t flags)
2149 struct tevent_req *req;
2150 struct netlogon_creds_cli_LogonSamLogon_state *state;
2152 req = tevent_req_create(mem_ctx, &state,
2153 struct netlogon_creds_cli_LogonSamLogon_state);
2154 if (req == NULL) {
2155 return NULL;
2158 state->ev = ev;
2159 state->context = context;
2160 state->binding_handle = b;
2162 state->logon_level = logon_level;
2163 state->const_logon = logon;
2164 state->flags = flags;
2166 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2167 context->server.computer);
2168 if (tevent_req_nomem(state->srv_name_slash, req)) {
2169 return tevent_req_post(req, ev);
2172 switch (logon_level) {
2173 case NetlogonInteractiveInformation:
2174 case NetlogonInteractiveTransitiveInformation:
2175 case NetlogonServiceInformation:
2176 case NetlogonServiceTransitiveInformation:
2177 case NetlogonGenericInformation:
2178 state->user_encrypt = true;
2179 break;
2181 case NetlogonNetworkInformation:
2182 case NetlogonNetworkTransitiveInformation:
2183 break;
2186 state->validation = talloc_zero(state, union netr_Validation);
2187 if (tevent_req_nomem(state->validation, req)) {
2188 return tevent_req_post(req, ev);
2191 netlogon_creds_cli_LogonSamLogon_start(req);
2192 if (!tevent_req_is_in_progress(req)) {
2193 return tevent_req_post(req, ev);
2197 * we defer all callbacks in order to cleanup
2198 * the database record.
2200 tevent_req_defer_callback(req, state->ev);
2201 return req;
2204 static void netlogon_creds_cli_LogonSamLogon_cleanup(struct tevent_req *req,
2205 NTSTATUS status)
2207 struct netlogon_creds_cli_LogonSamLogon_state *state =
2208 tevent_req_data(req,
2209 struct netlogon_creds_cli_LogonSamLogon_state);
2211 if (state->lk_creds == NULL) {
2212 return;
2215 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2217 * This is a hack to recover from a bug in old
2218 * Samba servers, when LogonSamLogonEx() fails:
2220 * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
2222 * All following request will get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2224 * A second bug generates NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE,
2225 * instead of NT_STATUS_ACCESS_DENIED or NT_STATUS_RPC_SEC_PKG_ERROR
2226 * If the sign/seal check fails.
2228 * In that case we need to cleanup the netlogon session.
2230 * It's the job of the caller to disconnect the current
2231 * connection, if netlogon_creds_cli_LogonSamLogon()
2232 * returns NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
2234 if (!state->context->server.try_logon_with) {
2235 status = NT_STATUS_NETWORK_ACCESS_DENIED;
2239 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2240 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2241 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2242 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2243 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2244 TALLOC_FREE(state->lk_creds);
2245 return;
2248 netlogon_creds_cli_delete(state->context, &state->lk_creds);
2251 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq);
2253 static void netlogon_creds_cli_LogonSamLogon_start(struct tevent_req *req)
2255 struct netlogon_creds_cli_LogonSamLogon_state *state =
2256 tevent_req_data(req,
2257 struct netlogon_creds_cli_LogonSamLogon_state);
2258 struct tevent_req *subreq;
2259 NTSTATUS status;
2260 enum dcerpc_AuthType auth_type;
2261 enum dcerpc_AuthLevel auth_level;
2263 TALLOC_FREE(state->ro_creds);
2264 TALLOC_FREE(state->logon);
2265 ZERO_STRUCTP(state->validation);
2267 dcerpc_binding_handle_auth_info(state->binding_handle,
2268 &auth_type, &auth_level);
2270 state->try_logon_ex = state->context->server.try_logon_ex;
2271 state->try_validation6 = state->context->server.try_validation6;
2273 if (auth_type != DCERPC_AUTH_TYPE_SCHANNEL) {
2274 state->try_logon_ex = false;
2277 if (auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
2278 state->try_validation6 = false;
2281 if (state->try_logon_ex) {
2282 if (state->try_validation6) {
2283 state->validation_level = 6;
2284 } else {
2285 state->validation_level = 3;
2286 state->user_encrypt = true;
2289 state->logon = netlogon_creds_shallow_copy_logon(state,
2290 state->logon_level,
2291 state->const_logon);
2292 if (tevent_req_nomem(state->logon, req)) {
2293 status = NT_STATUS_NO_MEMORY;
2294 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2295 return;
2298 if (state->user_encrypt) {
2299 status = netlogon_creds_cli_get(state->context,
2300 state,
2301 &state->ro_creds);
2302 if (!NT_STATUS_IS_OK(status)) {
2303 status = NT_STATUS_ACCESS_DENIED;
2304 tevent_req_nterror(req, status);
2305 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2306 return;
2309 netlogon_creds_encrypt_samlogon_logon(state->ro_creds,
2310 state->logon_level,
2311 state->logon);
2314 subreq = dcerpc_netr_LogonSamLogonEx_send(state, state->ev,
2315 state->binding_handle,
2316 state->srv_name_slash,
2317 state->context->client.computer,
2318 state->logon_level,
2319 state->logon,
2320 state->validation_level,
2321 state->validation,
2322 &state->authoritative,
2323 &state->flags);
2324 if (tevent_req_nomem(subreq, req)) {
2325 status = NT_STATUS_NO_MEMORY;
2326 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2327 return;
2329 tevent_req_set_callback(subreq,
2330 netlogon_creds_cli_LogonSamLogon_done,
2331 req);
2332 return;
2335 if (state->lk_creds == NULL) {
2336 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2337 state->context);
2338 if (tevent_req_nomem(subreq, req)) {
2339 status = NT_STATUS_NO_MEMORY;
2340 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2341 return;
2343 tevent_req_set_callback(subreq,
2344 netlogon_creds_cli_LogonSamLogon_done,
2345 req);
2346 return;
2349 state->tmp_creds = *state->lk_creds;
2350 netlogon_creds_client_authenticator(&state->tmp_creds,
2351 &state->req_auth);
2352 ZERO_STRUCT(state->rep_auth);
2354 state->logon = netlogon_creds_shallow_copy_logon(state,
2355 state->logon_level,
2356 state->const_logon);
2357 if (tevent_req_nomem(state->logon, req)) {
2358 status = NT_STATUS_NO_MEMORY;
2359 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2360 return;
2363 netlogon_creds_encrypt_samlogon_logon(&state->tmp_creds,
2364 state->logon_level,
2365 state->logon);
2367 state->validation_level = 3;
2369 if (state->context->server.try_logon_with) {
2370 subreq = dcerpc_netr_LogonSamLogonWithFlags_send(state, state->ev,
2371 state->binding_handle,
2372 state->srv_name_slash,
2373 state->context->client.computer,
2374 &state->req_auth,
2375 &state->rep_auth,
2376 state->logon_level,
2377 state->logon,
2378 state->validation_level,
2379 state->validation,
2380 &state->authoritative,
2381 &state->flags);
2382 if (tevent_req_nomem(subreq, req)) {
2383 status = NT_STATUS_NO_MEMORY;
2384 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2385 return;
2387 } else {
2388 state->flags = 0;
2390 subreq = dcerpc_netr_LogonSamLogon_send(state, state->ev,
2391 state->binding_handle,
2392 state->srv_name_slash,
2393 state->context->client.computer,
2394 &state->req_auth,
2395 &state->rep_auth,
2396 state->logon_level,
2397 state->logon,
2398 state->validation_level,
2399 state->validation,
2400 &state->authoritative);
2401 if (tevent_req_nomem(subreq, req)) {
2402 status = NT_STATUS_NO_MEMORY;
2403 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2404 return;
2408 tevent_req_set_callback(subreq,
2409 netlogon_creds_cli_LogonSamLogon_done,
2410 req);
2413 static void netlogon_creds_cli_LogonSamLogon_done(struct tevent_req *subreq)
2415 struct tevent_req *req =
2416 tevent_req_callback_data(subreq,
2417 struct tevent_req);
2418 struct netlogon_creds_cli_LogonSamLogon_state *state =
2419 tevent_req_data(req,
2420 struct netlogon_creds_cli_LogonSamLogon_state);
2421 NTSTATUS status;
2422 NTSTATUS result;
2423 bool ok;
2425 if (state->try_logon_ex) {
2426 status = dcerpc_netr_LogonSamLogonEx_recv(subreq,
2427 state->validation,
2428 &result);
2429 TALLOC_FREE(subreq);
2430 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2431 state->context->server.try_validation6 = false;
2432 state->context->server.try_logon_ex = false;
2433 netlogon_creds_cli_LogonSamLogon_start(req);
2434 return;
2436 if (tevent_req_nterror(req, status)) {
2437 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2438 return;
2441 if ((state->validation_level == 6) &&
2442 (NT_STATUS_EQUAL(result, NT_STATUS_INVALID_INFO_CLASS) ||
2443 NT_STATUS_EQUAL(result, NT_STATUS_INVALID_PARAMETER) ||
2444 NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)))
2446 state->context->server.try_validation6 = false;
2447 netlogon_creds_cli_LogonSamLogon_start(req);
2448 return;
2451 if (tevent_req_nterror(req, result)) {
2452 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2453 return;
2456 if (state->ro_creds == NULL) {
2457 tevent_req_done(req);
2458 return;
2461 ok = netlogon_creds_cli_validate(state->context, state->ro_creds);
2462 if (!ok) {
2464 * We got a race, lets retry with on authenticator
2465 * protection.
2467 * netlogon_creds_cli_LogonSamLogon_start()
2468 * will TALLOC_FREE(state->ro_creds);
2470 state->try_logon_ex = false;
2471 netlogon_creds_cli_LogonSamLogon_start(req);
2472 return;
2475 netlogon_creds_decrypt_samlogon_validation(state->ro_creds,
2476 state->validation_level,
2477 state->validation);
2479 tevent_req_done(req);
2480 return;
2483 if (state->lk_creds == NULL) {
2484 status = netlogon_creds_cli_lock_recv(subreq, state,
2485 &state->lk_creds);
2486 TALLOC_FREE(subreq);
2487 if (tevent_req_nterror(req, status)) {
2488 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2489 return;
2492 netlogon_creds_cli_LogonSamLogon_start(req);
2493 return;
2496 if (state->context->server.try_logon_with) {
2497 status = dcerpc_netr_LogonSamLogonWithFlags_recv(subreq,
2498 state->validation,
2499 &result);
2500 TALLOC_FREE(subreq);
2501 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
2502 state->context->server.try_logon_with = false;
2503 netlogon_creds_cli_LogonSamLogon_start(req);
2504 return;
2506 if (tevent_req_nterror(req, status)) {
2507 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2508 return;
2510 } else {
2511 status = dcerpc_netr_LogonSamLogon_recv(subreq,
2512 state->validation,
2513 &result);
2514 TALLOC_FREE(subreq);
2515 if (tevent_req_nterror(req, status)) {
2516 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2517 return;
2521 ok = netlogon_creds_client_check(&state->tmp_creds,
2522 &state->rep_auth.cred);
2523 if (!ok) {
2524 status = NT_STATUS_ACCESS_DENIED;
2525 tevent_req_nterror(req, status);
2526 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2527 return;
2530 *state->lk_creds = state->tmp_creds;
2531 status = netlogon_creds_cli_store(state->context,
2532 &state->lk_creds);
2533 if (tevent_req_nterror(req, status)) {
2534 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2535 return;
2538 if (tevent_req_nterror(req, result)) {
2539 netlogon_creds_cli_LogonSamLogon_cleanup(req, result);
2540 return;
2543 netlogon_creds_decrypt_samlogon_validation(&state->tmp_creds,
2544 state->validation_level,
2545 state->validation);
2547 tevent_req_done(req);
2550 NTSTATUS netlogon_creds_cli_LogonSamLogon_recv(struct tevent_req *req,
2551 TALLOC_CTX *mem_ctx,
2552 uint16_t *validation_level,
2553 union netr_Validation **validation,
2554 uint8_t *authoritative,
2555 uint32_t *flags)
2557 struct netlogon_creds_cli_LogonSamLogon_state *state =
2558 tevent_req_data(req,
2559 struct netlogon_creds_cli_LogonSamLogon_state);
2560 NTSTATUS status;
2562 /* authoritative is also returned on error */
2563 *authoritative = state->authoritative;
2565 if (tevent_req_is_nterror(req, &status)) {
2566 netlogon_creds_cli_LogonSamLogon_cleanup(req, status);
2567 tevent_req_received(req);
2568 return status;
2571 *validation_level = state->validation_level;
2572 *validation = talloc_move(mem_ctx, &state->validation);
2573 *flags = state->flags;
2575 tevent_req_received(req);
2576 return NT_STATUS_OK;
2579 NTSTATUS netlogon_creds_cli_LogonSamLogon(
2580 struct netlogon_creds_cli_context *context,
2581 struct dcerpc_binding_handle *b,
2582 enum netr_LogonInfoClass logon_level,
2583 const union netr_LogonLevel *logon,
2584 TALLOC_CTX *mem_ctx,
2585 uint16_t *validation_level,
2586 union netr_Validation **validation,
2587 uint8_t *authoritative,
2588 uint32_t *flags)
2590 TALLOC_CTX *frame = talloc_stackframe();
2591 struct tevent_context *ev;
2592 struct tevent_req *req;
2593 NTSTATUS status = NT_STATUS_NO_MEMORY;
2595 ev = samba_tevent_context_init(frame);
2596 if (ev == NULL) {
2597 goto fail;
2599 req = netlogon_creds_cli_LogonSamLogon_send(frame, ev, context, b,
2600 logon_level, logon,
2601 *flags);
2602 if (req == NULL) {
2603 goto fail;
2605 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2606 goto fail;
2608 status = netlogon_creds_cli_LogonSamLogon_recv(req, mem_ctx,
2609 validation_level,
2610 validation,
2611 authoritative,
2612 flags);
2613 fail:
2614 TALLOC_FREE(frame);
2615 return status;
2618 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state {
2619 struct tevent_context *ev;
2620 struct netlogon_creds_cli_context *context;
2621 struct dcerpc_binding_handle *binding_handle;
2623 char *srv_name_slash;
2624 enum dcerpc_AuthType auth_type;
2625 enum dcerpc_AuthLevel auth_level;
2627 const char *site_name;
2628 uint32_t dns_ttl;
2629 struct NL_DNS_NAME_INFO_ARRAY *dns_names;
2631 struct netlogon_creds_CredentialState *creds;
2632 struct netlogon_creds_CredentialState tmp_creds;
2633 struct netr_Authenticator req_auth;
2634 struct netr_Authenticator rep_auth;
2637 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2638 NTSTATUS status);
2639 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq);
2641 struct tevent_req *netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(TALLOC_CTX *mem_ctx,
2642 struct tevent_context *ev,
2643 struct netlogon_creds_cli_context *context,
2644 struct dcerpc_binding_handle *b,
2645 const char *site_name,
2646 uint32_t dns_ttl,
2647 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2649 struct tevent_req *req;
2650 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state;
2651 struct tevent_req *subreq;
2653 req = tevent_req_create(mem_ctx, &state,
2654 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2655 if (req == NULL) {
2656 return NULL;
2659 state->ev = ev;
2660 state->context = context;
2661 state->binding_handle = b;
2663 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2664 context->server.computer);
2665 if (tevent_req_nomem(state->srv_name_slash, req)) {
2666 return tevent_req_post(req, ev);
2669 state->site_name = site_name;
2670 state->dns_ttl = dns_ttl;
2671 state->dns_names = dns_names;
2673 dcerpc_binding_handle_auth_info(state->binding_handle,
2674 &state->auth_type,
2675 &state->auth_level);
2677 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2678 state->context);
2679 if (tevent_req_nomem(subreq, req)) {
2680 return tevent_req_post(req, ev);
2683 tevent_req_set_callback(subreq,
2684 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked,
2685 req);
2687 return req;
2690 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(struct tevent_req *req,
2691 NTSTATUS status)
2693 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2694 tevent_req_data(req,
2695 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2697 if (state->creds == NULL) {
2698 return;
2701 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2702 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2703 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2704 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2705 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2706 TALLOC_FREE(state->creds);
2707 return;
2710 netlogon_creds_cli_delete(state->context, &state->creds);
2713 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq);
2715 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_locked(struct tevent_req *subreq)
2717 struct tevent_req *req =
2718 tevent_req_callback_data(subreq,
2719 struct tevent_req);
2720 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2721 tevent_req_data(req,
2722 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2723 NTSTATUS status;
2725 status = netlogon_creds_cli_lock_recv(subreq, state,
2726 &state->creds);
2727 TALLOC_FREE(subreq);
2728 if (tevent_req_nterror(req, status)) {
2729 return;
2732 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2733 switch (state->auth_level) {
2734 case DCERPC_AUTH_LEVEL_INTEGRITY:
2735 case DCERPC_AUTH_LEVEL_PRIVACY:
2736 break;
2737 default:
2738 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2739 return;
2741 } else {
2742 uint32_t tmp = state->creds->negotiate_flags;
2744 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
2746 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
2747 * it should be used, which means
2748 * we had a chance to verify no downgrade
2749 * happened.
2751 * This relies on netlogon_creds_cli_check*
2752 * being called before, as first request after
2753 * the DCERPC bind.
2755 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
2756 return;
2761 * we defer all callbacks in order to cleanup
2762 * the database record.
2764 tevent_req_defer_callback(req, state->ev);
2766 state->tmp_creds = *state->creds;
2767 netlogon_creds_client_authenticator(&state->tmp_creds,
2768 &state->req_auth);
2769 ZERO_STRUCT(state->rep_auth);
2771 subreq = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_send(state, state->ev,
2772 state->binding_handle,
2773 state->srv_name_slash,
2774 state->tmp_creds.computer_name,
2775 &state->req_auth,
2776 &state->rep_auth,
2777 state->site_name,
2778 state->dns_ttl,
2779 state->dns_names);
2780 if (tevent_req_nomem(subreq, req)) {
2781 status = NT_STATUS_NO_MEMORY;
2782 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2783 return;
2786 tevent_req_set_callback(subreq,
2787 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done,
2788 req);
2791 static void netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_done(struct tevent_req *subreq)
2793 struct tevent_req *req =
2794 tevent_req_callback_data(subreq,
2795 struct tevent_req);
2796 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state *state =
2797 tevent_req_data(req,
2798 struct netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_state);
2799 NTSTATUS status;
2800 NTSTATUS result;
2801 bool ok;
2804 * We use state->dns_names as the memory context, as this is
2805 * the only in/out variable and it has been overwritten by the
2806 * out parameter from the server.
2808 * We need to preserve the return value until the caller can use it.
2810 status = dcerpc_netr_DsrUpdateReadOnlyServerDnsRecords_recv(subreq, state->dns_names,
2811 &result);
2812 TALLOC_FREE(subreq);
2813 if (tevent_req_nterror(req, status)) {
2814 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2815 return;
2818 ok = netlogon_creds_client_check(&state->tmp_creds,
2819 &state->rep_auth.cred);
2820 if (!ok) {
2821 status = NT_STATUS_ACCESS_DENIED;
2822 tevent_req_nterror(req, status);
2823 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2824 return;
2827 *state->creds = state->tmp_creds;
2828 status = netlogon_creds_cli_store(state->context,
2829 &state->creds);
2831 if (tevent_req_nterror(req, status)) {
2832 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2833 return;
2836 if (tevent_req_nterror(req, result)) {
2837 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, result);
2838 return;
2841 tevent_req_done(req);
2844 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(struct tevent_req *req)
2846 NTSTATUS status;
2848 if (tevent_req_is_nterror(req, &status)) {
2849 netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_cleanup(req, status);
2850 tevent_req_received(req);
2851 return status;
2854 tevent_req_received(req);
2855 return NT_STATUS_OK;
2858 NTSTATUS netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(
2859 struct netlogon_creds_cli_context *context,
2860 struct dcerpc_binding_handle *b,
2861 const char *site_name,
2862 uint32_t dns_ttl,
2863 struct NL_DNS_NAME_INFO_ARRAY *dns_names)
2865 TALLOC_CTX *frame = talloc_stackframe();
2866 struct tevent_context *ev;
2867 struct tevent_req *req;
2868 NTSTATUS status = NT_STATUS_NO_MEMORY;
2870 ev = samba_tevent_context_init(frame);
2871 if (ev == NULL) {
2872 goto fail;
2874 req = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_send(frame, ev, context, b,
2875 site_name,
2876 dns_ttl,
2877 dns_names);
2878 if (req == NULL) {
2879 goto fail;
2881 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2882 goto fail;
2884 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords_recv(req);
2885 fail:
2886 TALLOC_FREE(frame);
2887 return status;
2890 struct netlogon_creds_cli_ServerGetTrustInfo_state {
2891 struct tevent_context *ev;
2892 struct netlogon_creds_cli_context *context;
2893 struct dcerpc_binding_handle *binding_handle;
2895 char *srv_name_slash;
2896 enum dcerpc_AuthType auth_type;
2897 enum dcerpc_AuthLevel auth_level;
2899 struct samr_Password new_owf_password;
2900 struct samr_Password old_owf_password;
2901 struct netr_TrustInfo *trust_info;
2903 struct netlogon_creds_CredentialState *creds;
2904 struct netlogon_creds_CredentialState tmp_creds;
2905 struct netr_Authenticator req_auth;
2906 struct netr_Authenticator rep_auth;
2909 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2910 NTSTATUS status);
2911 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq);
2913 struct tevent_req *netlogon_creds_cli_ServerGetTrustInfo_send(TALLOC_CTX *mem_ctx,
2914 struct tevent_context *ev,
2915 struct netlogon_creds_cli_context *context,
2916 struct dcerpc_binding_handle *b)
2918 struct tevent_req *req;
2919 struct netlogon_creds_cli_ServerGetTrustInfo_state *state;
2920 struct tevent_req *subreq;
2922 req = tevent_req_create(mem_ctx, &state,
2923 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2924 if (req == NULL) {
2925 return NULL;
2928 state->ev = ev;
2929 state->context = context;
2930 state->binding_handle = b;
2932 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
2933 context->server.computer);
2934 if (tevent_req_nomem(state->srv_name_slash, req)) {
2935 return tevent_req_post(req, ev);
2938 dcerpc_binding_handle_auth_info(state->binding_handle,
2939 &state->auth_type,
2940 &state->auth_level);
2942 subreq = netlogon_creds_cli_lock_send(state, state->ev,
2943 state->context);
2944 if (tevent_req_nomem(subreq, req)) {
2945 return tevent_req_post(req, ev);
2948 tevent_req_set_callback(subreq,
2949 netlogon_creds_cli_ServerGetTrustInfo_locked,
2950 req);
2952 return req;
2955 static void netlogon_creds_cli_ServerGetTrustInfo_cleanup(struct tevent_req *req,
2956 NTSTATUS status)
2958 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2959 tevent_req_data(req,
2960 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2962 if (state->creds == NULL) {
2963 return;
2966 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
2967 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
2968 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
2969 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
2970 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
2971 TALLOC_FREE(state->creds);
2972 return;
2975 netlogon_creds_cli_delete(state->context, &state->creds);
2978 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq);
2980 static void netlogon_creds_cli_ServerGetTrustInfo_locked(struct tevent_req *subreq)
2982 struct tevent_req *req =
2983 tevent_req_callback_data(subreq,
2984 struct tevent_req);
2985 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
2986 tevent_req_data(req,
2987 struct netlogon_creds_cli_ServerGetTrustInfo_state);
2988 NTSTATUS status;
2990 status = netlogon_creds_cli_lock_recv(subreq, state,
2991 &state->creds);
2992 TALLOC_FREE(subreq);
2993 if (tevent_req_nterror(req, status)) {
2994 return;
2997 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
2998 switch (state->auth_level) {
2999 case DCERPC_AUTH_LEVEL_PRIVACY:
3000 break;
3001 default:
3002 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3003 return;
3005 } else {
3006 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3007 return;
3011 * we defer all callbacks in order to cleanup
3012 * the database record.
3014 tevent_req_defer_callback(req, state->ev);
3016 state->tmp_creds = *state->creds;
3017 netlogon_creds_client_authenticator(&state->tmp_creds,
3018 &state->req_auth);
3019 ZERO_STRUCT(state->rep_auth);
3021 subreq = dcerpc_netr_ServerGetTrustInfo_send(state, state->ev,
3022 state->binding_handle,
3023 state->srv_name_slash,
3024 state->tmp_creds.account_name,
3025 state->tmp_creds.secure_channel_type,
3026 state->tmp_creds.computer_name,
3027 &state->req_auth,
3028 &state->rep_auth,
3029 &state->new_owf_password,
3030 &state->old_owf_password,
3031 &state->trust_info);
3032 if (tevent_req_nomem(subreq, req)) {
3033 status = NT_STATUS_NO_MEMORY;
3034 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3035 return;
3038 tevent_req_set_callback(subreq,
3039 netlogon_creds_cli_ServerGetTrustInfo_done,
3040 req);
3043 static void netlogon_creds_cli_ServerGetTrustInfo_done(struct tevent_req *subreq)
3045 struct tevent_req *req =
3046 tevent_req_callback_data(subreq,
3047 struct tevent_req);
3048 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3049 tevent_req_data(req,
3050 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3051 NTSTATUS status;
3052 NTSTATUS result;
3053 const struct samr_Password zero = {};
3054 int cmp;
3055 bool ok;
3058 * We use state->dns_names as the memory context, as this is
3059 * the only in/out variable and it has been overwritten by the
3060 * out parameter from the server.
3062 * We need to preserve the return value until the caller can use it.
3064 status = dcerpc_netr_ServerGetTrustInfo_recv(subreq, state, &result);
3065 TALLOC_FREE(subreq);
3066 if (tevent_req_nterror(req, status)) {
3067 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3068 return;
3071 ok = netlogon_creds_client_check(&state->tmp_creds,
3072 &state->rep_auth.cred);
3073 if (!ok) {
3074 status = NT_STATUS_ACCESS_DENIED;
3075 tevent_req_nterror(req, status);
3076 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3077 return;
3080 cmp = memcmp(state->new_owf_password.hash,
3081 zero.hash, sizeof(zero.hash));
3082 if (cmp != 0) {
3083 netlogon_creds_des_decrypt(&state->tmp_creds,
3084 &state->new_owf_password);
3086 cmp = memcmp(state->old_owf_password.hash,
3087 zero.hash, sizeof(zero.hash));
3088 if (cmp != 0) {
3089 netlogon_creds_des_decrypt(&state->tmp_creds,
3090 &state->old_owf_password);
3093 *state->creds = state->tmp_creds;
3094 status = netlogon_creds_cli_store(state->context,
3095 &state->creds);
3096 if (tevent_req_nterror(req, status)) {
3097 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3098 return;
3101 if (tevent_req_nterror(req, result)) {
3102 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, result);
3103 return;
3106 tevent_req_done(req);
3109 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo_recv(struct tevent_req *req,
3110 TALLOC_CTX *mem_ctx,
3111 struct samr_Password *new_owf_password,
3112 struct samr_Password *old_owf_password,
3113 struct netr_TrustInfo **trust_info)
3115 struct netlogon_creds_cli_ServerGetTrustInfo_state *state =
3116 tevent_req_data(req,
3117 struct netlogon_creds_cli_ServerGetTrustInfo_state);
3118 NTSTATUS status;
3120 if (tevent_req_is_nterror(req, &status)) {
3121 netlogon_creds_cli_ServerGetTrustInfo_cleanup(req, status);
3122 tevent_req_received(req);
3123 return status;
3126 if (new_owf_password != NULL) {
3127 *new_owf_password = state->new_owf_password;
3129 if (old_owf_password != NULL) {
3130 *old_owf_password = state->old_owf_password;
3132 if (trust_info != NULL) {
3133 *trust_info = talloc_move(mem_ctx, &state->trust_info);
3136 tevent_req_received(req);
3137 return NT_STATUS_OK;
3140 NTSTATUS netlogon_creds_cli_ServerGetTrustInfo(
3141 struct netlogon_creds_cli_context *context,
3142 struct dcerpc_binding_handle *b,
3143 TALLOC_CTX *mem_ctx,
3144 struct samr_Password *new_owf_password,
3145 struct samr_Password *old_owf_password,
3146 struct netr_TrustInfo **trust_info)
3148 TALLOC_CTX *frame = talloc_stackframe();
3149 struct tevent_context *ev;
3150 struct tevent_req *req;
3151 NTSTATUS status = NT_STATUS_NO_MEMORY;
3153 ev = samba_tevent_context_init(frame);
3154 if (ev == NULL) {
3155 goto fail;
3157 req = netlogon_creds_cli_ServerGetTrustInfo_send(frame, ev, context, b);
3158 if (req == NULL) {
3159 goto fail;
3161 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3162 goto fail;
3164 status = netlogon_creds_cli_ServerGetTrustInfo_recv(req,
3165 mem_ctx,
3166 new_owf_password,
3167 old_owf_password,
3168 trust_info);
3169 fail:
3170 TALLOC_FREE(frame);
3171 return status;
3174 struct netlogon_creds_cli_GetForestTrustInformation_state {
3175 struct tevent_context *ev;
3176 struct netlogon_creds_cli_context *context;
3177 struct dcerpc_binding_handle *binding_handle;
3179 char *srv_name_slash;
3180 enum dcerpc_AuthType auth_type;
3181 enum dcerpc_AuthLevel auth_level;
3183 uint32_t flags;
3184 struct lsa_ForestTrustInformation *forest_trust_info;
3186 struct netlogon_creds_CredentialState *creds;
3187 struct netlogon_creds_CredentialState tmp_creds;
3188 struct netr_Authenticator req_auth;
3189 struct netr_Authenticator rep_auth;
3192 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3193 NTSTATUS status);
3194 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq);
3196 struct tevent_req *netlogon_creds_cli_GetForestTrustInformation_send(TALLOC_CTX *mem_ctx,
3197 struct tevent_context *ev,
3198 struct netlogon_creds_cli_context *context,
3199 struct dcerpc_binding_handle *b)
3201 struct tevent_req *req;
3202 struct netlogon_creds_cli_GetForestTrustInformation_state *state;
3203 struct tevent_req *subreq;
3205 req = tevent_req_create(mem_ctx, &state,
3206 struct netlogon_creds_cli_GetForestTrustInformation_state);
3207 if (req == NULL) {
3208 return NULL;
3211 state->ev = ev;
3212 state->context = context;
3213 state->binding_handle = b;
3215 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3216 context->server.computer);
3217 if (tevent_req_nomem(state->srv_name_slash, req)) {
3218 return tevent_req_post(req, ev);
3221 state->flags = 0;
3223 dcerpc_binding_handle_auth_info(state->binding_handle,
3224 &state->auth_type,
3225 &state->auth_level);
3227 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3228 state->context);
3229 if (tevent_req_nomem(subreq, req)) {
3230 return tevent_req_post(req, ev);
3233 tevent_req_set_callback(subreq,
3234 netlogon_creds_cli_GetForestTrustInformation_locked,
3235 req);
3237 return req;
3240 static void netlogon_creds_cli_GetForestTrustInformation_cleanup(struct tevent_req *req,
3241 NTSTATUS status)
3243 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3244 tevent_req_data(req,
3245 struct netlogon_creds_cli_GetForestTrustInformation_state);
3247 if (state->creds == NULL) {
3248 return;
3251 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3252 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3253 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3254 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3255 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3256 TALLOC_FREE(state->creds);
3257 return;
3260 netlogon_creds_cli_delete(state->context, &state->creds);
3263 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq);
3265 static void netlogon_creds_cli_GetForestTrustInformation_locked(struct tevent_req *subreq)
3267 struct tevent_req *req =
3268 tevent_req_callback_data(subreq,
3269 struct tevent_req);
3270 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3271 tevent_req_data(req,
3272 struct netlogon_creds_cli_GetForestTrustInformation_state);
3273 NTSTATUS status;
3275 status = netlogon_creds_cli_lock_recv(subreq, state,
3276 &state->creds);
3277 TALLOC_FREE(subreq);
3278 if (tevent_req_nterror(req, status)) {
3279 return;
3282 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3283 switch (state->auth_level) {
3284 case DCERPC_AUTH_LEVEL_INTEGRITY:
3285 case DCERPC_AUTH_LEVEL_PRIVACY:
3286 break;
3287 default:
3288 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3289 return;
3291 } else {
3292 uint32_t tmp = state->creds->negotiate_flags;
3294 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3296 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3297 * it should be used, which means
3298 * we had a chance to verify no downgrade
3299 * happened.
3301 * This relies on netlogon_creds_cli_check*
3302 * being called before, as first request after
3303 * the DCERPC bind.
3305 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3306 return;
3311 * we defer all callbacks in order to cleanup
3312 * the database record.
3314 tevent_req_defer_callback(req, state->ev);
3316 state->tmp_creds = *state->creds;
3317 netlogon_creds_client_authenticator(&state->tmp_creds,
3318 &state->req_auth);
3319 ZERO_STRUCT(state->rep_auth);
3321 subreq = dcerpc_netr_GetForestTrustInformation_send(state, state->ev,
3322 state->binding_handle,
3323 state->srv_name_slash,
3324 state->tmp_creds.computer_name,
3325 &state->req_auth,
3326 &state->rep_auth,
3327 state->flags,
3328 &state->forest_trust_info);
3329 if (tevent_req_nomem(subreq, req)) {
3330 status = NT_STATUS_NO_MEMORY;
3331 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3332 return;
3335 tevent_req_set_callback(subreq,
3336 netlogon_creds_cli_GetForestTrustInformation_done,
3337 req);
3340 static void netlogon_creds_cli_GetForestTrustInformation_done(struct tevent_req *subreq)
3342 struct tevent_req *req =
3343 tevent_req_callback_data(subreq,
3344 struct tevent_req);
3345 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3346 tevent_req_data(req,
3347 struct netlogon_creds_cli_GetForestTrustInformation_state);
3348 NTSTATUS status;
3349 NTSTATUS result;
3350 bool ok;
3353 * We use state->dns_names as the memory context, as this is
3354 * the only in/out variable and it has been overwritten by the
3355 * out parameter from the server.
3357 * We need to preserve the return value until the caller can use it.
3359 status = dcerpc_netr_GetForestTrustInformation_recv(subreq, state, &result);
3360 TALLOC_FREE(subreq);
3361 if (tevent_req_nterror(req, status)) {
3362 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3363 return;
3366 ok = netlogon_creds_client_check(&state->tmp_creds,
3367 &state->rep_auth.cred);
3368 if (!ok) {
3369 status = NT_STATUS_ACCESS_DENIED;
3370 tevent_req_nterror(req, status);
3371 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3372 return;
3375 *state->creds = state->tmp_creds;
3376 status = netlogon_creds_cli_store(state->context,
3377 &state->creds);
3379 if (tevent_req_nterror(req, status)) {
3380 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3381 return;
3384 if (tevent_req_nterror(req, result)) {
3385 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, result);
3386 return;
3389 tevent_req_done(req);
3392 NTSTATUS netlogon_creds_cli_GetForestTrustInformation_recv(struct tevent_req *req,
3393 TALLOC_CTX *mem_ctx,
3394 struct lsa_ForestTrustInformation **forest_trust_info)
3396 struct netlogon_creds_cli_GetForestTrustInformation_state *state =
3397 tevent_req_data(req,
3398 struct netlogon_creds_cli_GetForestTrustInformation_state);
3399 NTSTATUS status;
3401 if (tevent_req_is_nterror(req, &status)) {
3402 netlogon_creds_cli_GetForestTrustInformation_cleanup(req, status);
3403 tevent_req_received(req);
3404 return status;
3407 *forest_trust_info = talloc_move(mem_ctx, &state->forest_trust_info);
3409 tevent_req_received(req);
3410 return NT_STATUS_OK;
3413 NTSTATUS netlogon_creds_cli_GetForestTrustInformation(
3414 struct netlogon_creds_cli_context *context,
3415 struct dcerpc_binding_handle *b,
3416 TALLOC_CTX *mem_ctx,
3417 struct lsa_ForestTrustInformation **forest_trust_info)
3419 TALLOC_CTX *frame = talloc_stackframe();
3420 struct tevent_context *ev;
3421 struct tevent_req *req;
3422 NTSTATUS status = NT_STATUS_NO_MEMORY;
3424 ev = samba_tevent_context_init(frame);
3425 if (ev == NULL) {
3426 goto fail;
3428 req = netlogon_creds_cli_GetForestTrustInformation_send(frame, ev, context, b);
3429 if (req == NULL) {
3430 goto fail;
3432 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3433 goto fail;
3435 status = netlogon_creds_cli_GetForestTrustInformation_recv(req,
3436 mem_ctx,
3437 forest_trust_info);
3438 fail:
3439 TALLOC_FREE(frame);
3440 return status;
3443 struct netlogon_creds_cli_SendToSam_state {
3444 struct tevent_context *ev;
3445 struct netlogon_creds_cli_context *context;
3446 struct dcerpc_binding_handle *binding_handle;
3448 char *srv_name_slash;
3449 enum dcerpc_AuthType auth_type;
3450 enum dcerpc_AuthLevel auth_level;
3452 DATA_BLOB opaque;
3454 struct netlogon_creds_CredentialState *creds;
3455 struct netlogon_creds_CredentialState tmp_creds;
3456 struct netr_Authenticator req_auth;
3457 struct netr_Authenticator rep_auth;
3460 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3461 NTSTATUS status);
3462 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq);
3464 struct tevent_req *netlogon_creds_cli_SendToSam_send(TALLOC_CTX *mem_ctx,
3465 struct tevent_context *ev,
3466 struct netlogon_creds_cli_context *context,
3467 struct dcerpc_binding_handle *b,
3468 struct netr_SendToSamBase *message)
3470 struct tevent_req *req;
3471 struct netlogon_creds_cli_SendToSam_state *state;
3472 struct tevent_req *subreq;
3473 enum ndr_err_code ndr_err;
3475 req = tevent_req_create(mem_ctx, &state,
3476 struct netlogon_creds_cli_SendToSam_state);
3477 if (req == NULL) {
3478 return NULL;
3481 state->ev = ev;
3482 state->context = context;
3483 state->binding_handle = b;
3485 state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
3486 context->server.computer);
3487 if (tevent_req_nomem(state->srv_name_slash, req)) {
3488 return tevent_req_post(req, ev);
3491 ndr_err = ndr_push_struct_blob(&state->opaque, mem_ctx, message,
3492 (ndr_push_flags_fn_t)ndr_push_netr_SendToSamBase);
3493 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3494 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
3495 tevent_req_nterror(req, status);
3496 return tevent_req_post(req, ev);
3499 dcerpc_binding_handle_auth_info(state->binding_handle,
3500 &state->auth_type,
3501 &state->auth_level);
3503 subreq = netlogon_creds_cli_lock_send(state, state->ev,
3504 state->context);
3505 if (tevent_req_nomem(subreq, req)) {
3506 return tevent_req_post(req, ev);
3509 tevent_req_set_callback(subreq,
3510 netlogon_creds_cli_SendToSam_locked,
3511 req);
3513 return req;
3516 static void netlogon_creds_cli_SendToSam_cleanup(struct tevent_req *req,
3517 NTSTATUS status)
3519 struct netlogon_creds_cli_SendToSam_state *state =
3520 tevent_req_data(req,
3521 struct netlogon_creds_cli_SendToSam_state);
3523 if (state->creds == NULL) {
3524 return;
3527 if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED) &&
3528 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) &&
3529 !NT_STATUS_EQUAL(status, NT_STATUS_DOWNGRADE_DETECTED) &&
3530 !NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
3531 !NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
3532 TALLOC_FREE(state->creds);
3533 return;
3536 netlogon_creds_cli_delete(state->context, &state->creds);
3539 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq);
3541 static void netlogon_creds_cli_SendToSam_locked(struct tevent_req *subreq)
3543 struct tevent_req *req =
3544 tevent_req_callback_data(subreq,
3545 struct tevent_req);
3546 struct netlogon_creds_cli_SendToSam_state *state =
3547 tevent_req_data(req,
3548 struct netlogon_creds_cli_SendToSam_state);
3549 NTSTATUS status;
3551 status = netlogon_creds_cli_lock_recv(subreq, state,
3552 &state->creds);
3553 TALLOC_FREE(subreq);
3554 if (tevent_req_nterror(req, status)) {
3555 return;
3558 if (state->auth_type == DCERPC_AUTH_TYPE_SCHANNEL) {
3559 switch (state->auth_level) {
3560 case DCERPC_AUTH_LEVEL_INTEGRITY:
3561 case DCERPC_AUTH_LEVEL_PRIVACY:
3562 break;
3563 default:
3564 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3565 return;
3567 } else {
3568 uint32_t tmp = state->creds->negotiate_flags;
3570 if (tmp & NETLOGON_NEG_AUTHENTICATED_RPC) {
3572 * if DCERPC_AUTH_TYPE_SCHANNEL is supported
3573 * it should be used, which means
3574 * we had a chance to verify no downgrade
3575 * happened.
3577 * This relies on netlogon_creds_cli_check*
3578 * being called before, as first request after
3579 * the DCERPC bind.
3581 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
3582 return;
3587 * we defer all callbacks in order to cleanup
3588 * the database record.
3590 tevent_req_defer_callback(req, state->ev);
3592 state->tmp_creds = *state->creds;
3593 netlogon_creds_client_authenticator(&state->tmp_creds,
3594 &state->req_auth);
3595 ZERO_STRUCT(state->rep_auth);
3597 if (state->tmp_creds.negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
3598 netlogon_creds_aes_encrypt(&state->tmp_creds,
3599 state->opaque.data,
3600 state->opaque.length);
3601 } else {
3602 netlogon_creds_arcfour_crypt(&state->tmp_creds,
3603 state->opaque.data,
3604 state->opaque.length);
3607 subreq = dcerpc_netr_NetrLogonSendToSam_send(state, state->ev,
3608 state->binding_handle,
3609 state->srv_name_slash,
3610 state->tmp_creds.computer_name,
3611 &state->req_auth,
3612 &state->rep_auth,
3613 state->opaque.data,
3614 state->opaque.length);
3615 if (tevent_req_nomem(subreq, req)) {
3616 status = NT_STATUS_NO_MEMORY;
3617 netlogon_creds_cli_SendToSam_cleanup(req, status);
3618 return;
3621 tevent_req_set_callback(subreq,
3622 netlogon_creds_cli_SendToSam_done,
3623 req);
3626 static void netlogon_creds_cli_SendToSam_done(struct tevent_req *subreq)
3628 struct tevent_req *req =
3629 tevent_req_callback_data(subreq,
3630 struct tevent_req);
3631 struct netlogon_creds_cli_SendToSam_state *state =
3632 tevent_req_data(req,
3633 struct netlogon_creds_cli_SendToSam_state);
3634 NTSTATUS status;
3635 NTSTATUS result;
3636 bool ok;
3638 status = dcerpc_netr_NetrLogonSendToSam_recv(subreq, state, &result);
3639 TALLOC_FREE(subreq);
3640 if (tevent_req_nterror(req, status)) {
3641 netlogon_creds_cli_SendToSam_cleanup(req, status);
3642 return;
3645 ok = netlogon_creds_client_check(&state->tmp_creds,
3646 &state->rep_auth.cred);
3647 if (!ok) {
3648 status = NT_STATUS_ACCESS_DENIED;
3649 tevent_req_nterror(req, status);
3650 netlogon_creds_cli_SendToSam_cleanup(req, status);
3651 return;
3654 *state->creds = state->tmp_creds;
3655 status = netlogon_creds_cli_store(state->context,
3656 &state->creds);
3658 if (tevent_req_nterror(req, status)) {
3659 netlogon_creds_cli_SendToSam_cleanup(req, status);
3660 return;
3664 * Creds must be stored before we send back application errors
3665 * e.g. NT_STATUS_NOT_IMPLEMENTED
3667 if (tevent_req_nterror(req, result)) {
3668 netlogon_creds_cli_SendToSam_cleanup(req, result);
3669 return;
3672 tevent_req_done(req);
3675 NTSTATUS netlogon_creds_cli_SendToSam(struct netlogon_creds_cli_context *context,
3676 struct dcerpc_binding_handle *b,
3677 struct netr_SendToSamBase *message)
3679 TALLOC_CTX *frame = talloc_stackframe();
3680 struct tevent_context *ev;
3681 struct tevent_req *req;
3682 NTSTATUS status = NT_STATUS_OK;
3684 ev = samba_tevent_context_init(frame);
3685 if (ev == NULL) {
3686 goto fail;
3688 req = netlogon_creds_cli_SendToSam_send(frame, ev, context, b, message);
3689 if (req == NULL) {
3690 goto fail;
3692 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3693 goto fail;
3696 /* Ignore the result */
3697 fail:
3698 TALLOC_FREE(frame);
3699 return status;